WIP: public npx @bitrouter/agent — phases 0–4 of the self-serve plan - #7
Open
SPIKESPIGEL404 wants to merge 1 commit into
Open
WIP: public npx @bitrouter/agent — phases 0–4 of the self-serve plan#7SPIKESPIGEL404 wants to merge 1 commit into
npx @bitrouter/agent — phases 0–4 of the self-serve plan#7SPIKESPIGEL404 wants to merge 1 commit into
Conversation
Implements docs/plans/npx-self-serve.md. A stranger runs `npx @bitrouter/agent` in their repo and gets an audit that is true, advice matching the BitRouter release they actually have, and nothing of theirs modified. Phase 0 + CI — the package now runs. One bin, exact pi pin plus a shipped npm-shrinkwrap, a working exports map, ModelRuntime migration with an in-memory credential store (it writes ~/.pi/agent/auth.json otherwise), and a gate with a pack-smoke job that installs the tarball from a fresh resolution. Phase 1 — the wizard authors no routing config. Deleted buildYaml, the BARE_PROVIDER table, the emit_bitrouter_yaml and emit_optimized_yaml tools, writeYamlArtifact/writeOptimizedYamlArtifact and the `.proposed.` redirect. `bitrouter init` already writes a superset of any manifest we could produce, and a wizard-authored v2 lock would assert compiler-owned evidence with zero episodes. Deliverables are the audit and .bitrouter/analysis.json. `--target cloud` is gone; the endpoint resolves BITROUTER_BASE_URL -> `bitrouter status` -> loopback, with a one-token preflight because /v1/models is a listing, not a routability guarantee. yaml/validate.ts became a diagnostic over the user's own config, running `config validate` and `policy check` as a conjunction — a bad lock makes the former report only the filename while the latter gives line and column. Phase 2 — no unearned percentages. blendedReductionPct was an unweighted mean, over model-id strings found by a regex, of routineShare x (1 - altRate/curRate); routineShare also multiplied REAL METERED DOLLARS on the observed path and was extrapolated to a monthly $ headline. Both paths lose it in the same change. Replaced with a spend surface and honest unpriced-model rendering — BitRouter's registry is curated, not exhaustive, so gpt-4o-mini renders as unpriced-by-us rather than 0%. Where a number is wanted, cite BitRouter's own audited Terminal-Bench result. Phase 3 — nightly pi-bump, registry-refresh and bitrouter-compat jobs. The built providers.json includes BitRouter Cloud and eleven gateways; unfiltered, the cheapest-blended rule sends 22 of 57 model ids to `bitrouter`, which would quote Cloud's price as a self-hoster's price. sync-registry now filters on kind and status, and a gate enforces it. Phase 4 — smithers moves to packages/smithers as its own package. @smithers-orchestrator/agents and @ai-sdk/openai are removed outright: 350 -> 177 packages in a consumer install, and no binding.gyp at all. Review fixes: the audit now names any tier provider a stock `bitrouter init` config does not declare — `policy init` accepts an undeclared provider, both `config validate` and `policy check` pass, and the tier still never routes; OPENAI_BASE_URL carries the required /v1 suffix; the LLM path gets the same host-authored sections as the offline one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
SPIKESPIGEL404
marked this pull request as ready for review
August 19, 2026 12:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements
docs/plans/npx-self-serve.md. The goal: a stranger runsnpx @bitrouter/agentin their repo, having installed BitRouter themselves, and gets an audit that is true, advice matching the release they actually have, and nothing of theirs modified.What changed, by phase
Phase 0 + CI — the package did not run. Two differing
binkeys meant npm could not determine an executable; thebitrouterkey also shadowed the real router inside every npx run. Now one bin, an exact pi pin with a shippednpm-shrinkwrap.json, a working exports map, and theModelRuntimemigration with an in-memory credential store —ModelRuntime.create()writes~/.pi/agent/auth.jsonwithout one. The repo had no.github/at all; it now has agatematrix plus apack-smokejob that installs the tarball from a fresh resolution with no lockfile, which is the only thing that catches dependency drift.Phase 1 — the wizard authors no routing config.
bitrouter initalready writes a strict superset of any manifest we could produce, and under the v2 lock format a wizard-authored lock would assert compiler-owned evidence (owner,eligible_episodes) with zero episodes — fabricated provenance inside a system whose premise is auditable evidence. SobuildYaml, theBARE_PROVIDERtable, both emit tools, both yaml writers and the.proposed.redirect are deleted rather than fixed. Zero-write becomes true by construction.--target cloudis gone; the endpoint resolvesBITROUTER_BASE_URL→bitrouter status→ loopback, with a one-token preflight because/v1/modelsis a listing, not a routability guarantee.yaml/validate.tsbecame a diagnostic over the user's config, runningconfig validateandpolicy checkas a conjunction — a bad lock makes the first report onlyparsing policy lock <path>while the second gives line and column.Phase 2 — no unearned percentages.
blendedReductionPctwas an unweighted mean, over distinct model-id strings found by a regex, ofroutineShare × (1 − altRate/curRate): a model id appearing only in a__tests__file became a full-weight row whilegpt-4o-mini, the actual routine workhorse, was dropped from the denominator for being unpriced.routineSharealso multiplied real metered dollars on the observed path and was extrapolated to a monthly$headline, so both paths lose it in the same change — deleting only the cold headline would have leftDEFAULT_ROUTINE_SHARE = 0.3as the sole multiplier on the one number that prints in$. Replaced with a spend surface and honest unpriced rendering.Phase 3 — automation. Nightly
pi-bump,registry-refreshandbitrouter-compat.sync-registry.tsretargeted from a sibling checkout no npx user has to the publisheddist/registryURLs. The trap: the builtproviders.jsonincludes BitRouter Cloud and eleven gateways, and unfiltered the cheapest-blended rule sends 22 of 57 model ids tobitrouter— quoting Cloud's price as a self-hoster's price. Filtered onkindandstatus, with a gate that enforces it.Phase 4 — smithers leaves. Moved to
packages/smithers.@smithers-orchestrator/agentsand@ai-sdk/openairemoved outright, not relocated to peers: 350 → 177 packages in a consumer install, andfind node_modules -name binding.gypis empty.Review fixes (a fable-5 pass over the whole thing)
Three of these made the product wrong in a user's hands:
ci.ymlstill asserted the deleted./smithersexport resolves — the first post-merge run would have failed on its own pack-smoke job. Now asserts the inverse, plus no@smithers-orchestrator/@ai-sdkand nobinding.gypin a consumer tree.bitrouter policy initaccepts it,config validatereports valid,policy checkbinds the preset — and the tier never routes, because nothing backs it. Silent, and invisible to exactly the two commands the audit tells you to re-run. The audit now renders theproviders:stanza and says so. (Phase 3's snapshot refresh introduced this by excluding gateways, which moved the economy pick offopenrouter; Phase 1's proof predated it.)OPENAI_BASE_URL=http://localhost:4356404s — only/v1/*is served. Both reports emit the suffix now, andBITROUTER_BASE_URLis normalized.Also: README lede / CLI help / npm description still advertised the deleted policy generation;
diagnoseUserConfigwas wired to nothing; the LLM path skipped every host-authored section and still asked the model to use a rubric Phase 2 deleted;bitrouter-smithershad nobin. Plus hardening — 401/403 reported as an auth problem rather than "no routable model",--modelpreflighted, nightly fetches retried only on exit 2 so a real finding is never retried into silence.Verification
pnpm lint/typecheck/buildpnpm testpnpm test:e2epackages/smithersbinding.gypgit -C ~/Documents/Code/bitrouter status --porcelainZero-write proven by running the built CLI against a fixture already containing
bitrouter.yamlandpolicy-lock.yaml: both sha256 identical before and after,find -newershowing nothing written outside--out-dir. Every factual claim the audit makes about the router — the lock shape, the tool-safe clamp, the non-idempotence, the Terminal-Bench figures — was checked against realbitrouter 1.0.0-alpha.26and the checkout.Not done
create-pull-requestjobs need Settings → Actions → General → Allow GitHub Actions to create and approve pull requests, or their first run fails.src/pi/**has no real unit coverage, andsrc/commands/run-command.tshas none since its only test covered the deleted smithers branch.validate.test.tsskips its real-binary cases when no router is installed, so they will be permanently skipped in CI. Wants a step that installs BitRouter.guardrail_with_statusinpolicy_table_router.rsby line number against repo main; those numbers will rot.