living document · updated by the quality loop

The boost roadmap

Every finding from the autonomous quality loop lands here — what shipped, what's mid-flight, and what's queued — scored by complexity, impact, and a little bit of wow.

Shipped merged & released In flight a PR is open Next triaged, starting soon Planned on the list
16Shipped
1Next up
4Planned
143Loop finds

Shipped

// merged to main & published
ShippedCorrectness · Robustness

Atomic, corruption-safe lock-file writes

Shipped in #65 (this card lingered as "next" after the fact). core/lockfile.py now writes through util.atomic_write_text (temp file + os.replace()) and read() tells "empty" apart from "corrupt": an unparseable lock is preserved as <lock>.corrupt and surfaced loudly rather than silently overwritten, so an interrupted or concurrent write can no longer drop every prior install record.

Complexity M Impact High Wow ★★★★ already fixed in
ShippedBug · Infra

GitHub Pages deploy is broken every push

Fixed by #60: the bogus mutants/None gitlink (a stray mutmut artifact with no .gitmodules entry) that made Pages' submodule checkout abort with fatal: No url found for submodule path 'mutants/None' is gone. Verified: the Pages "build and deployment" now completes successfully and the site serves — the boards live at jonnyeclectic.github.io/boost/docs/roadmap.html (200), since Pages publishes from the repo root.

Complexity S Impact High Wow ★★ root cause removed in
ShippedTesting · Bug

Mutation hardening — core/store.py

Cut mutmut survivors 54 → 29 and uncovered a latent timestamp-preservation bug the old tests masked (second-precision now_iso() collisions hid installed_at/tags preservation mutants).

Complexity M Impact High Wow ★★★ 25 mutants killed
ShippedTesting

Mutation hardening — core/gitutil.py

35 → 1 survivor via argv-assertion tests that record the exact git command line — sidestepping the macOS case-insensitive filesystem that let HEAD/head, .git/.GIT and git/GIT mutants survive against a real repo.

Complexity M Impact High Wow ★★★★ 34 mutants killed
ShippedHygiene · DX

Untrack generated build noise

Shipped in #60. The generated mutants/**, __pycache__/*.pyc and .coverage files were removed from the index (verified: git ls-files now tracks zero of them), so they no longer churn every diff or force path-scoped git adds.

Complexity S Impact Med Wow already fixed in
ShippedBug · UX

browse crashes when you pick a rule or workflow

cmd_browse lists every catalog entry — skills, rules and workflows — then called store.install(picked) unconditionally, so selecting a rule or workflow raised … is a workflow, which boost indexes but cannot install yet and the TUI exited with a fatal Error: after the user had already navigated and chosen (reported from a real boost browse session on AGENT-playbook-to-automated-agent-workflow). Fixed in #118: the install call now catches BoostError and renders the message + hint as a friendly non-fatal notice (exit 0), so a non-skill pick — or an already-installed / pinned skill — no longer crashes the browser. Covered by a regression test that picks a workflow and asserts no fatal exit.

Complexity S Impact Med Wow ★★ user-reported crash, fixed
ShippedCorrectness

Consolidate skill-staleness / drift logic into core

The "is this skill outdated" decision — semver_gt → commit compare → sha256_dir vs lock — was reimplemented nearly verbatim in cmd_update, cmd_outdated and _drift_status — three copies of core business logic that would drift apart. It now lives in one place: core/staleness.py exposes two pure (I/O-free) decisions — upstream_reason() (the version→commit→content ladder rendered by cmd_update/cmd_outdated) and drift_state() (the store/local-edits/upstream ladder rendered by _drift_status). The commands became thin renderers; behavior is byte-for-byte preserved and the new module is fully unit-tested (every branch pinned, all mutants killed).

Complexity M Impact High Wow ★★★ three copies → one core module
ShippedTesting

Mutation hardening — core/frontmatter.py

34 → 11 survivors with exact-equality tests, replacing substring in checks a mutated string literal still satisfied (e.g. dump()'s XX%s:XX still contains tags:).

Complexity M Impact Med Wow ★★★ PR
ShippedTesting · Coverage

Extension-free tests — core/dense.py

The dense-vector RAG backend's whole test module is skipif-gated on the [rag] sqlite-vec C extension, so on the default zero-dependency install every degradation and ranking path went untested (17.6% → 89% coverage). New tests force _load() → None and drive the SQL helpers and retrieve()'s cosine reducer through in-memory/fake connections — killing mutants on every machine, extension or not.

Complexity M Impact High Wow ★★★ 42 tests · +71pts coverage
ShippedTesting · Resilience

Crash-recorder error paths — core/logs.py

The black-box diagnostic logger swallows every filesystem/handler failure so a broken log can never break the CLI — but those except arms (the parts that matter most during a crash) were the least exercised. New tests force each failure — handler close() raising, a read-only log dir, an unresolvable version, a wedged logger, unlink denied — taking the module to 100% coverage.

Complexity S Impact Med Wow ★★★ 7 branches · 88%→100%
ShippedTech-debt

Extract MCP + HTTP servers out of configuration.py

~200 lines implementing a full HTTP catalog server and a JSON-RPC 2.0 MCP server lived inside the "configuration" command module — nearly untestable in place. The JSON-RPC protocol now lives in core/mcp.py as a pure handle_request(req, *, version, registry) plus a serve_stdio() loop with injectable stdin/stdout; the HTTP server moved to a new core/serve.py with a pure route() function, serve_page()/skill_text(), and serve_http(). cmd_serve and cmd_mcp --stdio became thin wrappers. Behavior is preserved exactly (the full-server and stdio-protocol functional tests pass unchanged) and the extracted core is pinned by new unit tests covering every branch.

Complexity L Impact High Wow ★★★★ two servers now testable in core
ShippedInfra · DX

Autonomous ship-workflow & isolated worktree

The loop now runs commit → PR → green CI → squash-merge → release in a dedicated ~/boost-loop git worktree (own venv for mutmut), and modern git 2.55 replaced a 2017 build that fatally choked on the global zdiff3 config.

Complexity L Impact High Wow ★★★★
ShippedCorrectness

Fix self-update version detection (dead branch)

boost self-update greped __init__.py for a __version__ = "…" literal that setuptools-scm never writes, so the regex never matched and it always reported "already up to date" — even after a pull brought a newer tag. The success path was unreachable. It now derives the pulled version straight from git (describe --tags, mirroring _detect_version()) and treats a moved HEAD as the "an update landed" signal, so the version-bump path finally fires. Regression tests cover both the up-to-date and update-landed branches.

Complexity S Impact High Wow ★★★ broken headline command, now works
ShippedSecurity

End-of-options -- guard on git commands

clone_shallow passed the clone URL as a positional with no -- separator, so a value beginning with - could be read as a git flag, and git's remote-helper transports (ext::sh -c …, file::, fd::) can execute arbitrary commands straight from a URL. Now it refuses those transports outright and passes -- before the URL so option parsing can't be hijacked — argument-injection defense-in-depth beside registry.parse_spec. Kept scoped to the one primitive that takes a user-influenced URL (the refs in pull/reset are constants, and -- there would wrongly mean a pathspec). Six tests, mutation-verified.

Complexity S Impact Med Wow ★★★ transport allow-list + -- guard
ShippedObservability · Diagnostics

Crash-correlation breadcrumbs in the invocation log

A native abort (e.g. a macOS Obj-C fork-safety SIGABRT) kills the process outright, so it never reaches boost's Python crash recorder — leaving no boost-side trace to confirm or clear boost when an OS crash report appears. log_invocation now records pid, ppid and the interpreter path on every run, so any OS crash report can be cross-referenced by PID: if the crashing PID never appears in ~/.boost/logs/boost.log, boost is definitively ruled out.

Complexity S Impact Med Wow ★★★ rule boost in/out of OS crash reports
ShippedTech-debt

Reuse helpers; kill minor dead work

Shipped in #126. The byte-identical _user() getpass helper — copy-pasted three times across core/journal.py, commands/configuration.py and commands/team.py — is now a single public core/util.user() the three call sites delegate to (covered incl. the getpass-raises fallback). cmd_simulate also parsed the same frontmatter twice (_, body = … then meta, _ = …); collapsed to one meta, body = frontmatter.parse(text). cmd_migrate's two-agent validation is intentionally left as-is — its first-fail wording differs from _check_agents' collect-all message, so routing it through the helper would change user-facing errors.

Complexity S Impact Low Wow helper dedup + double-parse removed

Next up

// triaged findings, starting soon
ShippedDesign

Reconcile the theme drift

docs/index.html inlines its own amber/orange palette instead of the canonical Aurora cyan→violet→pink system in style/boost.css. Move it onto the shared stylesheet so one token edit recolours the guide, roadmap, and demo together.

Complexity M Impact Med Wow ★★★

Planned

// on the list
ShippedTesting

Finish mutation hardening across core/

Audited the surviving mutants across all ten listed modules — catalog, util, ai, registry, lockfile, policy, config, output, agents, paths — and killed every one that reflected a real behavioral coverage gap: the search desc-bonus accumulation and classify_workflow signature logic; score_skill signal detection and the rel_time bucket boundaries; registry.remove keeping other taps; a 3-level config.unset slicing bug; the untested lockfile.remove_rule/remove_workflow returns and corrupt-history skip; the entirely-untested policy.check_capabilities; and confirm()'s safe default. The residual survivors are equivalent mutants — encoding defaults, macOS case-folding (killed on CI's Linux runner), += vs = on a zero-init score, // vs / under %d, dead defensive defaults carried by DEFAULTS, and test-double-stubbed plumbing kwargs — none of which represents a missing assertion. The required mutation gate stays green with margin.

Complexity L Impact Med Wow ★★ behavioral gaps closed
PlannedTesting · Gap

Bring commands/ under mutation testing

The ~8,100-line command layer has zero mutation coverage: mutmut is scoped to core/ only. Measurements taken before attempting it, so the next attempt starts from data rather than re-deriving it: commands/ is 8,122 lines against core/'s 8,289, and core/ generates 9,909 mutants — so expect ~10,000 more, roughly doubling the ~18-minute mutation job that is already the long pole before every release. Three constraints found the hard way: mutmut's pytest_add_cli_args_test_selection is single-valued (tests/unit/ tests/functional/ is passed as one path and errors — it has to be tests/); commands/ is covered by tests/functional (61s) not tests/unit (12s), so per-mutant cost rises about 5×; and mutmut must run that suite inside mutants/, which needs docs/, style/, README.md and the root redirect added to also_copy — a missing tree fails baseline collection and surfaces as "mutmut run failed to execute", pointing nowhere near the cause. Deliberately not shipped as a blocking gate until the baseline kill rate has actually been measured: this gate runs on every release, and setting a floor without ever seeing the number is how you red-line main.

Complexity XL Impact High Wow ★★★
ShippedDesign · QA

Visual regression pass on the guide

Drive docs/index.html in a real browser across breakpoints to confirm the glass cards, aurora, and terminal windows render cleanly — and to catch anything the theme reconciliation shifts.

Complexity M Impact Med Wow ★★★
PlannedDocs · Marketing

Refresh the marketing surface

Re-record docs/demo.gif from demo.tape against the current CLI, tighten the README hero, and give the landing page a flashier first impression that matches the Aurora theme.

Complexity M Impact Med Wow ★★★★

Engine & command internals

// concrete file:line findings from the code scan
ShippedPerformance

Memoize config.load() in-process

Every config.get() re-reads config.json and runs a recursive deepcopy of DEFAULTS (core/config.py:80–102). It's called all over hot paths — ai.enabled, per-skill enabled_agents in sync loops, log-level and policy checks — so one command triggers dozens of full reads + deep-copies. Cache the load, invalidate on save.

Complexity S Impact Med-High Wow ★★★
ShippedRobustness

Atomic skill install (temp-dir swap)

Already shipped: core/store.py's _copy_skill stages the full copy in a temp dir on the same filesystem, then swaps it in with two atomic os.replace renames and rolls back to the original on any failure — the old rmtree-then-copytree window is gone. Covered by test_copytree_failure_preserves_existing and the flaky os.replace test in tests/unit/test_store.py.

Complexity M Impact Med Wow ★★★
ShippedRobustness

One shared atomic-write helper

journal._maybe_rotate is a racy read-modify-write that concurrent appends can truncate mid-line; rag._save and config.save repeat the non-atomic pattern (journal.py:63 · rag.py:252 · config.py:93). Factor a single atomic_write into core and route all four through it.

Complexity S Impact Med Wow ★★
ShippedCorrectness

Unify _tilde() — two copies have a boundary bug

Eight command modules each define _tilde; the quality and intelligence versions use startswith(home) with no separator check (quality.py:78), so /Users/bob-backup wrongly contracts to ~-backup. Collapse to one helper in core/paths.

Complexity S Impact Med Wow ★★
ShippedPerformance

Cache the catalog entry-set across RAG queries

rag.retrieve() calls all_entries(), which reads & json.loads every tap cache on every search to build the live map (rag.py:323 · catalog.py:166–181) — the BM25 index is mtime-cached, the entry set is not. Memoize the entry set on cache mtime the same way.

Complexity M Impact Med Wow ★★★
ShippedPerformance

Stop re-serializing entry meta on every search

catalog.search computes json.dumps(meta).lower() for every entry on every query just to substring-match (catalog.py:222). Precompute a lowercased search blob at index time, or match structured fields directly.

Complexity S Impact Med Wow ★★
ShippedPerformance

Prune ignored dirs during scan_dir walk

Two full rglob passes descend into .git/node_modules and only filter afterward, and the skill-dir membership test is O(files × skill_dirs) (catalog.py:106,119–123). Switch to an os.walk that prunes ignored dirs in place; index skill dirs in a set.

Complexity M Impact Low-Med Wow ★★
ShippedTech-debt

Single tech-stack prober

Shipped in #140. The canonical detect_stack prober — a ~75-line pure function that lived in the command module commands/discovery.py yet was imported across the command layer by both intelligence and quality — now lives in one place: a new pure core module core/stackprobe.py (with its private _SKIP_DIRS/_EXT_LANGS/_read_text helpers, used nowhere else). Every consumer imports the single core prober; discovery re-exports it for compatibility, and the now-dead helpers + unused os import were removed from it. Covered by 16 new mutation-gated unit tests. The consumer-local enrichment fallbacks (_local_stack, _STACK_MARKERS) are intentionally kept — they add coarse filesystem signal the language-only prober doesn't.

Complexity M Impact Med Wow ★★ prober moved to core
ShippedTech-debt

Single imperative-rule extractor

Three separate regexes scan SKILL.md bodies for "Always / Never / Must / Do not" lines across cmd_explain, simulate and conflict (info.py:363 · intelligence.py:254 · quality.py:822) — same concept, three implementations. Extract one shared core extractor.

Complexity M Impact Med Wow ★★
ShippedMaintainability

Split oversized command modules

quality.py (15 cmds / 1,264 lines) mixes audit regexes, conflict NLP, decay scoring, fingerprinting, a health dashboard and tap-provenance; intelligence.py and configuration.py are similarly overloaded. Split along cohesive seams to shrink blast radius. First seam (this PR): lift the installed-skill safety & integrity commands — audit, verify, attest, quarantine — into commands/safety.py, with the two shared helpers in commands/_common.py; quality.py drops from 1,264 to ~955 lines. Tap-side trust and the health/diagnostics set stay put.

Complexity L Impact Med Wow ★★
ShippedMaintainability

Robust tag argument parsing

Because -tag looks like an option, cmd_tag calls parse_known_args then re-walks raw argv to reorder tokens (info.py:575–584) — fragile enough that the comment calls it "defensive". Replace with a positional-only sub-parser or an explicit --add/--remove design.

Complexity M Impact Med Wow ★★
ShippedTech-debt · RAG

Localize the stored BM25 snippet

_make_docs stored piece[:200] — the head of the best chunk — and retrieve surfaced it verbatim, yet the docstrings promised the "best-matching passage": when the matched terms sat past the chunk's first 200 chars, the shown snippet (and the rerank context fed to the LLM) missed them entirely. Now the index stores a larger head of the matched chunk (SNIP_STORE) and retrieve windows a SNIP_WIDTH-char passage centered on the first query term, with ellipsis markers on trimmed edges (_passage). Ranking is untouched — the eval harness confirms recall@10 holds at 0.919 — and the index grows a bounded ~34% (an INDEX_VERSION bump forces the one-time reindex); storing whole chunks instead cost ~70%.

Complexity M Impact Low Wow ★★★ query-centered snippets
ShippedCorrectness

Frontmatter scalar over-coercion

Already shipped: core/frontmatter._scalar coerces only the YAML 1.2 core keywords (true/false/null/~); the 1.1 aliases yes/no/on/off/none stay strings, so a skill named none or tagged on keeps the right type. Guarded by test_scalar_leaves_yaml11_aliases_as_strings.

Complexity S Impact Low Wow ★★
ShippedInstall engine · Rules

Rule install — materialize rules into each agent's native format

Today store.install refuses every non-skill kind ("rules and workflows show up in boost search/boost taps for now"), so rules are indexed for discovery but land nowhere — there is no boost install path for a rule. Add one that writes each rule into the form the target agent actually reads, since there is no single cross-agent "rules folder": Cursor/Windsurf/Cline consume a rules directory (.cursorrules / .windsurfrules / .clinerules / .mdc), but Claude Code has no rules folder — its standing rules are CLAUDE.md. So installing a rule for Claude means merging it into CLAUDE.md (a managed, idempotent block), while for the others it means dropping the file into their rules dir. Needs a store/lock model for rules (uninstall must cleanly remove the merged block), mirroring how skills symlink into enabled_agents().

Complexity L Impact High Wow ★★★★ rules are indexed but never installed
ShippedInstall engine · Workflows

Workflow install — drop commands/subagents into each agent's native dir

After rules landed (#141), store.install still refused kind == "workflow", so slash commands and subagents were indexed for discovery but installed nowhere — browse could surface a workflow but not install it. Add the install path. Unlike rules (no cross-agent rules folder, so Claude needs a CLAUDE.md merge), workflows are a clean file drop: a command markdown lands in the agent's commands/ dir and a subagent in its agents/ dir, with the slot derived from the source path (commands//workflows/commands, agents//subagents/agents). Mirrors the rule store/lock model so uninstall removes exactly what install wrote.

Complexity M Impact High Wow ★★★ rules install (#141); workflows were still tap-only
ShippedInstall engine · Scope

Workspace scope — boost install --local into the project

boost was user-global by construction: one store at ~/.agents/skills, symlinked into every home-level agent dir. Right for the skills you use everywhere, wrong for the ones a team agrees on. Shipped the npm --save half: boost install <skill> --local (= --scope project) writes into the repo's own .claude/skills/, .cursor/skills/, … and records a committable per-repo lock at .boost/skill-lock.json. Real directories, never symlinks — a link into the author's ~/.agents/skills arrives dangling on a teammate's machine, which is the exact problem committing skills is meant to solve. Two separate locks, because ~40 call sites resolve a locked skill to ~/.agents/skills/<name>, which a project skill does not have. Scope resolution walks up for the nearest project root, so installing from src/deep/nested lands in the repo instead of scattering a .claude/ three levels down; list --local, uninstall --local and sync all understand both scopes, and sync re-materializes what a fresh clone is missing while never deleting a directory boost did not write.

Complexity L Impact High Wow ★★★★ --local, committable repo lock
ShippedInstall engine · UX

boost list shows installed rules and workflows

Rule (#141) and workflow (#150) install landed, but boost list still read only the lock file's skills section — so a rule or workflow installed from browse showed up nowhere, and worse, the empty-state ("no skills installed") fired whenever no skill was present even if rules/workflows were, hiding them entirely. Extend list to render an installed rules and installed workflows table (agents drawn from each item's recorded materializations, workflows also showing their slot), gate the empty state on all three kinds being empty, and move --json to a {skills, rules, workflows} shape. --tag stays skill-only.

Complexity S Impact Med Wow ★★ list was skill-only after rule/workflow install landed
ShippedInstall engine · Scope

Teach the rest of the CLI about project scope

Workspace scope shipped in #212install --local, list --local, uninstall --local, info and sync all understand the per-repo lock. The other ~70 commands still read the user lock alone, and an adversarial review of that PR named the consequences: boost update and outdated can't see a vendored skill (the workaround is install --local --force), and the governance commands — audit, verify, drift, doctor, health, fingerprint, attest — report a clean bill of health while N third-party skills sit in the repo being loaded by every agent on the team. That last one is the real prize: vendored skills are exactly the ones a security review should be looking at, because they arrive by PR and run on everyone's machine. Shipped the governance slice — the real prize — via a shared integrity.project_skills() / project_status() pair: verify and doctor now check project-scoped skills' committed digests the same way they do user-scope ones, so a drifted vendored skill is flagged instead of silently trusted.

Complexity M Impact Med Wow ★★ update/audit/doctor are user-scope only
ShippedInstall engine · UX

boost update refreshes installed rules and workflows

After rule (#141) and workflow (#150) install landed, boost update still upgraded only skills — a rule or workflow stayed frozen at its install-time content even after its tap moved. Extend the update pass: for each installed rule/workflow from a refreshed tap, re-materialize (force reinstall) when the source version bumped or its file content sha changed, mirroring the skill upgrade loop. Rules/workflows carry no pin/quarantine flags and their source is a single file, so there is no risky-diff gate — re-applying a file drop or a CLAUDE.md managed block is cheap and the refresh is reported per item.

Complexity S Impact Med Wow ★★ update was skill-only after rule/workflow install
ShippedInstall engine · Safety

Scan and sync rules/workflows like skills

Two skill-only gaps remained after rule (#141) / workflow (#150) install: the install-time injection + secret scan read res.dest/SKILL.md, which doesn't exist for a rule/workflow (a single file / merged block), so their executable Markdown went unscanned; and boost sync only reconciled skills, so a deleted rule/workflow materialization couldn't be repaired. Fix both: carry the raw source on the install result (scan_text) so injectscan/secretscan see exactly what was installed, and extend sync_plan/sync_apply with a missing_materializations pass that re-materializes a rule/workflow from its tap when a drop file or CLAUDE.md block is gone — mirroring the missing-store-dir repair for skills.

Complexity M Impact Med Wow ★★ close the last skill-only gaps for rules/workflows
ShippedInstall engine · UX

boost install --scope user|project for rules/workflows

Rule and workflow install always materialized into user-global agent config (~/.claude/CLAUDE.md, ~/.cursor/rules, …), so a rule meant for one repo leaked into every session. Add --scope project: materialize into the current repo instead — <repo>/.cursor/rules/, <repo>/.claude/commands|agents/, and, since Claude reads per-repo memory from the root and has no rules folder, <repo>/CLAUDE.local.md (the personal, git-ignored file). The chosen scope + base dir are recorded in the lock so update/sync re-materialize back into the same repo rather than wherever they happen to run. Default stays --scope user (unchanged behavior). Uninstall already reverses by recorded path, so it works for either scope.

Complexity M Impact High Wow ★★★ rules/workflows were user-global only
PlannedBug

Ambiguous tap short-name resolution silently picks the wrong tap

registry.get(name) matches on full name, safe-name, or trailing path segment and returns the first hit with no ambiguity check — unlike catalog.resolve_one, which explicitly errors on a multi-tap ambiguous match. Three of the five default taps end in /skills, so after boost tap --defaults, boost untap skills or boost update skills silently resolves to whichever tap sorts first and the others become unreachable by short name. Raise on an ambiguous short-name match, mirroring resolve_one.

Complexity S Impact High Wow ★★★
PlannedBug

Dense search's empty result skips the BM25 fallback

_retrieve_any treats any non-None dense result as final, but dense.retrieve() returns [] (not None) whenever every KNN neighbor gets filtered by kind mismatch or staleness — silently short-circuiting the documented "everything degrades to BM25" contract. Compounding it, dense.build()'s incremental path only prunes chunks for taps still present in the current entry set, so a tap removed via boost tap remove leaves ghost vectors in rag_vectors.sqlite forever, crowding the KNN pool on every future query. Distinguish "dense unavailable" from "dense had zero live hits," and prune removed taps on every build, not just changed ones.

Complexity M Impact Med Wow ★★
PlannedConcurrency · Bug

Journal rotation has a lost-update race between concurrent processes

_maybe_rotate reads the whole pulse file and atomically replaces it with a truncated snapshot — but two concurrent boost processes (explicitly expected per this repo's parallel-loop model) can both read, then both write their own snapshot, and whichever writes last silently discards any event the other appended in between. rotation_healthy() also opens the file with a bare p.open() and never closes it, relying on GC instead of a with block like every other open in the module. Rotate under a lock (or an append-only rename scheme), and close the handle explicitly.

Complexity M Impact Med Wow ★★
PlannedUX · Bug

boost uninstall has no confirmation prompt

boost uninstall deletes a skill's store directory and lock entry straight through shutil.rmtree() with zero confirmation — every other destructive command (snapshot restore, cohort delete, profile delete, untap, replay rollback, bmad uninstall) gates on out.confirm() first. Add the same out.confirm() (bypassable via the existing BOOST_ASSUME_YES/--yes convention) before the rmtree.

Complexity S Impact High Wow ★★★
PlannedBug

update/reinstall silently widen a skill's agent scope

A skill installed with --agent narrowing (e.g. boost install foo --agent claude-code) records that subset in the lock, but boost update/ boost reinstall force-reinstall via store.install(entry, force=True) without passing only_agents — so link_agents relinks into every currently enabled agent and silently overwrites the lock's narrower agent list. Pass only_agents=lk.get("agents") on both force-reinstall paths, matching what the rule/workflow update path already does for scope.

Complexity S Impact Med Wow ★★
PlannedBug

lint --tap mis-scores rule/workflow entries as broken

boost lint --tap builds its target list without filtering by kind, so rule/workflow catalog entries (which have no SKILL.md) always report "missing SKILL.md," and repo-root items get scored against the entire tap directory instead of their actual file. Running it against any tap that mixes rules/workflows with skills makes every rule/workflow entry show a bogus error and a garbage score. Skip or special-case non-skill kinds, mirroring the kind-branching already used elsewhere in pkg.py.

Complexity S Impact Med Wow ★★
PlannedUX · Bug

boost onboard silently overwrites existing generated files

boost onboard writes .boost/telemetry.json, a GitHub Actions workflow, and .skill-lock.json via a bare write_text() with no existence check, confirmation, or diff — unlike the sibling "write a generated file" helper elsewhere in the codebase, which always confirms before overwriting. Re-running it on a repo with its own tracked lock file silently clobbers it and still reports "created," even though it overwrote. Check dest.exists() and route through out.confirm() first.

Complexity S Impact Med Wow ★★
PlannedCLI ergonomics

Negative -n silently inverts log/pulse output

boost log/boost pulse accept -n/--limit as a bare type=int with no positivity check, and the slicing does out[:n] if n else out — a negative n becomes a Python negative slice, so -n -1 silently returns everything except the most recent event instead of erroring. discovery.py's --limit flags already share a _positive_int validator that rejects values below 1; reuse it here.

Complexity S Impact Low Wow
PlannedTesting · Bug

boost log --crashes listing branch has no non-empty test

_show_crashes has an empty-state branch and a listing branch that reads each crash-*.log, extracts its summary line, and swallows OSError on an unreadable report — only the empty-state message is exercised by any test. A regression in the glob sort, the summary-extraction regex, or the OSError fallback would ship undetected. Add a test that seeds one or more crash logs and asserts on the rendered listing.

Complexity S Impact Low Wow
PlannedTesting · Security

boost serve's own path-traversal guards are untested

serve.py's defenses against a malicious catalog skill_md path (_is_within, _safe_join_within, the ".." in rel.parts check) and its HTTP-handler failure modes are the least-covered lines in core/ — 84.5% file coverage, the lowest of any module — and no test actually feeds a ..-containing path through skill_text() to prove the guard fires. Add adversarial tests for the traversal guards and for _CatalogHandler's error paths.

Complexity S Impact Med Wow ★★ lowest coverage in core/
PlannedObservability

Diagnostic log has no structured/JSON output mode

core/logs.py uses stdlib logging with rotation and crash reports, but its file formatter only ever emits fixed plain-text lines — unlike core/journal.py, which already writes one JSON object per line for the pulse feed. A BOOST_LOG_FORMAT=json option emitting the same fields as structured records would let ~/.boost/logs/boost.log feed straight into jq or a log aggregator instead of needing regex parsing.

Complexity M Impact Med Wow ★★
PlannedObservability

AI bridge swallows failures with zero diagnostic trail

core/ai.py's CLI and API call paths both catch their failure modes (timeout, OS error, URL error, bad JSON) and return None — but neither ever calls into the logger, unlike the rest of boost. A user whose expired key or flaky network silently degrades every AI-assisted command to its heuristic fallback has no trail to diagnose why, even with --debug. Add a one-line logger.debug(...) in each except branch.

Complexity S Impact Med Wow ★★

Code health & security

// planned · free tooling to catch vulns, smells & bugs
ShippedSecurity · Vuln

Security linting — bandit via ruff S rules

Turn on the flake8-bandit (S) rule family already bundled in ruff — one line in pyproject.toml, zero new tools. It catches the Python SAST smells the linter is blind to today: subprocess(shell=True), assert as a runtime check, tempfile.mktemp, unsafe yaml.load, hardcoded secrets and weak hashing. Semgrep Community rules are the heavier alternative when a finding needs real dataflow.

Complexity S Impact High Wow ★★★ extend-select S; git/swallow rules ignored, real cases noqa'd
ShippedSecurity · Supply chain

Dependency CVE gate — pip-audit

PyPA's pip-audit fails CI when a resolved dependency matches a known advisory in the OSV / PyPI Advisory database. Dependabot opens update PRs but never blocks a merge on a live CVE; a scheduled + PR pip-audit job closes that gap and covers the dev/test toolchain that ships nothing but can still run malicious code.

Complexity S Impact Med Wow ★★ OSV-backed
ShippedQuality · Retrieval eval

Retrieval-quality eval harness (Tier 1 + rerank lift)

Boost's unit tests prove the retrieval math is arithmetically correct, but nothing graded whether search returns the right skill for a real question. This adds a golden-set harness — tests/eval/golden.jsonl, 43 query → relevant skill(s) judgments across skills, rules and workflows — scored with rank-aware IR metrics (recall@k, hit@1, MRR, nDCG@k). Deterministic and offline over the tapped catalog, so it runs as a local pre-release gate (make eval, --fail-under 0.85) alongside make check, with a pinned baseline (tests/eval/baseline.json) that flags regressions. The first run earned its keep immediately, exposing a duplicate-name double-count (recall 2.7) fixed by deduping the ranked list. A three-way engine compare proved BM25 full-content (0.919 recall) decisively beats the frontmatter heuristic (0.756), justifying the RAG stack. An opt-in, key-gated make eval-ai arm reuses the same labels to measure the LLM rerank lift — no judge needed — and confirmed rerank promotes the right skill to #1 in 16% more cases (hit@1 0.605 → 0.767) at unchanged recall. A Tier 2b arm (eval_recommend.py, make eval-rec) grades the boost recommend AI pick stage over golden project stacks with a hard grounding gate: it found the AI picks statistically tied with the heuristic on precision but perfectly grounded (0 hallucinated / off-shortlist picks) — the honest verdict that this stage earns its place through explanations and safety, not better ranking.

Complexity M Impact High Wow ★★★★ golden-set IR gate
ShippedSecurity · Posture

Supply-chain posture — OpenSSF Scorecard

The Scorecard GitHub Action audits ~18 supply-chain signals weekly — branch protection, token permissions, SHA-pinned actions, dangerous workflows, signed releases — and publishes results to the Security tab plus a README badge. Turns "are we set up safely?" into a tracked, trend-able number for a repo that owns a Trusted-Publisher release path.

Complexity S Impact Med Wow ★★★★ badge-worthy
ShippedQuality · Retrieval eval

Grow & diversify the golden set for statistical power

The golden set (43 queries / 8 stacks / 7 skills) is small enough that engine comparisons don't yet reach significance — the paired t-test lands at p≈0.11–0.26 on the pinned corpus, so BM25's numeric lead over the heuristic can't be called statistically real. Expand and diversify it: many more labelled queries with balanced per-kind coverage (skill / rule / workflow), harder near-miss distractors, and judgments for the still-unevaluated surfaces (search --smart, detect_stack). Tighter confidence intervals mean comparisons that actually reach significance and a gate that catches subtler regressions. The single highest-leverage extension of the eval harness.

Complexity M Impact High Wow ★★★★ 43 → deeper, per-kind
ShippedSecurity · Secrets

Secret scanning — gitleaks + push protection

Scan the full history and every PR diff for leaked tokens, keys and PyPI credentials with the free gitleaks action, paired with GitHub push-protection (free on public repos) so a secret is blocked before it lands. Cheap insurance for a project whose release automation trades on trusted identity.

Complexity S Impact Med Wow ★★★ pre-commit-able
ShippedQuality · Smell

Complexity & dead-code radar — xenon · vulture

Gate CI on a maintainability grade with xenon (built on radon) and flag unreachable branches, unused arguments and orphan helpers with vulture. First target: the ~5,000-line commands/ layer that has no complexity signal today. Surfaces the structural smells mutation testing can't see.

Complexity M Impact Med Wow ★★ commands/ first
ShippedQuality · Retrieval eval

Significance-tracked engine comparison (ranx monitor)

Tier 1b (the ranx paired t-test, --stats) only runs on demand today. Wire it into a scheduled CI monitor — like the eval-explain workflow — that tracks whether BM25's lead over the heuristic, and any new engine's lead over BM25, is statistically significant rather than merely numerically higher, and flags when a change erases a previously-significant win. Stays out of the required stdlib gate (ranx is an opt-in [eval] dependency); it's a non-blocking monitor, so a noisy p-value can never block a merge. Turns "recall went up 0.02" into "the improvement is real (or isn't)."

Complexity S Impact Med Wow ★★★ p-value, not point delta
PlannedQuality · Platform

Quality dashboard — SonarCloud (free for OSS)

SonarCloud is free for public repos and layers bugs, code smells, security hotspots, duplication and a coverage overlay into one dashboard, decorating each PR with a pass/fail quality gate. The single highest-signal freemium add — one external surface that unifies everything else in this section.

Complexity M Impact High Wow ★★★★★ PR quality gate
ShippedTesting · Bug

Property-based tests — hypothesis on the parsers

Generate adversarial inputs against core/frontmatter and core/catalog.scan_dir to surface crashes and round-trip failures the example-based unit tests never think to try — a dumpparse must round-trip; a scan must never raise on arbitrary bytes. Complements the gate: mutmut proves the tests are strict, Hypothesis proves the inputs are wide.

Complexity M Impact High Wow ★★★★ finds edge cases
ShippedTesting · Bug

Coverage-guided fuzzing — atheris / OSS-Fuzz

Google's atheris instruments the bytecode and evolves inputs toward uncovered branches in boost's two hand-rolled parsers — the SKILL.md frontmatter reader (a stdlib-only YAML subset, so no upstream project's fuzzing covers it) and the tap-spec parser. It has already paid for itself: the frontmatter harness found that numeric coercion was lossy. version: 1.10 is ten patch releases past 1.1, but float("1.10") is 1.1 — so boost read a skill published at 1.10 as 1.1, compared it as older than 1.9, and never offered the update, with boost outdated reporting "everything up to date" while the tap was nine releases ahead. Note that "it doesn't crash" would have missed it entirely: the invariant has to compare the parsed value against the source text. The seeds through every invariant run in the required suite so a harness cannot rot; the coverage-guided run is a weekly non-blocking job, because a timed search is not reproducible enough to gate a merge. Targets follow the OSS-Fuzz Python contract, ready for continuous runs once boost qualifies.

Complexity L Impact Med Wow ★★★★ stretch
ShippedReliability · Network

Fork-safe network layer — explicit ProxyHandler

core/ai.py and core/embed.py call urllib.request.urlopen with the default opener, which on macOS runs getproxies_macosx_sysconf()_scproxy → SystemConfiguration/CoreFoundation — an Obj-C path that is not fork-safe and aborts on the child side of a fork(). Harmless in today's single-process CLI, but fragile if boost ever runs post-fork (a future multiprocessing worker, or an embedding host). Build the opener with an explicit ProxyHandler honoring HTTP(S)_PROXY/NO_PROXY so network calls never touch the Obj-C proxy machinery — deterministic and fork-safe.

Complexity S Impact Med Wow ★★★ avoid macOS _scproxy Obj-C path
ShippedObservability · Diagnostics

Log timestamps are local time mislabeled Z

core/logs.py builds the logging.Formatter with datefmt="%Y-%m-%dT%H:%M:%SZ" but never sets converter = time.gmtime, so %(asctime)s uses local time while stamping a literal Z (UTC) suffix. Every line in ~/.boost/logs/boost.log is therefore off by the machine's UTC offset — which nearly caused a 5-hour mis-correlation when matching the log against an OS crash report. Set the formatter's converter to time.gmtime (or drop the Z) so the trail is honestly UTC, making the pid/ppid crash-correlation breadcrumbs trustworthy.

Complexity S Impact Med Wow ★★ converter = time.gmtime
PlannedTesting · Type

mypy's default mode skips untyped command bodies

[tool.mypy] in pyproject.toml sets only python_version/ files, leaving mypy in its default permissive mode — a function with any untyped parameter has its body skipped entirely. All 76 cmd_* functions across boost_cli/commands/*.py take a bare argv, and a third have no return-type annotation, so the required "zero mypy errors" lint gate isn't actually checking most of the CLI's dispatch logic. Scoping disallow_untyped_defs (or at least check_untyped_defs) to boost_cli.commands will surface a real backlog — exactly what the gate is supposed to catch.

Complexity M Impact High Wow ★★★
ShippedDiagnostics · Install engine

boost doctor checks installed rules and workflows

After rule (#141) and workflow (#150) install landed, boost doctor's health loop still only walked the lock file's skills — so a rule or workflow whose materialized file a user deleted (or whose CLAUDE.md managed block was hand-removed) went undetected. Extend the doctor loop to verify every recorded rule/workflow materialization is still on disk: a file drop must exist, and a Claude rule's CLAUDE.md must still carry its managed block. A missing materialization is flagged with a boost reinstall hint and flips the verdict, matching how skill-drift is surfaced.

Complexity S Impact Med Wow ★★ doctor was skill-only after rule/workflow install
PlannedFlaky test

rel_time tests race the wall clock and flake on a loaded runner

TestRelTime builds its input with iso_ago(n) = (now() - n).strftime("%Y-%m-%dT%H:%M:%SZ"), which truncates sub-second precision, then asserts on util.rel_time() calling now() a second time. The elapsed delta is therefore n + frac(first_now) + runtime, and rel_time floors it — so whenever frac(first_now) + runtime ≥ 1.0 the bucket is one higher than the test expects. Observed failing on tests (ubuntu-latest, 3.14): assert '31s ago' == '30s ago'. The off-by-one cases are the mild ones. iso_ago(59) and iso_ago(59 * 60) sit directly on a bucket boundary, so the same race flips "59s ago" to "1m ago" and "59m ago" to "1h ago" — a different unit, not a neighbouring number. Every assertion in the class shares the window; it is narrow on a quiet machine and widens with runner load, which is why it reads as random redness rather than a broken test. Fix by giving the test a fixed clock — monkeypatch util.datetime (or inject a now seam into rel_time) so both reads come from one frozen instant, and the boundary cases become exact rather than probabilistic. Freezing is preferable to widening the assertions: the boundaries are precisely the behaviour worth pinning.

Complexity S Impact Med Wow ★★ caught red on CI, 3.14

Pipeline & supply-chain integrity

// planned · free tooling to secure the CI/CD path itself
ShippedSecurity · CI/CD

Workflow SAST — zizmor

boost's four workflows embed github-script JavaScript and shell and drive a Trusted-Publisher release — a rich attack surface. zizmor statically flags template injection, unpinned actions, over-broad GITHUB_TOKEN permissions and dangerous triggers. The one tool that audits the automation that ships every other fix.

Complexity S Impact High Wow ★★★★★ pipx-run
ShippedQuality · CI/CD

Workflow linting — actionlint

Catches GitHub Actions YAML bugs before they fail a live release: malformed ${{ }} expressions, deprecated syntax, and shellcheck run over every run: block. Cheap insurance for a repo whose release is fully automated — a broken workflow is a broken publish.

Complexity S Impact Med Wow ★★★ shellcheck built in
ShippedSecurity · Supply chain

Build provenance — SLSA attestations

actions/attest-build-provenance emits a cryptographically signed, verifiable record of which workflow built which wheel from which commit, layered on top of the existing PyPI Trusted Publishing. Consumers can gh attestation verify the artifact they install — provenance without a paid signing service.

Complexity S Impact Med Wow ★★★★ SLSA build L2
ShippedSecurity · Supply chain

SBOM on every release — CycloneDX / Syft

Generate a CycloneDX SBOM with the free anchore/sbom-action and attach it to each GitHub Release, so downstreams can inventory and scan exactly what boost is built from. Modest today (boost is close to stdlib-only) but it grows in value as the optional [rag] extras pull in real dependencies.

Complexity S Impact Med Wow ★★★ feeds osv-scanner
ShippedSecurity · Vuln

SBOM-aware scanning — osv-scanner

Google's osv-scanner cross-checks a lockfile or the SBOM above against the OSV database, with broader ecosystem coverage than a single-language audit. The SBOM-driven complement to pip-audit: one scans the resolved env, the other scans the published manifest.

Complexity S Impact Med Wow ★★ OSV-backed
ShippedTesting · Type

Second type checker — pyright

Run Microsoft's pyright alongside mypy. Its independent inference catches None-flow and narrowing bugs the current mypy config lets slide, and it's the same engine most editors use — so CI enforces what contributors already see. Two type checkers rarely agree on nothing.

Complexity M Impact Med Wow ★★★ editor-parity
ShippedQuality · Smell

Widen the ruff rule surface — B·SIM·C4·PERF·RUF

Beyond the S security family (round 1), enable flake8-bugbear (B), simplify (SIM), comprehensions (C4), perflint (PERF) and Ruff-native (RUF) rules — bug, readability and performance smells caught at zero new-tool cost since ruff already runs in the lint gate.

Complexity S Impact Med Wow ★★★ 0 new deps
ShippedTesting · Gap

Patch-coverage gate — diff-cover

Enforce coverage on the changed lines of each PR — no external service needed, it reads the same coverage.xml the suite already emits. Pairs with the 80% project gate so new code can't quietly ride in under-tested behind an already-high overall number.

Complexity S Impact Med Wow ★★ self-hosted
PlannedCI/CD

publish.yml ignores the pip-audit / metadata gates

publish.yml triggers on workflow_run: [ci] and gates only on github.event.workflow_run.conclusion == 'success' — it never checks the independently-triggered pip-audit.yml or package-metadata.yml workflows that run on the same push. A merge that fails the live-CVE gate or the twine/metadata check still auto-publishes to PyPI as long as ci itself is green. Fold both as jobs inside ci.yml, or have the release job poll their run status via the API before publishing.

Complexity S Impact High Wow ★★★ gates PyPI
PlannedCI/CD

No timeout-minutes on any CI job

None of the 8 workflow files set timeout-minutes, so a hung step — a stalled tap clone, a wedged smoke-test subprocess — runs until GitHub's default job timeout instead of failing fast, costliest across the 2 OS × 3 Python tests matrix. Add explicit per-job timeouts: short for lint/pip-audit, longer for tests/mutation.

Complexity S Impact Low Wow
PlannedSupply chain

Dependabot's pip entry misses pyproject.toml's extras

.github/dependabot.yml declares pip for directory: /requirements, so the hash-pinned dev/CI toolchain does get weekly bump PRs. What it does not cover is pyproject.toml at the repo root: Dependabot only scans manifests under the declared directory, so the optional extras — [rag] (sqlite-vec), [eval] (ranx, ragas and the pinned langchain 0.3 stack), [bdd] (behave), [perf] (pytest-benchmark) — never get proactive version-bump PRs, only reactive pip-audit CVE flags. Low impact by design: [project].dependencies is empty, so none of this reaches anyone who installs boost-skill-cli — it is contributor-facing only. The fix is a second pip entry with directory: /. Weigh it against the noise: the [eval] stack is deliberately held at langchain 0.3 because ragas 0.2.x breaks against langchain ≥1.0, so that one will raise PRs that must be closed unmerged until ragas catches up.

Complexity S Impact Low Wow extras only — /requirements is covered
PlannedSupply chain

License-compliance scanning of the dependency closure

Nothing in CI checks SPDX license compatibility of resolved dependencies — pip-audit gates known CVEs, not license terms, and the [eval]/[rag] extras pull in a nontrivial transitive closure (the langchain stack, ragas, sqlite-vec) whose licenses are never verified against boost's own. Add a pip-licenses --fail-on (or reuse lint) step to package-metadata.yml to catch an incompatible transitive dependency before an extra ships it.

Complexity S Impact Med Wow ★★
PlannedSupply chain

The pytest tmpdir CVE has no fix at our Python floor

CVE-2025-71176 — pytest through 9.0.2 relies on the predictable /tmp/pytest-of-{user} path, letting a local user cause a denial of service or possibly gain privileges. Dependabot alert #1 (medium), raised against requirements/test-tools.txt. It cannot be closed by a version bump. The lock carries two markered pins, and only one of them is exposed: pytest==9.1.1 ; python_full_version ≥ '3.10' is already past the 9.0.3 patch, while pytest==8.4.2 ; python_full_version < '3.10' is not — and cannot be, because pytest 9.x declares requires-python ≥3.10 while this project declares requires-python = ">=3.9". The advisory marks every 8.x release vulnerable, so there is no backport to move to either. The fix is gated on dropping the 3.9 floor, which is a deliberate compatibility promise, not an oversight. Residual exposure is contributor-facing only: test-tools.txt is the dev/CI toolchain and [project].dependencies is empty, so nobody installing boost-skill-cli ever receives pytest, and CI runners are single-tenant ephemeral VMs where the local-attacker precondition does not hold. Dismissed as tolerable_risk rather than left open to rot the alert list. Revisit when either the 3.9 floor is dropped or a patched 8.x lands. If the floor must stay and the alert must clear, the real mitigation is pointing pytest at a private base temp dir (--basetemp / PYTEST_DEBUG_TEMPROOT) so the predictable path is never used — that fixes the behaviour without satisfying Dependabot's version check.

Complexity M Impact Low Wow ★★ dismissed as tolerable risk, 2026-07-25

Developer experience & maintainability

// planned · free tooling to catch issues earlier & keep the code legible
ShippedDX · Infra

Shift-left gate — pre-commit + pre-commit.ci

A .pre-commit-config.yaml runs ruff, mypy, codespell and the whitespace fixers before code ever reaches CI, and the free-for-OSS pre-commit.ci auto-fixes and auto-updates hooks right on the PR. The foundation the rest of this section plugs into — one config, many checks, faster feedback.

Complexity S Impact High Wow ★★★★ auto-fix PRs
ShippedQuality · Architecture

Layering guard — import-linter

Enforce the architecture boost already assumes: core/ must never import commands/, and the CLI depends inward only. import-linter turns that contract into a CI check, catching the cross-layer imports that slowly erode a clean engine — a structural smell no line-level linter can see.

Complexity M Impact Med Wow ★★★★ core/ ↛ commands/
ShippedQuality · Docs

Typo detection — codespell

Cheap, high-signal for a project this documentation-heavy: scan the README, docs/*.html, docstrings and every user-facing CLI string for misspellings. A typo in boost --help is a bug users see on their first run.

Complexity S Impact Med Wow ★★ user-facing text
ShippedQuality · Docs

Docstring coverage — interrogate

Gate CI below a docstring-coverage threshold so the engine stays self-documenting as it grows. core/ is already well commented; interrogate keeps it that way and flags the new public function that shipped without a word of explanation.

Complexity S Impact Low Wow ★★ keeps core/ documented
ShippedTesting · Perf

Performance-regression gate — pytest-benchmark

Benchmark the hot paths — a catalog scan over a large skills tree, a registry load — and fail the build when a change regresses them past a threshold. Catches the performance bugs a correctness suite waves through: the O(n²) that only bites at scale.

Complexity M Impact Med Wow ★★★ scan & registry
ShippedQuality · Smell

Modernization smells — refurb + pyupgrade

refurb's unique FURB checks flag dated idioms the ruff families miss, and pyupgrade rewrites to the cleanest form the >=3.9 floor allows. Keeps the codebase reading like modern Python instead of accreting legacy patterns.

Complexity S Impact Low Wow ★★ respects 3.9 floor
PlannedTesting · Platform

Coverage dashboard — Codecov (free for OSS)

Upgrade the homegrown coverage badge to Codecov's PR diff-coverage comments, file sunburst and trend graph — free for public repos. The hosted counterpart to the self-contained diff-cover gate: one enforces patch coverage in CI, the other visualizes the trend over time.

Complexity S Impact Med Wow ★★★ PR decoration
ShippedCI · Reproducibility

Pin the lint toolchain so a release can't redden the gate

The lint job installed its tools unpinned (pip install ruff mypy …), so every run pulled the latest release. When ruff 0.16.0 shipped it began flagging rule families this repo deliberately does not select (UP/BLE/PLW — ~1100 findings of exactly the pyupgrade-style churn the roadmap already declined), turning the gate red on every open PR and on main with no code change. A gate whose meaning can shift out from under you on an upstream release is not a gate. Froze the eight lint tools to their known-good versions in one requirements/lint-tools.txt that both CI and the Makefile install from, so upgrades become a deliberate, reviewable bump. (The broader runtime/build reproducibility story is the uv.lock item; this is the lint-gate slice that was actively on fire.)

Complexity S Impact High Wow ★★★ unpinned ruff 0.16 reddened every PR
ShippedSecurity · CI/CD

Runner egress monitoring — StepSecurity Harden-Runner

Free for public repos, Harden-Runner watches (and can block) unexpected network egress from CI runners — the runtime signal that catches a compromised action exfiltrating a token. The dynamic complement to zizmor's static workflow analysis, guarding the release path from both sides.

Complexity S Impact Med Wow ★★★★ runtime + static
PlannedCI/CD

Required-status-checks list is prose-only, and already stale

Branch protection is hand-configured in GitHub Settings and only described in prose in CONTRIBUTING.md — there is no config-as-code (a repo ruleset export, Terraform, or a CI check diffing required names against real job names) to catch drift. It has already drifted: ci.yml's install-smoke job, and the pip-audit/ package-metadata workflows, are never listed as required, so a PR can merge to main with any of them red.

Complexity S Impact Med Wow ★★
PlannedDeveloper Experience

No issue/PR templates or a code of conduct

The repo has SECURITY.md, CONTRIBUTING.md, and dependabot.yml, but no .github/ISSUE_TEMPLATE/, no .github/PULL_REQUEST_TEMPLATE.md, and no CODE_OF_CONDUCT.md. For a project that explicitly expects parallel external contributors (per the worktree-coordination rules in CONTRIBUTING.md), a bug-report template built around boost doctor/crash-log output and a PR checklist would cut triage friction more cheaply than most engine work.

Complexity S Impact Med Wow ★★
PlannedTest infra

New BDD suite has zero CI wiring

The behave suite added under tests/bdd/ (11 features, 47 scenarios) passes cleanly today, but make bdd is invoked nowhere in .github/workflows/ — only lint, test, smoke, and mutation run in ci.yml. Unlike the eval/mutation gates, which degrade cleanly but still execute, this suite only runs if a human remembers to run it locally, so a CLI change that breaks the step glue (output-string matching, mocked shutil.which) can rot silently for any number of merges.

Complexity S Impact Med Wow ★★
ShippedInterop

boost adapt — render a skill as another framework's agent source

boost only installs skills as files for editor agents (Claude Code, Cursor, Windsurf); CrewAI / OpenAI-Agents-SDK apps can't consume them — an agent there is a value built in source. boost adapt <skill> --to crewai|agents-sdk renders one SKILL.md into each framework's native Agent(...) as a deterministic, zero-dependency string transform (core/adapters.py). Strings emit via json.dumps so any body (quotes, """, unicode) stays valid Python; 97.6% mutation kill. Docs: adapters.html.

Complexity M Impact Med-High Wow ★★★★
ShippedInterop

boost adapt --to langgraph — third framework renderer

Extend boost adapt (shipped in #146) with a LangGraph target. Unlike CrewAI / Agents-SDK, a LangGraph agent isn't one Agent(...) constructor — the skill body is the system prompt of a node bound into a StateGraph. Add a render_langgraph to core/adapters.py emitting a node factory (prebuilt create_react_agent, or a prompt-carrying node) + its FORMATS row, with byte-exact golden + compile() tests. Then add a langgraph leg to .github/workflows/adapter-conformance.yml (pip install langgraph, import the emitted file). Follows the pattern in adapters.html: one render_* fn + registry row + golden test + one matrix line.

Complexity M Impact Med Wow ★★★
ShippedInterop

boost adapt — multi-agent skills → crews/graphs, not one Agent

Today boost adapt (#146, #163) projects a skill into a single framework Agent carrying its instructions/role/model — but a skill can declare tools and a whole subagent graph (e.g. rust-review = worker + dedup-judge + fp-judge). Adapt the richer structure: emit a CrewAI Crew (agents + tasks) or a LangGraph StateGraph when a skill's frontmatter/plugin dir declares subagents, and surface declared tools as stubs. Scope: detect subagent/tool declarations in SKILL.md/plugins/*/agents/*.md; add a crew/graph renderer path in core/adapters.py (single-Agent stays the default for flat skills); golden + compile() tests + a conformance leg. Turns "one skill → one agent" into "one skill → a runnable multi-agent workflow." See adapters.html.

Complexity L Impact Med Wow ★★★★
ShippedInterop

boost run — search → adapt → a live agent doing the task, in one command

The allure ceiling on boost adapt (#146, #163): it stops at source you assemble, and the adapted agent has a brain (prompt) but no hands (tools). Close both. boost run <skill> [target] = adapt → wire a default toolset (file read, ripgrep/shell, web) → execute on boost's model and stream the result. Opt-in like the conformance path (installs the framework + needs a key, so the zero-dep default holds). Two prerequisites ship with it: (1) tool-wiring — emit/attach the tools a skill needs (or declares) so the agent can act, not roleplay; (2) reuse the adapt renderer for the agent def. Pairs with [[framework-adapter-multi-agent]] so a skill like rust-review runs as a real crew. This is the screenshot: "one command → an expert agent audits your repo, on Claude, that you never wrote." Working preview: examples/boost-run-prototype.sh already does this by hand (adapt → wire a read_file tool → Runner.run on a file with planted bugs).

Complexity L Impact High Wow ★★★★★
ShippedInterop · Adoption

MCP — make agents search boost before reinventing a skill

The boost MCP server returned no initialize instructions and described its tools by boost's nouns ("Search AI coding skills across the configured tap registries"), so an agent mid-task never mapped "I'll write a code-review workflow" onto "search boost first" — and reinvented the wheel. Add server-level instructions (the field MCP hosts load into the agent's context) framed by the agent's trigger — before you author a reusable skill / rule / subagent, call boost_search FIRST — and rewrite the six tool descriptions to lead with that trigger and a "don't reinvent one that already exists" frame. Follow-up: a self-bootstrapping boost-first meta-skill that boost mcp register / onboard offers to install.

Complexity S Impact High Wow ★★★ agent reflex
ShippedCore · Package manager

boost install resolves a skill's requires: closure

Skills already declare relationships in frontmatter (requires: / conflicts:), and boost info / boost deps show them — but boost install X only ever installed exactly what you named, never what X depends on. That is the one headline package-manager behavior boost was missing: installing a skill should pull in the skills it needs, in the right order. Add a pure, mutation-tested resolver in core/resolve.py — post-order DFS over the requires: graph, cycle-safe, deduped, already-installed nodes pruned — and wire it into cmd_install so a named skill installs its transitive requires: closure (dependencies first), with a --no-deps escape hatch. Declared conflicts: against an installed or co-installed skill surface as an advisory warning, and a requires: naming a skill in no tap is flagged, not fatal. Surfaced by mining boost's own catalog: the densest skill cluster is dependency management, which every package manager treats as table stakes.

Complexity M Impact High Wow ★★★★ the Homebrew move
ShippedInterop · MCP

MCP-aware skills — declare and wire an .mcp.json on install

Mining boost's catalog surfaces a recurring shape: skills that only work paired with a Model Context Protocol server (manage-mcp-servers, mcp-integration, mcp-builder and dozens more). boost already is an MCP server and registers itself, but a skill could not say "I need server Y", so it installed cleanly and then failed in the agent for a reason nothing surfaced. Now a skill declares mcp: github, playwright in frontmatter and/or bundles a standard .mcp.json; on install boost states the requirement and offers to register the servers that came with a runnable spec, the same way boost mcp register wires boost itself. boost info lists them beside capabilities:, and --no-mcp opts out. Deliberately flat, not the nested mcp: block first sketched: boost's frontmatter parser is a stdlib YAML subset that does not fail loudly on a nested mapping — it hoists the inner keys to top level and clobbers their siblings — so the declaration meets the parser where it already works and full specs live in the sidecar that needs no parser at all. The decision layer is core/mcpdecl.py, pure and I/O-free like core/resolve.py.

Complexity L Impact Med Wow ★★★★ skills that need a server

Docs-site & content quality

// planned · free tooling for the Pages site, README & prose
ShippedDocs · Discoverability

Make the roadmaps discoverable

The living roadmaps were unreachable unless you knew the URL: design-roadmap.html was linked nowhere and the README had no roadmap link at all. The Visual Guide nav now carries both boards (a Design ↗ entry beside the existing Roadmap ↗), and the README opens with a Roadmap section linking the code and design boards plus the Visual Guide — so the two data-driven boards are one click away and the work stays visible.

Complexity S Impact Med Wow ★★★ nav + README links
ShippedDocs · Perf

Lighthouse CI on the Pages site

treosh/lighthouse-ci-action scores index.html and roadmap.html on performance, accessibility, best-practices and SEO on every deploy, and fails the build against budgets. Turns the marketing surface's quality into four numbers that can't silently regress as the Aurora theme evolves — four floors (a11y and SEO 0.95, best-practices 0.90, the noisier performance 0.85) asserted on the median of three runs, calibrated below the real scores with margin the same way perf_gate sets its thresholds. And, as every checker on this repo has, it found real defects on the storefront: muted text at 3.9:1 contrast (below WCAG AA), an h2 → h4 heading skip, and colour-only footer links — all fixed, so both pages now score 100 on accessibility.

Complexity M Impact High Wow ★★★★★ 4 budgets + 3 real a11y fixes
ShippedQuality · A11y

Accessibility audit — pa11y-ci / axe-core

WCAG 2.1 AA over every docs page, in two halves. scripts/a11y_check.py is the always-on gate: pure stdlib, so it runs in the lint job beside the other --check scripts with no Node, Chrome or network. It covers what the markup alone decides — lang, alt, accessible names for links and buttons, duplicate ids, heading order — plus the 1.4.3 contrast ratios computed from the Aurora tokens for the ink/ground pairs the CSS actually puts together (listing the real pairs, not the cross-product, so a pair that never renders can't cry wolf). The axe-core sweep in tests/visual/ is the other half: contrast as rendered over glass and gradient, ARIA validity against the computed tree, landmarks, focusable-but-hidden elements — everything that needs a live DOM and therefore can't be a cheap always-on gate. The audit found one real failure, a skipped heading level on the design board, fixed by promoting the section headings with their class-scoped selectors in lockstep so the rendering is unchanged. Contrast came back clean: the muted tokens the card suspected were already fixed (--text-3 had been raised from a 3.9:1 value), and this gate is what keeps them that way.

Complexity M Impact Med Wow ★★★★ WCAG AA
ShippedQuality · Docs

HTML validation — html-validate

The guide and roadmap are hand-authored HTML whose tags are balanced by eye today. A CI html-validate pass catches unclosed elements, duplicate ids and invalid nesting before they ship a subtly broken layout — the automated version of the manual tag-count sanity check.

Complexity S Impact Med Wow ★★★ hand-authored HTML
ShippedQuality · Content

Prose & terminology linting — vale

vale enforces a consistent voice across the README and docs with a small boost vocabulary — canonical spelling of skill, tap, registry; no Boost/boost drift; flagged weasel words. Keeps a docs-heavy project reading like one author wrote it.

Complexity S Impact Low Wow ★★ house style
ShippedQuality · Docs

Markdown consistency — markdownlint-cli2

Lint every Markdown surface — README, CLAUDE.md, DEBUGGING.md, rag-architecture.md — for heading order, list style and fenced-code hygiene. Cheap, deterministic, and it keeps the contributor-facing docs as tidy as the code the gates already enforce.

Complexity S Impact Low Wow ★★ every .md
ShippedQuality · Style

Theme-asset linting — stylelint + eslint

The shared style/boost.css and boost.js theme the guide, roadmap and demo together, so a bug there recolours or breaks everything at once. stylelint guards the CSS tokens and eslint the reveal/interaction JS — the one place a small mistake has system-wide blast radius.

Complexity S Impact Med Wow ★★ shared blast radius
PlannedTesting · Docs

Post-deploy smoke — headless load check

After each Pages deploy, headless-load the guide and roadmap and assert the essentials: HTTP 200, every asset resolves, and the console is free of errors. Distinct from the planned visual-regression pass — this is a cheap always-on health gate that would have caught the current broken Pages deploy automatically.

Complexity M Impact Med Wow ★★★ catches red deploys
ShippedDocs · Command reference

Command reference documentation site

boost has no browsable command reference — help lives only in --help output and scattered README prose, so there's no versioned, searchable home for what each command does. Build a proper docs site in the shape of learning-python.readthedocs.io: a left-nav tree of commands, per-command pages (synopsis, flags, examples, exit codes), and full-text search. Generate the command pages from the CLI's own definitions so the docs can't drift from the code, and publish alongside the existing Pages site under the Aurora theme.

Complexity M Impact High Wow ★★★★ Read the Docs–style
ShippedDocs · Discoverability

Surface every docs/*.html page from the main page

Making the roadmaps discoverable put both boards in the Visual Guide nav, but the same gap remains for the rest of docs/*.html: mcp-hub.html is reachable only if you already know the URL — nothing on index.html links to it. Add a nav entry for every shipped doc page (today just the MCP Hub, beside Roadmap ↗ / Design ↗) so no page is an orphan, and treat "a new docs/*.html means a new nav link" as the standing rule — ideally checked in CI so a future page can't ship unlinked.

Complexity S Impact Med Wow ★★
ShippedDocs · Visual polish

Fix overflowing node text in the RAG diagram (mcp-hub.html)

On the Fig 2 RAG-pipeline diagram, the read_body → chunk node overflows its rounded box: the third caption line (1000 chars · 150 overlap · ≤40…) runs past the node's right border and is clipped where the pink embed arrow begins. Give the node room so all three lines sit inside the bubble — widen its min-width, wrap or shrink the caption, or trim the label text — and re-check the other nodes at the same breakpoint so none clip.

Complexity S Impact Low Wow ★★ read_body→chunk node clips its 3rd line
ShippedDocs · Design system

Docsite audit — stale counts, dev-noise footers, and a nav that breaks on mobile

Promoting the chrome into style/boost.css gave the docsite .site-nav and footer primitives, but nothing adopted them: three pages still had no nav at all (eval, adapters, mcp-hub), commands.html had neither nav nor footer, and design-roadmap.html had no footer. Alongside that, stale content — the Visual Guide advertised “73 commands” in three places while cli.py's COMMANDS held 78, its embedded array missing adapt, run, trust, hooks and bmad — and unprofessional footers: four pages signed off with “Styled with the shared Aurora design system” over a raw ../style/boost.css link, the roadmap credited “the boost quality loop”, and the MCP Hub listed three internal PR numbers. Shipped: every page now carries the same nav and the same footer — brand line, install line, the page index, GitHub/PyPI/Portfolio and the licence, and nothing else. The command inventory is regenerated from COMMANDS. On phones the link row drops to its own full-width line and scrolls with 40 px tap targets (WCAG 2.5.5) and a faded trailing edge, replacing both roadmap.html's display:none below 560 px — which deleted the nav outright — and the column stack that turned fourteen links into six rows of sticky header. Two latent bugs fell out: roadmap.html's hero was a second bare <header>, so it silently inherited the shared sheet's sticky chrome, and generated cards had no id, so no item could link another. Locked by tests/unit/test_docsite_chrome.py.

Complexity M Impact Med Wow ★★★ 7 pages · one nav, one footer

Compatibility & install integrity

// planned · free tooling to prove boost installs & runs everywhere it claims
ShippedCompat · Platform

Windows in the CI matrix

The test matrix runs macOS and Ubuntu only, so windows-latest path separators, case-sensitivity and console-encoding bugs ship uncaught to any Windows user. Adding one matrix leg closes the biggest untested surface for a tool that promises to work "everywhere your agent does".

Complexity S Impact High Wow ★★★★ untested OS
ShippedTesting · Install

Clean-env install smoke — pip & pipx

Every gate runs against an editable pip install -e ., which hides missing package-data, a broken entry point or an undeclared dependency. A job that pip installs the built wheel into a fresh venv (and pipx installs it) then runs boost --version proves the artifact a user actually gets works.

Complexity S Impact High Wow ★★★★ tests the real artifact
ShippedTesting · Deps

Lowest-version resolution — uv --resolution lowest-direct

CI always installs the newest compatible dependencies, so the lower bounds declared in pyproject.toml are never actually exercised. Resolving and testing against the minimum versions catches the "works here, breaks on the floor we advertise" class of bug.

Complexity S Impact Med Wow ★★★ honours declared floors
ShippedCompat · Python

Pre-release Python canary — 3.14t free-threaded

An allow-failure matrix leg on Python pre-releases and the free-threaded (no-GIL) build gives early warning of breakage before users on new interpreters hit it. Cheap insurance for a project that already targets 3.9 → 3.14 and can't afford a surprise on release day.

Complexity S Impact Med Wow ★★★ continue-on-error
ShippedPerf · Startup

Startup & import-time budget — -X importtime

For a CLI, cold-start latency is the UX — every command pays it. A gate on python -X importtime boost catches the accidental top-level import of a heavy module (the optional [rag] stack is the obvious trap) and keeps common commands feeling instant.

Complexity M Impact High Wow ★★★★ lazy-import guard
ShippedQuality · Packaging

Package-metadata validation — twine check + friends

Before every publish, twine check confirms the long description renders on PyPI, check-wheel-contents catches stray or missing files, and pyroma scores the metadata completeness. Stops a broken PyPI page or an empty wheel from reaching users — the release path currently trusts the build blindly.

Complexity S Impact Med Wow ★★★ pre-publish gate
ShippedSecurity · Repro

Hash-pinned, reproducible toolchain — requirements/*.txt

Every dev/CI tool was resolved at install time, so two runs of the same gate could install different bytes — and only requirements/lint-tools.txt pinned anything at all (added after ruff 0.16.0 reddened the gate with no code change). Now every tool comes from a generated, hash-pinned requirements/*.txt: exact versions plus a sha256 for every artifact in the transitive closure, which pip enforces on install, so a yanked or tampered dependency fails loudly instead of silently changing a build. scripts/lock_toolchain.py regenerates from the .in declarations and --check gates drift in make lint; a new Dependabot pip entry keeps the locks from rotting. One file per consumer, because pip enforces hashes across a whole resolution — and test-tools resolves universally, so one file covers the 3 OS × 3 Python matrix without dragging 3.12/3.14 back to the 3.9 floor's versions. The opt-in [eval] extra stays out on purpose: locking its deliberately-old langchain stack into a scannable file would re-expose the pin osv-scanner.yml is PR-diff-scoped to avoid.

Complexity M Impact Med Wow ★★★ supply-chain repro
ShippedTesting · Infra

One command, every env — nox

A noxfile.py makes the full lint / test / smoke / mutation gate reproducible across 3.9 → 3.14 in isolated environments, locally and in CI alike — so "green on my machine" and "green in CI" finally mean the same thing, and a contributor can run the exact gate before pushing.

Complexity S Impact Med Wow ★★ local == CI
ShippedCompatibility · macOS

Harden boost mcp launch against macOS Obj-C fork aborts

On macOS, a host that spawns boost mcp --stdio via fork() can abort on the child side pre-exec when Obj-C is touched post-fork (CFPreferences / _scproxy proxy lookup) — the classic "crashed on child side of fork pre-exec" SIGABRT. Not boost's own code (it aborts before boost runs), but boost can make its integration robust: when registering the MCP server (boost mcp register / the emitted client config), set OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES (and no_proxy=*) in the launch environment so the host's fork into boost can't trip the Obj-C fork-safety abort. Document it for hosts that launch boost directly.

Complexity S Impact Med Wow ★★★ OBJC_DISABLE_INITIALIZE_FORK_SAFETY
ShippedCompatibility · macOS

Self-harden every boost process against the macOS fork-safety abort

The launch-env fix (#119) only protects hosts that register boost through boost, which injects no_proxy=*. A host that fork()s into boost mcp --stdio from a stale or hand-written config — or any stray default-opener call inside the process — is still one getproxies() away from the macOS _scproxy Obj-C SIGABRT. Close the gap from inside: at the top of main(), seed no_proxy for the current process (only when no *_proxy env is already set, so a real proxy is never clobbered) so the stdlib default getproxies() short-circuits on getproxies_environment() and never consults SystemConfiguration. Belt-and-suspenders atop the nethttp opener (#115).

Complexity S Impact Med Wow ★★★ self-seed no_proxy at startup
PlannedBug

self-update is non-functional for pip/pipx installs

boost self-update only works when boost runs from a git checkout: paths.repo_root() resolves inside site-packages for a pip/pipx install, gitutil.is_repo() is False, and cmd_self_update raises "boost is not running from a git checkout" with a hint to clone the repo — telling a normal PyPI user to abandon their install method. Detect the install method and shell out to pip install --upgrade boost-skill-cli / pipx upgrade boost-skill-cli, falling back to the git-pull path only for source checkouts.

Complexity M Impact High Wow ★★★
ShippedBug · MCP

Order the server name before -e flags in `boost mcp register`

boost mcp register shelled out to claude mcp add --scope user -e OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES -e no_proxy=* boost -- … — the -e flags before the server name. But claude's -e is variadic, so it swallowed boost as a third env var and aborted with Invalid environment variable format: boost, making the one-command install path fail outright on macOS. Reordered to claude mcp add boost --scope user -e … -- … (the add <name> [options] -- <command> form), so the name is consumed as the positional before -e can grab it. A regression test pins name < first -e so a future reorder can't silently re-break it.

Complexity S Impact Med Wow ★★ unbreak `boost mcp register`

Skill-content trust & safety

// planned · boost's core threat model — the third-party skills it installs run inside an agent
ShippedSecurity · Content

Prompt-injection scanning of skill Markdown

The highest-signal gap: boost installs Markdown an agent then executes, and nothing inspects that content. Scan skills for injection patterns — "ignore previous instructions", data-exfiltration prompts, embedded curl … | sh — with free rule engines (semgrep custom rules, garak/llm-guard patterns) at tap and install time.

Complexity M Impact High Wow ★★★★★ the core risk
ShippedSecurity · Integrity

Integrity verification — boost verify

The lockfile already records a sha256 per install via util.sha256_dir, but nothing ever re-checks it. A verify command (and a doctor gate) that re-hashes installed skills and flags drift turns that stored digest into actual tamper-detection — cheap, and built on machinery that already exists.

Complexity S Impact High Wow ★★★★ reuses sha256_dir
ShippedSecurity · Provenance

Tap signing & provenance — Sigstore / minisign

A tap records its commit today but offers no cryptographic proof the content came from its claimed publisher, so a hijacked mirror can serve altered skills undetected. Verify a signature (Sigstore keyless or minisign) before trusting a tap — free, and the standard the wider ecosystem is converging on.

Complexity M Impact Med Wow ★★★★ keyless OIDC
ShippedTrust · Hallucination guard

Runtime hallucination guardrail for boost explain

Today the ragas faithfulness check (Tier 2c, scripts/eval_explain.py) is eval-time only — an offline monitor that flags when generated explanations drift from their SKILL.md, but never intercepts a live response. Promote it to a runtime guardrail: score the generated summary against the source and, when it falls below a faithfulness threshold, fall back to the deterministic extractive summary cmd_explain already ships for the no-AI case (description + outline + key rules) — or append a low-confidence caveat. Turns "a human notices the drift next week" into "the tool refuses to show an ungrounded explanation," closing the gap between detecting hallucinations and preventing them.

Complexity M Impact Med Wow ★★★★ faithfulness → extractive fallback
ShippedSecurity · Registry

Typosquat & name-confusion detection

The classic package-manager attack: a skill named one edit-distance from a popular one, or a familiar name that quietly resolves to an unexpected owner/repo. Flag near-duplicate names and owner mismatches at search and install time so a user can't fat-finger their way into a malicious skill.

Complexity M Impact Med Wow ★★★★ edit-distance guard
ShippedSecurity · Supply chain

Update-diff before apply

Shipped in #132. boost update no longer overwrites an installed skill in place unseen. A new pure core module core/updatediff.py diffs the installed tree against the incoming source (diff_tree) and flags when the change adds executable-looking instructions — shell commands, pipe-to-shell, shebangs (touches_executable). When it does, cmd_update prints the unified diff and requires confirmation before applying, so a poisoned update is visible instead of silent; routine version bumps and prose edits still apply quietly. Fully unit-tested and mutation-covered, plus functional coverage of the confirm / decline / no-gate paths.

Complexity M Impact Med Wow ★★★ no silent overwrites
ShippedSecurity · Secrets

Secret & PII scanning of installed skills

Point the round-2 secret scanners (gitleaks/trufflehog) at third-party skill content, not just boost's own repo — catching a skill that ships embedded credentials or, worse, one whose prompt coaxes the agent into harvesting the user's. Same free tools, a different and higher-stakes target.

Complexity S Impact Med Wow ★★★ installed content
ShippedSecurity · Integrity

Lockfile enforcement & commit pinning

Promoted the recorded sha256 from a note to a rule. The check moved into core/integrity.py (where the mutation gate covers it), and every command that serves a skill's content routes through one resolver that now refuses a tree whose bytes have drifted from the lock — a tamper tripwire at the point of use, since boost can't police what the agent loads but can refuse to hand you a skill that no longer matches what you reviewed. Opt-in (config security.enforce_digest, default off) so it never surprises an existing setup; verify reports drift either way. Commit pinning rides alongside: boost pin <skill> --commit freezes the exact source commit, and verify flags it if the recorded commit ever moves off the pin.

Complexity S Impact Med Wow ★★★ digest binding at load, opt-in
ShippedSecurity · Policy

Capability manifest & least-privilege policy

Extend the existing policy.py so a skill declares the capabilities it expects — network, shell, file scope — and the user's policy allows or denies them. Turns install-time governance into least-privilege for the instructions an agent is about to run, the natural next step for a tool that already blocks installs by policy.

Complexity L Impact Med Wow ★★★★ builds on policy.py
PlannedSecurity · Bug

install_from_path bypasses pin & policy checks

boost import, boost migrate --from-skills-cli, boost rename, and the local-install paths behind the AI distill/evolve commands all route through store.install_from_path(), which never calls policy.check_install() and never checks existing.get("pinned") the way store.install() does. Any of those commands can silently overwrite a pinned skill, or one that blocked_skills/allowed_taps/max_skills/pin_only policy would otherwise refuse. Route install_from_path through the same pinned/existing/policy gates as install().

Complexity S Impact High Wow ★★★ code-scan finding
PlannedSecurity · Bug

Path traversal via unsanitized rule/workflow name

catalog._make_entry only slugifies a catalog name when it contains a space, so a tap's rule/workflow frontmatter carrying name: ../../../../.ssh/authorized_keys sails straight through into rule_target/workflow_target, which build the destination as root / "rules" / (name + ext) with zero traversal guard — unlike skill_store_dir()'s [A-Za-z0-9._-]+ regex. A malicious tap can write an arbitrary file outside .cursor/rules/ or .claude/, and it is worse under --scope project since base is the victim's own repo. Apply the same name-validation regex used by skill_store_dir() before any rule/workflow install path is built.

Complexity M Impact High Wow ★★★ live-reproduced
ShippedTrust · Health

boost audit --skills — a trust/staleness report for installed skills

boost already computes every individual trust signal, each in its own command: verify checks lock-file integrity, outdated compares an installed skill against its tap, trust reports tap-level signing provenance, deps shows the requires:/conflicts: graph. What nothing answered is the aggregate question — of the skills I actually run, which ones should I stop trusting? boost audit --skills gathers all of it into one report: every installed skill that is unsigned, signed by an untrusted key, signed but failing verification, sitting on a tap nobody has synced in a month, behind its tap, or conflicting with another installed skill. The decision layer is core/trustaudit.py — pure and I/O-free like core/staleness.py, so every branch is unit-tested and reachable by the mutation gate. Only a malformed signature is HIGH; an unsigned tap is the norm for most of the catalog today and stays LOW, so the command never cries wolf on an ordinary install.

Complexity M Impact Med Wow ★★★ audit what you run