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 to main & publishedGitHub Pages deploy is broken every push
Mutation hardening — core/store.py
Mutation hardening — core/gitutil.py
Untrack generated build noise
browse crashes when you pick a rule or workflow
Consolidate skill-staleness / drift logic into core
Write-up · consolidate-skill-staleness-drift-logic-into-cor.md
Mutation hardening — core/frontmatter.py
Extension-free tests — core/dense.py
Crash-recorder error paths — core/logs.py
Extract MCP + HTTP servers out of configuration.py
Write-up · extract-mcp-http-servers-out-of-configuration-py.md
Autonomous ship-workflow & isolated worktree
Write-up · autonomous-ship-workflow-and-isolated-worktree.md
Fix self-update version detection (dead branch)
End-of-options -- guard on git commands
Crash-correlation breadcrumbs in the invocation log
The copyleft protected nothing and cost the one thing boost needs
bmad on knew about a second host and wrote to one anyway
A Gemini user got the heuristic fallback from every AI command
Reuse helpers; kill minor dead work
All 80 boost commands audited against a disposable HOME — four defects fixed
fix_hint's no-key guard has been unreachable since the day it was written; a missing API key now prescribes the full re-embed the guard exists to prevent
The eval corpus's size and its concentration ceiling are counted with len(scan_dir) — the measure measure_registry.py exists to say is wrong — so 44.7% of the gate's corpus is vendored …
Write-up · eval-corpus-counted-by-the-method-the-repo-disavows.md
The 2026-09-01 pin refresh moved the corpus and re-baselined it, but nothing re-derives the floors — CLAUDE.md's "~10% under measured" is now 7.2%–17.3%
Write-up · eval-floor-calibration-stale-after-pin-refresh.md
The exemplar mechanism was applied to the ungated set only: golden.jsonl is 0/91 pinned, and 10 of its 44 hit@1 credits are on names the metric cannot adjudicate
The exemplar migration never reached the query set the required gate runs: 0 of 91 rows, and 27 of them have an ambiguous target on the gate's own corpus
Research: how boost install could tell that a skill needs something else installed first
A locally built vector store displaced by a new API key is told to re-embed through the paid provider, where unsetting the key is free
Next up
// triaged findings, starting soonReconcile the theme drift
Planned
// on the listFinish mutation hardening across core/
Bring commands/ under mutation testing
The ~8,100-line command layer has zero mutation coverage: mutmut is
scoped to core/ only. A blocking 80% floor was attempted and the
baseline has now actually been measured — it does not clear the bar, and
two of the three constraints recorded here earlier were wrong. What a sample run
of commands/taps.py (the best-covered module in the package,
95.8% lines) against tests/unit/ + tests/functional/
reports through this repo's own gate:
570/793 killed — 71.9%, under the 80% floor, with all 223
survivors spread across every one of the module's 7 functions rather than
concentrated in one testable gap. Mutant density is 4.2 per
statement in taps.py but 2.46 across
core/ (9,909 mutants over 4,033 statements), so
commands/'s 5,314 statements imply somewhere between
13,000 and 22,300 mutants; at the measured
1.42 mutations/sec — roughly 6.5× slower per mutant than the
core/ job, which matches the functional-vs-unit suite cost — that is
2.5 to 4.5 hours on one runner, against an ~18-minute job today.
The job sets no timeout-minutes, so it inherits GitHub's 360-minute
cap rather than failing fast.
Two blockers sit underneath that number. Selecting only tests/unit/,
the way core/ does, leaves commands/ at
17.9% line coverage versus 91.5% with functional included — and
"no tests" mutants count against the score, so that route floors out near 18%.
Selecting tests/functional/ instead crashes the run: mutmut's
record_trampoline_hit calls p.resolve(strict=True) on the
relative source path, so any test that chdirs into a temp
project dies with FileNotFoundError: <tmp>/boost_cli — confirmed
on test_verify_sees_a_project_skill. Corrections to the earlier note:
pytest_add_cli_args_test_selection is not single-valued, it
is a list that configparser splits on newlines (a space-separated line is what
errors), and a sibling pytest_add_cli_args takes extra pytest flags.
One prerequisite is already fixed: --no-mcp leaked through
os.environ and made the suite order-dependent, which mutmut exposes
because it runs whichever test subset covers each mutant.
Declined 2026-07-29. Not "hard" — blocked, and the block is
upstream. mutmut 3.6.0 is still the latest release, and
src/mutmut/__main__.py:120 still reads
source_paths = [p.resolve(strict=True) for p in Config.get().source_paths]
— unconditionally, before the max_stack_depth guard — on paths that
configuration.py:102 builds as plain relative Paths. Every
chdir-ing functional test therefore kills the run, and the functional
suite is precisely what takes commands/ from 17.9% to 91.5% line
coverage. So the two candidate configurations are "floors out near 18%" and "crashes";
there is no third. Even granting a fix, the measured numbers already refuse the
proposal on their own terms: 71.9% against an 80% blocking floor, with
survivors spread evenly rather than pooled in one testable gap, at
2.5–4.5 hours per run against an ~18-minute job. A gate that is 8 points red
on the day it lands does not gate anything; it just makes main red.
The lead, if anyone reopens this: the crash is a relative-path bug, and
source_paths is not required to be relative — an absolute path survives
resolve(strict=True) from any working directory. Whether the rest of
mutmut's mutants/ copy machinery tolerates one is untested. That, plus a
non-blocking scheduled job that rotates one module per week, is the shape worth
trying; a blocking 80% floor is not.
What is not lost by declining. The architecture already puts behaviour in
core/ — which is mutation-gated at 80% — and keeps
commands/ as thin CLI glue. The uncovered layer is the one deliberately
designed to hold the least logic, and it still carries 91.5% line coverage from the
functional suite.
Visual regression pass on the guide
Refresh the marketing surface
a Tier 3 eval for tool-call behaviour, floored in both directions
unpin the [eval] langchain stack when ragas ships its fix
The [eval] extra pins langchain-core<0.4,
langchain-community<0.4 and langchain-openai<1 because ragas hard-imports
ChatVertexAI from a langchain_community chat-models path that 0.4.x
deleted. The LangChain integration card originally made this unpin its phase 0 and was
corrected in place: ragas 0.4.3 still carries the import (measured 2026-08-04 — declared
bounds are open, but import ragas crashes beside langchain 1.x), while upstream main
already has the removal merged. So the unpin is one release of someone else's package away.
What to do when it lands. Check pip index versions ragas (or the PyPI JSON) for
a release after 0.4.3; verify in a throwaway venv that import ragas succeeds beside
langchain>=1; then move [eval] to that floor, delete the three langchain
pins, and adapt scripts/eval_explain.py if the 0.4 scoring API moved (its
evaluate/to_pandas surface is what
test_eval_faithfulness.py stubs in the unit suite). The eval-explain workflow is
the live proof — it must stay green with real keys.
Re-checked 2026-08-30. pip index versions ragas still reports
0.4.3 as the newest release, so nothing has changed and this card is still not
claimable. Recorded here rather than left implicit: a card that says "check before starting"
gives a reader no way to tell a check that came back negative from a check nobody ran.
Why it stays its own card. The shipped integration card documents the block but will not be
re-read; an unpin nobody remembers is how a workaround pin outlives its reason by years. This card
is the reminder, and it is deliberately not claimable until the upstream release exists.
Re-checked 2026-10-09. The PyPI simple index still lists 0.4.3 as the newest
ragas, so this card stays blocked.
give boost-langchain a release path to PyPI
Declined, deliberately. Both missing pieces below were owner-only or upstream-blocked, and
the research they prompted dissolved the premise: a second PyPI project bought a separate release
cadence nobody needed (boost releases more often than langchain), while the ecosystem evidence —
langchain-community sunset, non-langchain-* names in LangChain's own integrations
listing, in-host precedents from ragatouille to mlflow — showed the
standalone distribution was never required. The integration now ships inside the
boost-skill-cli wheel behind a [langchain] extra instead; see
langchain-in-the-wheel. The original card follows for the record.
The boost-langchain distribution shipped under integrations/langchain/
with its whole point being a separate release cadence from boost-skill-cli —
langchain majors move faster than boost does, and the conformance workflow already builds the
sdist/wheel and runs twine check on every touching PR. What does not exist is any way
for those artifacts to reach PyPI: the name 404s there, and nothing publishes on any trigger.
Two pieces, one of which only the repo owner can do. First, create the PyPI project and
configure a Trusted Publisher for it — pending-publisher registration works before the first
upload, and the filename-matching rule that pinned boost's own workflow name applies here too.
Second, a publish workflow with a deliberate trigger: not boost's every-merge cadence
(publish.yml releases boost-skill-cli on every push to main, which is
exactly the coupling the separate distribution exists to avoid) — a tag like
boost-langchain-v0.1.0 or a manual dispatch that bumps the static version, builds from
integrations/langchain/, and publishes with the OIDC token. Remember the repo's own
lesson: a release:-triggered workflow can never fire here (GITHUB_TOKEN events do not
chain), so trigger on the tag push or dispatch directly.
The floor is already honest. The package requires boost-skill-cli>=1.0.320 —
measured against the actual API it calls, verified by an adversarial install — so the first
published version works against PyPI as it stands today.
publish the keyword index the way vectors are published
shrink the keyword index before publishing it — structure first, then compression
A best-effort log handler prints a traceback over every command's output
Near-identical copies survive content-hash dedup and take the whole result page
The monthly corpus refresh rewrote the pins and the baseline but left every documented number stale — taps.txt now contradicts its own header, and nothing checks it
With a corrupt config.json, doctor reports "no registries tapped" and verdicts "● ready to set up" exit 0 while search is dead; heal says "nothing to heal"
BOOST_NO_EMBED has no state in the reason ladder: doctor calls a deliberate kill switch a degraded fault (exit 1) and hands advice that is a measured no-op in both branches
status() has no state for "ready but the embedder does not work": doctor green-ticks a tier that never ran, the search hint is suppressed, and every search re-pays the failed model fetch
out.err's multi-line hint is coloured as one span, so line 1 ends with no RESET and lines 2+ carry no start code
The corpus's 65.6% duplication is 99.93% inside a single tap, so the required gate never once exercises the cross-tap trust ordering dedup exists for — 0 swaps in 264,735 comparisons
Declined, and re-measured first on origin/main's pins. Same instrumentation over the 91-query golden.jsonl on the current 10,731-entry corpus: 264,737 collapse comparisons, 264,546 same-tap (99.93%), 191 cross-tap, 0 swaps. Marking composio-community/awesome-codex-skills curated fires 191 swaps and leaves BM25 at 0.846154 / 0.483516 / 0.606517 / 0.659484 (recall@k / hit@1 / MRR / nDCG@k) both ways — exactly the committed baseline.json — with all 91 graded top-k lists byte-identical. Nothing ships, for the reason this card already found: grade_key is invariant under a swap by construction, because a swap only replaces the entry inside one content cluster. Source preference is not a relevance metric, and the retrieval gate is right not to grade it. Where it is graded already: tests/unit/test_rag_fastpath.py::test_curated_copy_promoted_but_rank_and_score_kept runs a real cross-tap curated duplicate through rag.retrieve and asserts the cluster collapses to one hit, that the hit is the curated tap's copy, and that the fast path matches the entries= path; test_dedup_trust.py::test_the_cluster_keeps_its_best_score pins the kept score directly, and test_dedup_trust.py / test_content_dedupe.py pin the source_rank ordering in both directions — all inside make check's test and mutation gates. Making the eval gate non-vacuous here would mean curating a tap in the pinned corpus (all five cross-tap clusters are high/high, so source_rank ties), which changes a gate input, forces a baseline regeneration and adds no coverage the unit tier lacks. The taps.txt header "doc trap" is gone too: origin/main generates the size block from the rows and tests/unit/test_corpus_prose.py checks the quoted figures, and the remaining 10,152 mentions are figures measured on the earlier #410 pins. Three of them say so (taps.txt, scripts/eval_corpus.py, docs/rag-architecture.md); the rest quote the size as it was then.
Measured (the original finding, measured at the card's original pins in 52b5adcd, before #992 and the golden-row pinning moved these figures; the title and this paragraph keep its figures, and the paragraph above supersedes them). Over the 91 required golden queries on the current pins, 264,544 of 264,735 collapse comparisons inside rag.dedupe_by_content (99.93%) were between two copies in the SAME tap and the source-preference branch executed 0 times; and forcing it to fire — marking one tap curated produces 191 swaps — leaves recall@k / hit@1 / MRR / nDCG@k at 0.8407 / 0.4835 / 0.6065 / 0.6552 both before and after, with all 91 graded ranked-key lists identical.
Reproduce it.
cd <repo>
export HOME=$TMPDIR/audit-corpus-verify && export BOOST_HOME=$HOME/.boost # after eval_corpus.py --ensure (see other finding)
.venv/bin/python - <<'PY'
import sys, json
sys.path.insert(0,"."); sys.path.insert(0,"scripts")
from boost_cli.core import rag
from boost_cli.core.rag import source_rank
stats={"collapses":0,"same_tap":0,"diff_tap":0,"swaps":0,"ties":0}
def patched(hits, limit):
best={}; out=[]
for hit in hits:
d=hit.get("content")
if not d: out.append(hit); continue
s=best.get(d)
if s is None: best[d]=len(out); out.append(hit); continue
stats["collapses"]+=1; kept=out[s]
…
What adversarial verification corrected. This card's numbers are the re-measured ones, not the ones first reported.
1. THE REMEDY CLAIM IS WRONG, and this is the correction that matters. The finding's why_it_matters says "adding a single mirror registry to taps.txt would be enough to make it visible." It would not. eval_retrieval.grade_key (scripts/eval_retrieval.py:197-209) keys every ranked slot on the content digest (body:<digest>), the exemplar class (cls:...), or the entry name — and a swap only ever replaces hit["entry"] INSIDE a content cluster, where the digest is identical by construction and, because catalog._content_digest hashes name + description + body, so is the name. Every return branch of grade_key is therefore invariant under a swap; the nohash:tap::skill_md branch at :209 is unreachable for a swapped hit because dedupe never collapses a hit with no digest. Proven, not argued: marking composio-community/awesome-codex-skills curated on the same pinned corpus fires 191 swaps (every cross-tap collapse becomes a swap — the composio copy arrives second in all 191) and leaves recall@k / hit@1 / MRR / nDCG@k at 0.840659 / 0.483516 / 0.606517 / 0.655233 before AND after, with all 91 graded ranked-key lists byte-identical. So a trust-ordering regression is invisible to the required gate BY CONSTRUCTION, regardless of corpus shape — the gap is that the harness never grades on source, not that the corpus lacks mirrors.
What is NOT established. Recorded because a card that overstates its own evidence is worse than no card.
SCOPE OF MY REPRO — read this before re-verifying. The finder's numbers reproduce ONLY on the CURRENT pins (10,731 entries). The shared read-only corpus at $TMPDIR/eval-home is PRE-REFRESH: 10 of its 20 clones are not at the SHAs in tests/eval/taps.txt (anthropics/skills, NeoLabHQ, LessUp, affaan-m/ECC, first-fluke, langchain-ai, minio, OneWave-AI, sickn33, anthropics/claude-agent-sdk-python), and it holds 10,152 entries. There the same instrumentation gives 1,986 clusters / 6,348 entries (62.5%) / 240,646 collapses / 240,455 same_tap / 191 diff_tap / 0 swaps. I materialised the current pins into a private copy (eval_corpus.py --ensure, network fetch works despite a harmless failed to store: 100001 commit-graph warning) to get the finder's exact figures. Anyone re-checking against $TMPDIR/eval-home will get the smaller set and should not read that as refuting the finding — the qualitative result (5 cross-tap clusters, all high/high, 0 swaps, ~99.9% same-tap) is identical on both.
DOC TRAP, not this finding's fault: tests/eval/taps.txt's own header prose says "10,152 entries" and "sickn33 … is 6,309", and CLAUDE.md repeats 10,152 — but the file's own per-repo rows sum to 10,731 with sickn33 at 6,634. The pins were moved in commit cbc0a58b ("test(eval): refresh the pinned retrieval corpus") and the header prose was not updated. A card author quoting corpus size must take the row sum, not the header.
NOT ALREADY CARDED, but read the existing card first.
Why it is worth doing. The required corpus contains essentially none of the duplicate shape that dominates a real install. A user's duplicates arrive as mirror registries republishing each other's skills across taps, which is what source_rank decides between and what determines where a user is told to install from; the gate's duplicates are one publisher re-vendoring itself into 60 plugin bundles, where every candidate has the same tap and the tie-break is a no-op.
Found by an automated audit of retrieval/eval quality, the search & browse surfaces, and first-run onboarding; every finding was then re-measured from scratch by an independent adversarial verifier whose instruction was to refute it. Verdict: CORRECTED. No fix is prescribed here — the measurement is the contribution.
make eval scores a corpus with every SKILL.md body missing, reports all four floors PASS, and scores HIGHER than the real corpus
boost explain's heuristic fallback prints every heading in the file — 541 lines for one skill — while the sibling list in the same function caps at 12
The CI-vs-Makefile floor-parity test compares only the floor VALUES, so changing -k in ci.yml turns a PASS into a FAIL with the test still green
boost info/deps on a not-installed rule or workflow widens the tap's sparse cone for a directory source_dir_for immediately rejects
boost_install's description enumerates four of the five enabled agent targets and omits Antigravity CLI, the fourth linking agent
boost_search advertises "10-15 seconds" unconditionally; with no AI configured it is 0.013 s median and the rerank never runs
Write-up · mcp-search-cost-overstated-on-keyless-machines.md
The skip list — the one bound on boost's triggers — ships in INSTRUCTIONS only, in zero of the seven tool descriptions
out.panel still fits its content to term_width(), so boost count | … clips the line to an assumed 80 columns
quickstart silently discards the incompatible shard status, so a user with any API key is never told why zero vectors arrived
A local manifest read error is reported as "no published shards", and the BoostError's hint — the only actionable line — is discarded
Write-up · quickstart-manifest-error-drops-hint-and-misnames-cause.md
With every registry unreachable, quickstart prints "✓ indexed 0 items" and "✓ ready", exits 0 — and the command it recommends exits 1
Write-up · quickstart-says-ready-exit-0-after-every-tap-failed.md
The shard download is invisible both before and during: --catalog --dry-run never names the 1,604.8 MB, and the live fetch passes no progress callback and has no spinner
Write-up · quickstart-shard-download-invisible-in-preview-and-run.md
README's "81 commands" table enumerates only 80 — the missing one is quickstart, the README's own first command
Write-up · readme-81-command-table-lists-80-omits-quickstart.md
README's hero block ends in exit 1: boost install tdd-workflow names a skill no starter registry ships
Write-up · readme-hero-installs-a-name-no-starter-registry-ships.md
boost recommend sizes the description cell per row from that row's because: text, so neither column lines up
The corpus refresh re-baselines only golden.jsonl, so golden-natural.jsonl's baseline silently describes a corpus that no longer exists
The two roadmap boards' install footers still advertise Python 3.9+, four minor versions under the real floor
search caps the name column at 32 and the tap column at 20 at every terminal width, while the description column grows without limit
The search footer is the one unfitted line on a screen search_layout just fitted: 55 columns in a 40-column pane
Write-up · search-footer-not-fitted-to-the-pane-its-rows-were-fitted-to.md
boost search's footer overflows a 40-column pane by 2-15 cells, and the gate that swears it doesn't passes only because its fixture returns exactly one match
Write-up · search-footer-overflows-40-col-pane-gate-passes-by-luck.md
The relevance meter and its "one gradient moment" are constant on the default result page: 138/150 rows full bars, 150/150 the same colour
Write-up · search-relevance-meter-is-constant-on-default-page.md
boost search rows fit to term_width(), not pane_width(), so a piped search silently loses the TAP column entirely
Write-up · search-rows-use-term-width-so-piping-drops-the-tap-column.md
The contributor-onboarding gate tables state three wrong suite sizes, and README and CONTRIBUTING disagree with each other
rag.surface's de-hyphenated name copy is justified by two claims that are both false, and its real effect — an undocumented 3x name / 2x description field weight — is guarded by a test …
_fit_widths shrinks data columns to a bare "…" and still overflows: boost taps is 54 columns wide on every terminal narrower than 54
Write-up · table-fit-widths-floor-destroys-columns-and-still-overflows.md
Tier 3's false-call ceiling is unreachable at its own default N, and tolerates zero false calls at the N make eval-tools uses
An unreadable tap cache is invisible to doctor ("✓ 1 tap cloned & cached", exit 0) while search, browse and heal all exit 70 with a crash report
Write-up · unreadable-tap-cache-healthy-doctor-crashing-heal.md
"! agent dir ~/.cursor/skills is not writable" is the one doctor issue with no next action — heal has no path for it and the next install crashes at exit 70
Nothing boost prints ever names an entry point: bare ./boost is byte-identical on a virgin machine and a working one, and the one command its failure-hints route you to is the only setup …
golden-natural.jsonl — the only fully exemplar-graded query set — is invoked by no make target and no workflow, so its numbers can only be produced by a human typing the command
The "taps last refreshed N days ago" hint can never fire on a machine that tapped and never ran boost update — the only writer of the marker is update itself
CLAUDE.md instructs the wrong licence: every new source file is told to carry GPL-3.0-only in a repo whose 373 headers, LICENSE and pyproject all say Apache-2.0
At a narrow pane boost hooks list drops name, the argument hooks remove -n takes, while host and scope survive
An unwritable agent rules/ or commands/ dir still crashes a rule or workflow install at exit 70
Write-up · unwritable-rule-or-workflow-dir-crashes-install.md
Two config.json shapes still slip past the corrupt-config handling. Invalid UTF-8 crashes every command, doctor included. {"taps": "x"} is a fresh install to doctor and a configured machine to --help.
Two cache writers still crash on what one sudo boost leaves behind. A read-only _names.txt fails heal, update and untap at exit 70 while doctor says healthy.
Write-up · cache-writers-that-still-crash-on-a-read-only-cache.md
Just before out.table drops a column, it shrinks the widest one with an ellipsis. In hooks list that is often name, and bmad-r… is not a name hooks remove -n accepts.
Write-up · identifier-columns-shrink-to-a-name-no-command-accepts.md
Under a read-only ~/.boost with no cache dir, update, heal and doctor crash at exit 70, and heal --dry-run says 0 for a run that crashes
With an API key exported and no vector store yet, doctor and search send the user to a paid build while quickstart offers the free download
Write-up · keyed-no-store-hint-disagrees-with-shard-remedy.md
A rule or workflow row for a disabled agent makes boost sync claim the same repair on every run, and doctor never goes healthy
Agent-dir shapes boost still trips on: a parent with no search bit, a missing dir under a read-only parent, a dir at a rule's file path, a blocked agent dropped from the lock's scope
Six install paths still printed success over an agent dir that refused the link
A reinstall into a locked skills dir says "not linked" over a link that is already there and correct
Write-up · a-correct-link-in-a-locked-dir-reads-as-refused.md
A refusal and its remedy print past the pane, on the one line a user reads before acting
The import-budget gate reports OK when the command it measures never ran
Write-up · import-budget-gate-passes-when-boost-cannot-import.md
The release guard fails open when it cannot read the commit's tags
Write-up · release-guard-fails-open-when-it-cannot-read-tags.md
One failed shard-build job silently drops its whole chunk from the published manifest
Write-up · one-failed-shard-job-drops-registries-from-the-manifest.md
The CI job summary reports the coverage gate as 80% when it is 90%
One valid-JSON message that is not an object kills the whole MCP session
Write-up · mcp-server-dies-on-a-valid-json-message-that-is-not-an-object.md
boost_doctor certifies a machine healthy that boost_search calls untapped
Write-up · mcp-doctor-says-healthy-where-mcp-search-says-nothing-is-tapped.md
MANIFEST.in prunes only the root copy, so dev-local files ship in the sdist
A search that finds nothing echoes the whole query back into the agent's context
A deeply nested JSON line kills the MCP session, because the parse guard names one exception
The model back-off dated its record by the filesystem clock and read it against the process clock
boost mcp registration writes outside a sandboxed HOME
Write-up · mcp-registration-writes-outside-a-sandboxed-home.md
Codex hooks are shaped like Claude's, and the two fields that differ are unverified
Registering a skill's MCP server handed Antigravity the one argv its CLI rejects
wrap() sizes a stderr line by stdout's pane
Engine & command internals
// concrete file:line findings from the code scanSemantic search is gated behind an API key it does not need
Every dense search re-scanned all 3.08 GB of vectors — vec0 has no ANN index
Memoize config.load() in-process
Atomic skill install (temp-dir swap)
One shared atomic-write helper
Unify _tilde() — two copies have a boundary bug
Cache the catalog entry-set across RAG queries
Write-up · cache-the-catalog-entry-set-across-rag-queries.md
Stop re-serializing entry meta on every search
Write-up · stop-re-serializing-entry-meta-on-every-search.md
Prune ignored dirs during scan_dir walk
Single tech-stack prober
Single imperative-rule extractor
Split oversized command modules
Robust tag argument parsing
Localize the stored BM25 snippet
Frontmatter scalar over-coercion
Rule install — materialize rules into each agent's native format
Workflow install — drop commands/subagents into each agent's native dir
Workspace scope — boost install --local into the project
boost list shows installed rules and workflows
Teach the rest of the CLI about project scope
boost update refreshes installed rules and workflows
Scan and sync rules/workflows like skills
boost install --scope user|project for rules/workflows
Ambiguous tap short-name resolution silently picks the wrong tap
sync --apply deletes any broken symlink, not just boost's own
Dense search's empty result skips the BM25 fallback
Journal rotation has a lost-update race between concurrent processes
boost uninstall has no confirmation prompt
update/reinstall silently widen a skill's agent scope
lint --tap mis-scores rule/workflow entries as broken
sync relinks a narrowed skill into every agent
Dependabot raises every toolchain bump twice
Write-up · dependabot-root-pip-entry-duplicates-requirements.md
boost onboard silently overwrites existing generated files
Write-up · onboard-overwrites-generated-files-without-confirm.md
Dependabot cannot regenerate the hash-pinned locks
Negative -n silently inverts log/pulse output
The toolchain lock has no proactive update path any more
boost log --crashes listing branch has no non-empty test
boost serve's own path-traversal guards are untested
Diagnostic log has no structured/JSON output mode
AI bridge swallows failures with zero diagnostic trail
The eval gate reports a perfect score on a corpus 4× smaller than a real user's
boost info rejects the tap-qualified name its own error tells you to type
The axe-core sweep intermittently fails color-contrast on a page the PR never touched
The eval gate would not pass on the catalogue its own users have
Write-up · eval-corpus-is-96x-smaller-than-a-real-install.md
The golden set grades by name, and 35 of 53 names are ambiguous
The “pinned” eval corpus pinned names, not commits
The eval de-duplicated its ranked list by name, so homonyms shared a rank
62% of the required gate's corpus is a single third-party repository
Nothing refreshes the eval corpus pins, so the gate measures one frozen day
agents recorded the request, not what was linked
Write-up · agents-field-records-the-request-not-the-links.md
the Python floor moves from 3.9 to 3.12
the typing.List → list sweep the floor now allows
audit the 16 zip() calls the 3.12 floor made checkable
boost search never noticed a tap added after the first search
boost update told you to run a flag it then rejected
one deleted upstream stopped boost update for every other tap
The update path skipped the scan the install path runs
heal removed symlinks boost never created
bring scripts/ under the ruff gate
install --dry-run predicted an install that never happens
boost_search never said which ranking produced its answer
est_items counted one skill fourteen times once registries went multi-agent
The catalog was missing the two most-starred token-efficiency registries
Dependabot splits one action repo into three unmergeable PRs
The shards workflow has never once produced a shard
The repair command could not repair the thing two commands sent you to it for
Taps download and check out the 84% of a repo that boost never opens
A catalog entry knew where it came from, never what it was
a convention that said "verify the repo is real" verified nothing
Write-up · the-catalogue-advertised-repos-that-no-longer-exist.md
Path.exists() looks total, and is not
a publisher that could not publish, and an alert that could not stand down
the shard job that had never once finished, and the timeout that could not be raised
the scheduled re-pin that refreshed the twenty rows it must not touch, and none of the hundred and sixty-five it existed to pin
--category marketing matched nothing, while four marketing registries sat in the catalog under other names
reindex --dense runs for hours behind a bare spinner, and a cancel discards all of it
Dense reuse is per tap, so one changed file re-embeds the whole registry
The dense store keeps one vector per copy, not one per distinct text
adapt renders every sibling of a flat agents/-dir workflow as a 138-agent crew
Write-up · audit-adapt-renders-every-sibling-of-a-flat-agents-dir-workflow-as.md
reinstall, sync repair and audit resolve by name+tap, ignoring the lock's source path
Write-up · audit-reinstall-sync-repair-and-audit-resolve-by-name-tap-ignoring.md
Pinned taps silently moved to HEAD by update re-clone and compact --reclone, pin left stale
Write-up · audit-pinned-taps-silently-moved-to-head-by-update-re-clone-and-co.md
focus/profile sideline by unlinking without recording it; list lies, doctor exits 1, and its own remedy (sync) undoes the switch
Write-up · audit-focus-profile-sideline-by-unlinking-without-recording-it-lis.md
snapshot restore replaces the lock wholesale, orphaning newer rules' CLAUDE.md blocks
Write-up · audit-snapshot-restore-replaces-the-lock-wholesale-orphaning-newer.md
boost create: CLI audit findings (2026-08)
boost reindex: CLI audit findings (2026-08)
quickstart reruns re-download every shard; shards.sync never asks what is built
Two concurrent rag.build() runs delete each other's temp index
Write-up · concurrent-rag-builds-delete-each-others-temp-index.md
compact --reclone left a clone on HEAD when it could not reach the pin
Write-up · reclone-leaves-a-clone-on-head-when-it-cannot-reach-the-pin.md
compact <tap> answers a question about one tap with a global all-clear
Write-up · compact-answers-a-named-tap-with-a-global-all-clear.md
boost taps vouches for a clone that is not there
reindex reported a completeness share it could not compute
Write-up · reindex-reported-a-completeness-share-it-could-not-compute.md
A scan that stops the bare-int count flag coming back
The sandbox fixture sandboxes every env var except the one project scope reads
Write-up · sandbox-fixture-does-not-sandbox-the-working-directory.md
The links job fetches 467 URLs from one host at once and GitHub 503s a random handful
Capping the burst did not stop the 503s — the whole fetch was signal-free
One 30-minute cap for nine matrix cells, and only Windows is anywhere near it
Write-up · the-windows-test-cap-is-five-minutes-from-the-measurement.md
Code health & security
// planned · free tooling to catch vulns, smells & bugsSecurity linting — bandit via ruff S rules
Dependency CVE gate — pip-audit
Retrieval-quality eval harness (Tier 1 + rerank lift)
Supply-chain posture — OpenSSF Scorecard
Grow & diversify the golden set for statistical power
OpenSSF Best Practices — all 67 passing criteria answered
Secret scanning — gitleaks + push protection
Complexity & dead-code radar — xenon · vulture
OSPS Baseline — three levels, audited rather than assumed
Significance-tracked engine comparison (ranx monitor)
Quality dashboard — SonarCloud (free for OSS)
OpenSSF silver — reachable solo, and mostly already true
Property-based tests — hypothesis on the parsers
Write-up · property-based-tests-hypothesis-on-the-parsers.md
Coverage-guided fuzzing — atheris / OSS-Fuzz
OpenSSF gold — how far it goes without a second human
Fork-safe network layer — explicit ProxyHandler
The README read like a machine wrote it — measurably
main went red because "require branches up to date" was never actually on
Log timestamps are local time mislabeled Z
mypy's default mode skips untyped command bodies
ruff 0.16 widens the default rule set — 83 new errors on a version bump
The lock invariant can't parse name[extra]==version, so a valid pin fails the gate
boost doctor checks installed rules and workflows
rel_time tests race the wall clock and flake on a loaded runner
Gemini logged a skill conflict every session and boost doctor called the machine healthy
A machine-readable VEX feed, sourced from findings that already existed
A missing or corrupt lock file makes doctor prescribe boost sync/boost heal, and both delete every live agent symlink of an intact install
Write-up · doctor-prescribes-sync-that-deletes-live-links.md
import --all skips the injection/secret scans and the per-skill report single import runs
Write-up · audit-import-all-skips-the-injection-secret-scans-and-the-per-skil.md
verify/drift say 'nothing installed' (exit 0) when the lock file is missing or corrupt
Write-up · audit-verify-drift-say-nothing-installed-exit-0-and-doctor-says-lo.md
Quarantine/pin state invisible: list/info/doctor report links and materializations that were removed
Write-up · audit-quarantine-pin-state-invisible-list-info-doctor-report-links.md
boost audit: CLI audit findings (2026-08)
boost doctor: CLI audit findings (2026-08)
boost drift: CLI audit findings (2026-08)
boost fingerprint: CLI audit findings (2026-08)
boost health: CLI audit findings (2026-08)
boost lint: CLI audit findings (2026-08)
boost policy: CLI audit findings (2026-08)
boost quarantine --release: CLI audit findings (2026-08)
boost test: CLI audit findings (2026-08)
boost verify: CLI audit findings (2026-08)
Three commands that denied what was on the disk in front of them
The lock kept advertising links it had just removed
One unresolvable agent dir silences the whole `boost doctor` report
Write-up · one-bad-agent-dir-silences-the-whole-doctor-report.md
An item materialized nowhere reads ok in verify, health and drift
Write-up · an-item-materialized-nowhere-reads-ok-in-verify-health-drift.md
Pipeline & supply-chain integrity
// planned · free tooling to secure the CI/CD path itselfPrebuilt vectors are published where no new user can reach them
Workflow SAST — zizmor
Every weekly shard run re-embedded the whole catalogue
Workflow linting — actionlint
Build provenance — SLSA attestations
SBOM on every release — CycloneDX / Syft
SBOM-aware scanning — osv-scanner
Second type checker — pyright
Widen the ruff rule surface — B·SIM·C4·PERF·RUF
Patch-coverage gate — diff-cover
publish.yml ignores the pip-audit / metadata gates
No timeout-minutes on any CI job
Dependabot's pip entry misses pyproject.toml's extras
License-compliance scanning of the dependency closure
The pytest tmpdir CVE — unfixable, then closed by the floor move
OpenSSF Scorecard's findings, triaged into three piles
main has no branch protection, so the release rules are honour-system
adapter-conformance's LangGraph leg never passed — a quoted matrix value
The required-check gate could not see paths:, so it green-lit a list that deadlocks every PR
Write-up · required-checks-can-declare-a-check-that-deadlocks-prs.md
ci.yml's job summary could exit 1 on its own, under the always() it was given
post-deploy.yml's always() destroyed the second signal it existed to preserve
markdownlint linted the fuzzer's corpus, so shipping a crash reproducer would redden a prose gate
Enabling a merge queue would deadlock every required check except ci.yml's
Write-up · merge-queue-would-deadlock-most-required-checks.md
The mutation gate was CI — 26 minutes, three times the next-longest job
The mutation gate's floor is a single file — shard 0 is store.py
A third of CI job time is spent waiting for a runner, not running
The required lint job pins zizmor==1.27.0 — a yanked release
The release verifies one commit and ships another
demo.yml still fails on every push — and the fix is not in the workflow
68 of the repo's 77 branches are merged loop/* branches nobody deletes
One commit can cut two releases, and the naive guard against it breaks retries
Near-duplicate items consume the top-10, and it gets worse with every tap
The BM25 index is one JSON blob, and it stops working between 10k and 50k items
Semantic search for users who will never set an API key
Dense retrieval today needs the [rag] extra and a
VOYAGE_API_KEY/OPENAI_API_KEY and a built
store. Most users will do none of that, so the default experience is BM25
forever. The keyless path is a local static embedding model —
potion-retrieval-32M class, MIT, model2vec family — which is not a
transformer: the entire weight file is one lookup table, so inference is
tokenize → gather rows → mean-pool → L2-normalize.
Measured locally, pure stdlib: ~1 ms to embed a query (mmap + bisect over
sorted keys), 12.8 MB of int8 vectors for 50k items at 256-d, and ~20 ms to
rerank BM25's top-200. No numpy, no sqlite-vec, no ANN index,
no new runtime dependency. import numpy alone costs 180–390 ms
cold, which disqualifies it from a one-shot CLI query path; the BM25 prefilter is
what makes the stdlib version viable, since a full 50k brute-force scan is 1.5 s
in pure Python. Pool depth is justified by measurement: BM25 recall saturates at
0.890 by depth 200 and gains nothing at 400, so reranking the top-200 gives up
essentially nothing versus scanning everything.
Why this and not a shipped Voyage index. A precomputed Voyage index is
inert without a Voyage query vector, and the only keyless way to get one
is a maintainer-run anonymous embedding endpoint — an unauthenticated free
embeddings API backed by the maintainer's card, which also ships every user query
off-machine and breaks offline. A local model is deterministic, so the artifact
becomes a cache rather than a correctness dependency: a newly tapped
repo can be embedded on the user's own machine. Doc-side is the asymmetry worth
shipping for — 29 ms/doc in pure Python is ~24 min for 50k single-core, versus
seconds in CI with numpy.
Do not ship this before the eval and dedup items. The headline claim
(+11.0 recall / +15.9 hit@1) did not survive verification: its baseline
used the kind oracle the real search path lacks, and both the blend weight
(w_dense=0.7) and the pool depth were argmax'd on the same 82
queries they were reported on, by 2-query margins. On a binary metric at n=82
the smallest net win reaching p<0.05 is 6 queries; hit@1 (+13 net
queries) holds up, recall (+9) sits at the resolution floor. And the structural
risk is real: the name is only ~10.5% of a mean-pooled surface vector while 106
description clusters are shared across 270 distinct names, so the lift may
shrink toward 50k rather than hold. Sequence: fix the gate, dedup, fix
the index format, then re-measure with McNemar and a held-out blend weight,
leading with hit@1. Test entry-level dense alone before the
blend, ship 512-d not 256-d (the whole case for 256-d was one query), keep
Voyage/OpenAI as the opt-in ceiling, and keep BM25 as the floor. The model table
cannot go in the default wheel — the shipped runtime is 0.79 MB and every merge
to main cuts a release, so +17.4 MB × ~24 releases/day exhausts PyPI's 10 GB
project quota in under a month; it needs a separate, rarely-released data
package behind an extra.
Related, and partly overtaken: [[keyless-semantic-search-for-everyone]] shipped a keyless
path using a transformer (BGE via ONNX Runtime, in the [rag] extra) while this
item was open. That does not settle the question this card asks — a static lookup table is
still far cheaper, and this card's discipline about not shipping a retrieval claim before the eval
still stands. What it does change is the baseline: "keyless" is no longer the differentiator, so the
case for a static model now rests on cost (~1 ms and no runtime dependency, against a
measured 233 ms cold and 34 MB of wheels) rather than on availability. Status left alone
deliberately — this is another loop's item to own.
Unblocked, and the case for it got stronger. This card says “do not ship this before the
eval and dedup items”. Both have now landed: the eval gate floors four metrics over a
realistic-sized corpus with baselines keyed to their query set, and content-hash dedup has merged.
The new evidence is a timing measurement. Building the shipped ONNX keyless store over 743
entries (3,740 chunks, bge-small-en-v1.5 on CPU) took 4,431 s — 74 minutes,
about 1.2 s per chunk. This card's static-embedding proposal claims ~29 ms/doc in pure Python. If
that holds it is a difference of more than an order of magnitude on the doc side, which is exactly
the cost that makes prebuilt shards mandatory today. Worth measuring the model2vec path directly
before committing — but the gap it claims to close is now a measured number rather than an
estimate.
Spike done — the prerequisites this card set have all shipped, so the measurement it asked
for was finally runnable. It says “do not ship before the eval and dedup items”;
dedup landed in #370, the index format in #367/#371, the
published eval in #373. What follows is potion-retrieval-32M (MIT, 63,091
× 512 F32 lookup table — confirmed a single tensor, no transformer) driven by a
hand-written pure-stdlib loader: WordPiece → gather rows → mean-pool → L2, mmap'd,
no numpy.
The two unverified performance claims were not just right, they were conservative. Query
embedding measured 0.16 ms against the card's ~1 ms. Document
embedding measured 1.34 ms on a synthetic 105-token doc and 3.27 ms on 300
real catalogue entries (median 61 tokens), against the card's ~29 ms.
That reverses one of this card's design arguments. The doc-side cost was the reason prebuilt
artifacts looked mandatory: “29 ms/doc in pure Python is ~24 min for 50k
single-core”. At the measured 3.27 ms it is 2.7 min — roughly the time
a first boost tap --defaults already takes. Local embedding is therefore viable on the
user's own machine, and shipped shards become a genuine optimisation rather than a requirement. (Not
to be confused with the ONNX bge-small path measured at ~1.2 s/chunk in
keyless-semantic-search-for-everyone; that number stands, and the gap between them
is the case for the static model.)
But reranking bought nothing at real scale, which is the result that matters. Over the 50
natural-language golden queries against a real 71,655-entry catalogue, reranking BM25's
top-200 by cosine scored hit@1 2/50 — identical to BM25's own
2/50, a net change of +0 queries where this card's own statistics note says 6 net
queries is the smallest win reaching p<0.05. On two hand-checked pairs the ordering was right but
the margin was thin (related 0.154 vs unrelated 0.097).
Stated limits, because this does not settle the question. The document vector was built from
name + description truncated to 1,500 characters, not the full body the real dense path
indexes, so this measures a weaker representation than the one being proposed. No blend was tried
— pure rerank, no w_dense — and this card explicitly asks for a held-out
blend weight and McNemar. What it does establish is that the cheap version of the idea does
not pay for itself, so the remaining work is representation and blending, not inference speed.
An unrelated finding fell out of it, and it is the more important one. BM25 scored
hit@1 0.040 here against the 0.340 published in #373. Both
are correct: the published figure is measured over the pinned 6-tap eval corpus of 743
entries, and this run used a real 77-tap install — 96× larger. Golden targets are
all present and rank 7th, 8th, 38th, 163rd rather than 1st. The eval corpus is not a scale model of
a real install, and the gate's floors describe a catalogue two orders of magnitude smaller than the
one users have. Tracked separately in [[eval-corpus-is-96x-smaller-than-a-real-install]].
Declined on measurement, after a second model was tried specifically to avoid declining on one
data point. The card's premise is that a local static model buys keyless semantic
search. Tested against the 50 natural-language golden queries over the pinned 20-tap corpus (3,843
entries as those registries stand today), with BM25 at hit@1 0.260 as the
baseline in every run:
potion-retrieval-32M (retrieval-tuned, 63,091×512 F32) scored dense 0.220,
hybrid RRF 0.260. potion-code-16M-v2 (code-domain, 63,457×256 F16 —
chosen because this catalogue is coding-agent skills, which is the strongest hypothesis for
why a general retrieval model would underperform here) scored dense 0.240, hybrid
0.260. A third representation — name+description only, over the full 71,655-entry
catalogue — reranked BM25's top-200 to +0 net queries.
So: two models, three representations, no measurable gain, and fusion never beats BM25 alone.
The code model is one query better than the retrieval model, which at n=50 is inside the noise
(±0.02 per query) and should not be read as a trend.
The contrast is what makes this a decline rather than a shrug. The published eval measures a
real embedding model at hybrid 0.440 against BM25 0.340 — a genuine
+0.100. Static embeddings reproduce the cost profile that made the keyless tier attractive
(0.16 ms/query, 3.3 ms/doc, no dependency) but not the quality that made it worth
having. Cheap and no better than what ships today is not a tier; it is a second code path to
maintain for nothing.
What survives. The performance findings stand on their own and are already recorded above:
doc-side embedding is ~24× faster than the card assumed, which is why prebuilt shards are an
optimisation rather than a requirement for the real models in
[[keyless-semantic-search-for-everyone]]. The pure-stdlib loader (WordPiece → gather →
mean-pool → L2, mmap'd, F32 and F16) is proven workable if a future model justifies it.
What would reopen this. A static model that actually separates on this task — the bar
is beating 0.260 as a reranker, not merely producing plausible cosines. The two hand
pairs looked fine for both models (0.224 related vs -0.001 unrelated for the code model), which is
exactly why plausible similarity was not accepted as evidence.
boost chat — ask about skills in plain language, grounded in retrieval
One global concurrency group let any PR cancel any other PR's check
The fuzzer found a real crash and nobody was listening
The published metrics could never be published
A line-anchored suppression drifted, and make lint never ran the tool
Write-up · zizmor-ignores-drift-and-make-lint-never-ran-it.md
The sweep gate died at browser launch, not at a page
A cold search materialises 71,600 entries to print five
boost search brainstorm finds nothing, and brainstorming finds it
Reproducible release builds — the sdist half nobody's setuptools does for you
The weekly republish reached the machines that had never been set up
A query made only of characters tokenize drops returns zero results, and the documented catalog.search fallback is unreachable — boost search "C++" finds nothing on a machine holding …
Write-up · bm25-empty-tokenization-kills-catalog-fallback.md
boost search 'C++' returns zero and blames the catalogue: tokenize drops every 1-char token, and nothing ever says a term was discarded
Mutation shards re-run every mutant on every push of the same PR
The sweep gate died at a page, not at launch — and took six unrun checks with it
A new card filed as shipped always 404s its own write-up link
Write-up · a-new-shipped-card-always-404s-its-own-write-up-link.md
Codex is a skills and rules target but not yet an MCP host
The free-threaded canary is red for a missing setuptools, so it warns about nothing
One 30-line class makes registry.py unsplittable, and floors the mutation gate at 95% of its timeout no matter how many shards you add
Developer experience & maintainability
// planned · free tooling to catch issues earlier & keep the code legiblePromote nav / footer into the shared style system
Write-up · promote-nav-footer-into-the-shared-style-system.md
Shift-left gate — pre-commit + pre-commit.ci
Layering guard — import-linter
Typo detection — codespell
Docstring coverage — interrogate
Performance-regression gate — pytest-benchmark
Modernization smells — refurb + pyupgrade
Coverage dashboard — Codecov (free for OSS)
Pin the lint toolchain so a release can't redden the gate
Runner egress monitoring — StepSecurity Harden-Runner
Write-up · runner-egress-monitoring-stepsecurity-harden-run.md
Required-status-checks list is prose-only, and already stale
No issue/PR templates or a code of conduct
make boost mcp the whole setup, and put all three kinds behind it
New BDD suite has zero CI wiring
A project-scoped install registers its MCP servers machine-wide
boost bmad needed Node and a per-project install before it did anything
boost adapt — render a skill as another framework's agent source
boost adapt --to langgraph — third framework renderer
boost adapt — multi-agent skills → crews/graphs, not one Agent
boost run — search → adapt → a live agent doing the task, in one command
MCP — make agents search boost before reinventing a skill
boost install resolves a skill's requires: closure
MCP-aware skills — declare and wire an .mcp.json on install
roadmap.html goes stale on every rebase, so a card and a merge race redden the whole matrix
make lint reports success when actionlint fails — and says it wasn't installed
MCP — check for a skill when a task starts, not only when authoring one
The second silent skip — actionlint runs, and checks no run: block at all
boost chat cites its sources by a number it never prints
Write-up · chat-cites-sources-by-a-number-it-never-prints.md
MCP — one benefit, one observable trigger (and stop routing through boost_info)
MCP — answer the veto that overruled the trigger ("a skill already matched")
boost-first — the one rule boost authors, offered opt-in at boost mcp register
The MCP instructions understated what a search costs by 100x
install dead-ends on a registry that vendors its own skills
boost completions completes command names and nothing else
install refused an ambiguous name and offered no way to answer it
boost discover <query> asks GitHub, instead of filtering whatever boost index happened to sample
Share the catalogue instead of making everyone re-tap it
boost-first carried the trigger that had already fired and lost — and could never be updated
boost serve becomes a searchable, faceted catalogue with a graph of the taps
completions --install could delete the config between its own markers
browse could not search for two words, and the fix reshaped the whole browser
One design system across search and browse
The smart rerank pays the LLM again for a search it already answered
The box drew 108 columns into an 80-column pane, and --help never asked how wide the pane was
The hints still run past the pane, and the worst one is pinned by six test files
MCP has no way to read a skill before installing it
clean counts failed removals as cleaned, journals the inflated count, and exits 0
Write-up · audit-clean-counts-failed-removals-as-cleaned-journals-the-inflate.md
config/policy set store type-unchecked values; consumers crash exit 70 and pin_only no freezes installs
Write-up · audit-config-policy-set-store-type-unchecked-values-consumers-cras.md
Corrupt settings/config/state JSON silently read as empty, then clobbered on the next write
Write-up · audit-corrupt-settings-config-state-json-silently-read-as-empty-th.md
Five exit-70 crashes on bad paths/data: catalog --export, serve --port, count, replay, infer -o
Write-up · audit-five-exit-70-crashes-on-bad-paths-data-catalog-export-serve.md
distill's heuristic merge drops repeated ``` fences/braces, writing a structurally corrupt SKILL.md
Write-up · audit-distill-s-heuristic-merge-drops-repeated-fences-braces-writi.md
create/distill/infer/absorb --install silently replace an installed (unpinned) skill and flip its lock provenance to local
Write-up · audit-create-distill-infer-absorb-install-silently-replace-an-inst.md
hooks remove -n cannot find hooks boost itself added (unknown events skipped, embedded # boost: mangles the name)
Write-up · audit-hooks-remove-n-cannot-find-hooks-boost-itself-added-unknown.md
install --dry-run promises agents the real install never writes (antigravity-cli copy, antigravity materialize) and omits the MCP plan
Write-up · audit-install-dry-run-promises-agents-the-real-install-never-write.md
Rules/workflows reported as 'skills': uninstall claims a store dir that never existed
Write-up · audit-rules-workflows-reported-as-skills-uninstall-claims-a-store.md
install --local writes the repo's .mcp.json silently — the 'recorded N servers' report never runs
Write-up · audit-install-local-writes-empties-the-repo-s-mcp-json-silently-of.md
mcp register's boost-first consent names one file but writes every agent
Write-up · audit-mcp-register-s-boost-first-consent-names-only-the-registered.md
catalog.resolve_one's duplicate-name hint advertises --path to commands that reject it
Write-up · audit-catalog-resolve-one-s-duplicate-name-hint-advertises-path-to.md
adapt/run/stats/edit/tag/export reject the tap:name qualifier that info/install accept and adapt's own hint recommends
Write-up · audit-adapt-run-stats-edit-tag-export-reject-the-tap-name-qualifie.md
tap --dry-run is silently ignored outside --catalog: SPEC and --defaults clone for real
Write-up · audit-tap-dry-run-is-silently-ignored-outside-catalog-spec-and-def.md
out.warn defaults to stdout: infer/absorb corrupt > SKILL.md; search/explain/context warnings pollute piped stdout
Write-up · audit-out-warn-defaults-to-stdout-infer-absorb-corrupt-skill-md-se.md
AI degrade note blames PATH/API keys regardless of cause; several commands fall back with no note at all
Write-up · audit-ai-degrade-note-blames-path-api-keys-regardless-of-cause-sev.md
Declined confirms never name -y/BOOST_ASSUME_YES; snapshot, clean, infer/distill/absorb and sync reject --yes
Write-up · audit-declined-confirms-never-name-y-boost-assume-yes-snapshot-cle.md
Dry-runs disagree with the real run: compact, heal and onboard previews mispredict
Write-up · audit-dry-runs-disagree-with-the-real-run-compact-counts-bytes-it.md
Name slugging is inconsistent: distill -o accepts what import rejects; create/profile slug silently
Write-up · audit-skill-profile-name-slugging-is-inconsistent-distill-o-accept.md
git ops never set GIT_TERMINAL_PROMPT=0, so a 404/private repo prompts for credentials
Write-up · audit-git-operations-never-set-git-terminal-prompt-0-so-a-404-priv.md
cli.py COMMANDS summaries and parser help contradict behavior across ~11 commands
Write-up · audit-cli-py-commands-summaries-and-parser-help-contradict-behavio.md
info/stats/explain render a smaller shape for rules and workflows than for skills
Write-up · audit-info-stats-explain-render-a-different-smaller-shape-for-rule.md
taps/outdated/decay/policy/snapshot --json emit display strings as machine fields
Write-up · audit-taps-outdated-decay-policy-snapshot-json-emit-display-string.md
--json accepted but ignored: cohort/config/policy set, focus, profile, replay rollback, who empty state
Write-up · audit-json-accepted-but-ignored-on-many-branches-cohort-config-pol.md
Missing --json on doctor, test, health, changelog, trending, log, hooks list and friends; bundle install lacks --dry-run
Write-up · audit-missing-json-on-doctor-test-health-changelog-trending-log-ho.md
Name-miss errors: unknown tap qualifier never named, no close-match hint, tap tokens pollute suggestions
Write-up · audit-name-miss-errors-unknown-tap-qualifier-unnamed-no-close-matc.md
Six count flags (tap/chat/absorb/lint/changelog/hooks) accept 0 and negatives
Write-up · audit-six-count-flags-tap-chat-absorb-lint-changelog-hooks-skip-ut.md
Project scope seams: uninstall/verify/list/info disagreed with what install --local wrote
Write-up · audit-project-scope-seams-uninstall-verify-list-info-reinstall-dis.md
Project scope in an unmarked tree does not walk up, so src/ becomes its own project
Write-up · project-scope-in-an-unmarked-tree-does-not-walk-up.md
A rule or workflow installed --local into a since-deleted repo reads as missing, and every remedy recreates the repo
Write-up · rule-and-workflow-rows-carry-a-scope-nothing-but-list-local-reads.md
export -o, cohort create and profile save silently overwrite existing outputs and still say created/saved
Write-up · audit-export-o-cohort-create-and-profile-save-silently-overwrite-e.md
Stray positionals and inapplicable flags silently ignored across import, config, policy, trust, log, schedule, hooks, snapshot
Write-up · audit-stray-positionals-and-inapplicable-flags-silently-ignored-ac.md
out.table clips data columns to an assumed 80 columns when stdout is a pipe; narrow TTYs clip IDs/hashes
Write-up · audit-out-table-clips-data-columns-to-an-assumed-80-columns-when-s.md
output._wrap_tokens splits punctuation off backtick spans, inserting a stray space
Write-up · audit-output-wrap-tokens-splits-punctuation-off-backtick-spans-ins.md
Sweep: positionals/--json lack help strings and no command help shows examples (~30 cmds)
Write-up · audit-sweep-positionals-json-lack-help-strings-and-no-command-help.md
Singular/plural misses (“1 skills”, “1 issue need”, “1 skill pass”) across six commands
Write-up · audit-singular-plural-misses-1-skills-1-issue-need-1-skill-pass-ac.md
log/simulate/changelog headings echo the raw qualified argument, printing the tap twice
Write-up · audit-log-simulate-changelog-headings-echo-the-raw-qualified-argum.md
Stale prose after shipped changes: catalog --export, live discover, 464 count, Apache-2.0
Write-up · audit-stale-prose-after-shipped-changes-catalog-export-live-discov.md
boost ROOT: CLI audit findings (2026-08)
boost absorb: CLI audit findings (2026-08)
boost adapt: CLI audit findings (2026-08)
boost bmad: CLI audit findings (2026-08)
boost browse: CLI audit findings (2026-08)
boost bundle: CLI audit findings (2026-08)
boost catalog: CLI audit findings (2026-08)
boost changelog: CLI audit findings (2026-08)
boost chat: CLI audit findings (2026-08)
boost cohort: CLI audit findings (2026-08)
boost completions: CLI audit findings (2026-08)
boost config: CLI audit findings (2026-08)
boost context: CLI audit findings (2026-08)
boost deps: CLI audit findings (2026-08)
boost discover: CLI audit findings (2026-08)
boost edit: CLI audit findings (2026-08)
boost evolve: CLI audit findings (2026-08)
boost explain: CLI audit findings (2026-08)
boost export: CLI audit findings (2026-08)
boost import: CLI audit findings (2026-08)
boost index: CLI audit findings (2026-08)
boost install: CLI audit findings (2026-08)
boost log: CLI audit findings (2026-08)
boost mcp: CLI audit findings (2026-08)
boost onboard: CLI audit findings (2026-08)
boost outdated: CLI audit findings (2026-08)
boost preview: CLI audit findings (2026-08)
boost profile use: CLI audit findings (2026-08)
boost protocol: CLI audit findings (2026-08)
boost pulse: CLI audit findings (2026-08)
boost quickstart: CLI audit findings (2026-08)
boost recommend: CLI audit findings (2026-08)
boost replay: CLI audit findings (2026-08)
boost run: CLI audit findings (2026-08)
boost schedule: CLI audit findings (2026-08)
boost search: CLI audit findings (2026-08)
boost simulate: CLI audit findings (2026-08)
boost sync: CLI audit findings (2026-08)
boost tag: CLI audit findings (2026-08)
boost tap: CLI audit findings (2026-08)
boost taps: CLI audit findings (2026-08)
boost unpin: CLI audit findings (2026-08)
boost untap: CLI audit findings (2026-08)
boost update: CLI audit findings (2026-08)
boost who: CLI audit findings (2026-08)
August 2026 full-CLI audit: every one of the 81 boost commands exercised and verified
Per-item categories in search/browse/info — not just a ★ curated bool
The last command that blamed boost for the user's typo
One incidental keyword decides the boost bmad track
The BMAD router reads each prompt alone, so a pasted log, an “ok update both and rerun” and a yes/no question all get a banner
boost bmad gives every track the build contract, so a review is told to finish a change
bmad route never checks autopilot state, so any hook off missed keeps routing
The autopilot routes docs at a skill BMAD 6.12 no longer installs, and no test would notice
On Gemini, the bmad on briefing reaches the user and never the model
Persona descriptions say Use PROACTIVELY, so the router's silence governs only the banner
out.err() judges colour by stdout while writing to stderr
boost quickstart: a rerun could move already-tapped registries to their vectors
uninstall --local cannot remove a rule or workflow that list --local shows
Write-up · uninstall-local-cannot-remove-a-rule-or-workflow-list-local-shows.md
The agents line lists every recorded agent, including the ones boost no longer writes
Write-up · the-agents-line-lists-agents-an-item-does-not-reach.md
Docs-site & content quality
// planned · free tooling for the Pages site, README & proseMake the roadmaps discoverable
Lighthouse CI on the Pages site
Accessibility audit — pa11y-ci / axe-core
HTML validation — html-validate
Broken-link & anchor checking — lychee
The OpenSSF badge playbook
Prose & terminology linting — vale
Markdown consistency — markdownlint-cli2
Theme-asset linting — stylelint + eslint
Post-deploy smoke — headless load check
Command reference documentation site
Surface every docs/*.html page from the main page
The engine had no architecture diagram — and the one written rule was documented backwards
Fix overflowing node text in the RAG diagram (mcp-hub.html)
Docsite audit — stale counts, dev-noise footers, and a nav that breaks on mobile
A GIF carousel touring one flagship command per group
demo.yml has failed every run since it landed — vhs-action cannot install ffmpeg
No install doc ever said how to upgrade, so users guessed install --upgrade — which no-ops
Nothing tells a user semantic search is off — not the README, not search, not /mcp
roadmap.html grew 36% in one session and nothing bounds it
The Lighthouse budget passes on noise, not on margin
an explainer page for the LangChain / LangGraph / LangSmith integration
The performance gate was measuring a page nobody is served
Expanded card bodies overflow the roadmap board sideways
The performance gate flips on byte-identical input
Compatibility & install integrity
// planned · free tooling to prove boost installs & runs everywhere it claimsWindows in the CI matrix
Clean-env install smoke — pip & pipx
Lowest-version resolution — uv --resolution lowest-direct
Write-up · lowest-version-resolution-uv-resolution-lowest-d.md
Pre-release Python canary — 3.14t free-threaded
Startup & import-time budget — -X importtime
Package-metadata validation — twine check + friends
Write-up · package-metadata-validation-twine-check-friends.md
Hash-pinned, reproducible toolchain — requirements/*.txt
What Gemini actually receives from boost, audited
One command, every env — nox
boost hooks learns a second host — and finds two bugs upstream
Harden boost mcp launch against macOS Obj-C fork aborts
Self-harden every boost process against the macOS fork-safety abort
self-update is non-functional for pip/pipx installs
self-update said "already up to date" without asking PyPI
sync reported success for a link it had just refused
Two crashes that should have been messages
Order the server name before -e flags in `boost mcp register`
Gemini CLI as a first-class agent target (skills, rules, workflows, MCP)
production-ready LangChain / LangGraph / LangSmith integration
ship the LangChain integration inside the wheel, behind a [langchain] extra
sanitize agent frontmatter for Gemini instead of copying it verbatim
BoostRetriever advertised a source that does not open, and k=0 returned nothing forever
garrytan/gstack — tap it first, then learn to coexist with it
73 reads and writes left the text encoding to the locale, and the Windows jobs were the only thing that noticed
934 text writes leave the line ending to the platform, and five of them are bugs
Write-up · writers-whose-bytes-are-compared-do-not-pin-their-newline.md
Skill-content trust & safety
// planned · boost's core threat model — the third-party skills it installs run inside an agentPrompt-injection scanning of skill Markdown
Integrity verification — boost verify
The MCP boost_install tool skipped the injection scan the CLI runs
Crash reports carried API keys in cleartext
Tap signing & provenance — Sigstore / minisign
Runtime hallucination guardrail for boost explain
Typosquat & name-confusion detection
Update-diff before apply
Project scope — refuse to write through an escaping symlink
Secret & PII scanning of installed skills
Lockfile enforcement & commit pinning
Capability manifest & least-privilege policy
Write-up · capability-manifest-and-least-privilege-policy.md
install_from_path bypasses pin & policy checks
Write-up · install-from-path-bypasses-policy-and-pin-checks.md
Path traversal via unsanitized rule/workflow name
A CodeQL job rename silently blocked every merge
boost audit --skills — a trust/staleness report for installed skills
sbom.yml has never run — it waits for an event GITHUB_TOKEN cannot emit
The main ruleset is inert — its ref pattern is refs/heads/"main", quotes included
The release trigger was reachable from a fork — branches: filters head_branch, not the event
The code_scanning ruleset rule can go back on — but only scoped to CodeQL
The SBOM can declare a different version than the release it is attached to
rules and workflows install, then cannot be governed
boost serve echoed the request path back into its 404 body
denied_capabilities policy never applied to rule/workflow installs
trust verify labels a manifest tampered after signing by a TRUSTED key 'untrusted'; sweep exits 0
Write-up · audit-trust-verify-labels-a-manifest-tampered-after-signing-by-a-t.md
util.rmtree's retry hook chmods a symlink's target, outside the tree it is deleting
Write-up · util-rmtree-chmods-a-symlink-target-outside-the-tree.md
boost attest: CLI audit findings (2026-08)
boost trust: CLI audit findings (2026-08)
uninstall --local deletes any in-repo directory the committed lock names
Write-up · project-uninstall-deletes-any-in-repo-directory-the-lock-names.md
The add_many concurrency probe measured a race, not the pool
Write-up · concurrency-probe-measured-a-race-not-the-pool.md
install --local writes through a redirected dotdir that uninstall --local will not remove
Write-up · install-writes-through-a-redirected-dotdir-uninstall-will-not.md
The mutation shard planner is packing for a mutant set that is 14% smaller than the real one
Write-up · mutation-shard-balance-hints-are-a-release-behind.md
Eleven util.rmtree call sites guard with exists() or is_dir(), which a symlink satisfies
Write-up · is-dir-follows-a-symlink-at-eleven-rmtree-call-sites.md
The floors job builds its own venv and never put setuptools in it, so main went red on the weekly cron
test_canary_deps.py needs PyYAML, which the required tests job does not install — so it only runs inside the mutation gate
Mutation shard weights balance perfectly and predict nothing, so a shard can time out and cancel a release
A cancelled ci on main skips the release and alerts nobody, because the alert asks only about failure
Write-up · cancelled-ci-on-main-is-silent-and-skips-the-release.md
The shard model runs through the origin, so plan gets more optimistic with every shard added
AI-assisted commands reach the real config home from a sandboxed HOME
scopes.contains calls the same directory two different trees when only the case differs
Write-up · scopes-contains-is-case-sensitive-on-a-case-insensitive-disk.md
boost quarantine reports links removed that it could not see
Write-up · quarantine-reports-a-link-removed-that-it-could-not-see.md