Skip to content

bob CLI reference

Every bob command on one page. Each command is one row in scripts/bob/commands.json (#2044), and this page is generated from those rows, so it always matches what bin/bob runs and what bob --help prints. The same information is available as JSON from bob help --json (bob-help/1), and the terminal version of any entry is bob <noun> [<verb>] --help. For why BoB has a single bob command and how to add one, see The bob CLI.

Commands for a Claude session. Slash commands and skills are a second set of commands, run inside a Claude session rather than a shell. Slash commands and skills at the end of this page lists the pairs that do the same job and links the full catalogs.

bob with no arguments (or bob help) prints the few commands most sessions need, grouped by the situation that calls for them. bob help --all prints every command on one line each. The list is declared once, as everyday in the routing table.

$ bob
bob — the BoB CLI. The everyday commands:
Is everything OK? bob status every scope at a glance, and the one command to run next
bob doctor is this machine's BOB_HOME what was deployed?
Start work bob ready start or resume a project: converge it to warp-ready
bob preflight the warp-drive gate: doctor + ready --dry-run in one verdict
bob warp start launch a warp-drive run in tmux, after the preflight gate
Watch a run bob warp status the active run's phase, issue, chunk and metrics
bob warp viz the live session graph in the browser
Whole fleet bob viz every project on every fleet machine, in the browser
bob help --all every command, one line each
bob <noun> --help detail for one command: usage, flags, exit codes
A command failed? Search docs/how-to/troubleshooting.md for the message it printed.

Check this machine, catch up, and find out what needs you.

Command What it does
bob doctor Assert this machine’s BOB_HOME is what deploy.sh produced from the commit it records, across every synced surface, every symlink, the toolchain and the settings.json hook wiring; … →
bob status The front door: with no arguments, one line per scope — host, the project you are in, the fleet — from cached verdicts with no network, the warp run going here, and ONE next: … →
bob asks Every open ask of the operator across the portfolio, in one list (#3801, cap #3800): one line per open todo without completed and per open brief in brief:new or brief:acting, … →
bob brief One portfolio briefing as briefing/1 (#2243, cap #2224): Needs you / Done / Doing / Will do across every project since the previous briefing, assembled from source data with links … →
bob tour What is provisioned here but never invoked, from session-ledger evidence: each item with one line on when to reach for it and the command to try, graded unknown / parked / in-use … →
bob u Bob University (BobU) from a shell — a thin router over the disposition record (#2901), applicability and fleet usage (#2900, #2899) and the eval suites (#2390): status counts … →
bob notify Send a Telegram message over the remote-decision bridge from a shell: reads BRIDGE_WORKER_URL/BRIDGE_SECRET from the environment, the project’s .mcp.json, or $BOB_HOME/.mcp.json, … →
bob viz Open bob viz — every project on every fleet machine as small multiples, from the fleet feed (/bob on the dashboard server, same freshness and self-update path as bob warp viz); … →
bob control Open BoB Control (#3813, cap #3812): /control on the dashboard server, one frame whose navigation is Now, Projects, Fleet and Costs (#3914, #4034), then the crumbs of where you … →

Bring a repo under BoB and keep its tooling converged.

Command What it does
bob init Initialize a project with BoB tooling: the .claude/ directory, universal symlinks into BOB_HOME, and — when no manifest exists — an offer of one-shot auto-provisioning (bob … →
bob ready The one command for starting or resuming a project: takes a new or existing directory, or an owner/repo it clones, to warp-ready and visible on bob viz — idempotent, no prompts, … →
bob preflight The warp-drive preflight gate: doctor + ready --dry-run as one verdict. →
bob provision Provision a project from its manifest — status / diff / check / refresh / prune / init / interview / detect / add / remove / decline / reconcile / overlay / untrack / ignore-paths … →
bob link Link a global item (command, agent, hook) into the current project’s .claude/, link every missing one, or list what is available. →
bob promote Promote a local .claude/ item (command, agent, hook, skill) to the global source and replace the local file with a symlink back. →
bob promotion setup Scaffold a project’s dev → test → prod promotion ladder — detect → dev.json → wrangler → provision handoff → todo → verify; dry run by default, –apply writes (#931). →
bob deploy Deploy this project to its test or prod environment through scripts/deploy/deploy.sh — the resolved adapter’s check → build → migrate → deploy → verify contract — with a D1 backup … →
bob backup setup Render a project’s backup Worker from its dev.json environments.<env>.backup block (#3084, cap #3067): the Worker and its scheduled Workflow (templates/backup-worker/) written to … →
bob backup status How old a project’s newest D1 backup is (#3085, cap #3067): per env whose dev.json declares environments.<env>.backup, the newest dump the backup Worker wrote (read from its … →
bob backup run Take a D1 backup now (#3085, cap #3067): trigger the project’s backup Workflow — the one its nightly cron starts — through wrangler workflows trigger, then wait until the … →
bob backup restore Load a backup into the restore-target env’s D1 and verify it (#3085, cap #3067): the newest dump (or –from <key>) fetched from the backup bucket, the target’s existing tables and … →

Groom the queue, freeze a flight plan, launch and steer autonomous runs.

Command What it does
bob groom Run the /groom pass headless from a shell: claude -p over the inlined /groom command text and scope — an explicit DRY-RUN by default, –apply at automation Level 3 … →
bob decompose Decompose an approved capability or use case into filed child requirements through six evidence-gated phases on the shared machine engine (#2975): sourcing (cap-status) → drafting … →
bob do Run an hour of unstructured work as a state machine on the shared engine (#2975): framing (a one-line question and an artifact from the closed set decision · lesson · doc · spike … →
bob plan build Derive a flight plan once and write/refresh its issue — flightplan.js build –no-interview with the mapped scope flags; prints the plan number. →
bob plan remaining Runnable plan items in run order — flightplan.js remaining <N>, argv passed through unchanged. →
bob plan status Plan progress — runnable vs gated vs withheld vs moot vs waiting, todo gate states, gate mode, integration branch, lifecycle — flightplan.js status <N>, argv passed through … →
bob plan items The plan’s ordered items, todo rows marked — flightplan.js items <N>, argv passed through unchanged. →
bob warp start Launch a warp-drive run in a named tmux session from any shell: bob preflight first (exit 1 with the verdict when it fails; on the BoB source checkout a failure that is only this … →
bob warp attach Attach to the project’s live warp-drive run and follow it across segments: one name per run, no warp-seg-N to know. →
bob warp status Show the active warp-drive phase, issue, chunk and metrics; –watch redraws in place, –log appends the phase history. →
bob warp log The warp-drive phase-transition history for this project. →
bob warp config Show the resolved workflow configuration (_workflow keys, kickoff options) for this project. →
bob warp viz Open the live session graph in the browser (#1552); –tailnet serves it on this machine’s Tailscale address, the default where machines.json declares dashboard.bind: tailnet … →
bob warp stop Abort the active warp-drive session — graceful (transitions to aborted) or –hard (deletes the state file, no cleanup). →
bob warp reap GC leaked warp-seg-* tmux sessions and orphaned REPLs, and find Claude Code in every other tmux session graded stale or live by idle time (#3302) — dry run by default, –force … →
bob warp session The integration-branch session: start <branch> [–area <slug>|–flightplan <N>] creates + checks out a scope-bound session branch (#1177), end clears it, status shows the resolved … →
bob warp finalize Ship the integration branch to main — one PR at Level 2, rebase + merge at Level 3 (#268). →
bob fork Fan out parallel warp-drive sessions into isolated git worktrees + tmux windows: fork <branch...> | fork –from-issues [N] | fork –from-flightplan <N> | status | drop | watch | … →
bob pair The cross-repo, contract-driven shape of fork: paired worktrees in a backend and a frontend repo on one shared branch (the standalone form of bob fork pair). →
bob swarm Run the full agent-swarm loop as one command — decompose → approve → capped dispatch via bob fork → gate → integrate → summary (#582). →

Bring the app up, clean residue, and serve the project dashboard.

Command What it does
bob dev up Bring the dev environment to a fully testable state from dev.json: start the server, migrate, seed, provision test users, health-check, report the URL. →
bob dev health Quick health check of the dev environment — the shortcut for dev up --check. →
bob reap Reap regenerable working-tree residue per the project’s reap.json — dry run by default, –apply deletes; keep-list and liveness guards (#1664). →
bob dash status The tooling dashboard: global items and every registered project’s symlink status, port band, warp-drive harness defects, and last bob ready verdict. →
bob dash generate Generate a project’s static dashboard (bugs, releases, changes, incidents, journal, cross-refs) into .dash/ from the current directory. →
bob dash serve Start the dashboard server for the current project on its ledger-assigned port, or list / stop running dashboards and show port allocations. →
bob serve Converge this machine’s declared tailscale serve front door (#2407): one MagicDNS address, no port, with /bob and every declared project’s /<project>/warp path-routed to its … →

Ship BoB, move a machine to a release, and run the unattended cycle.

Command What it does
bob release The BoB release engine from a shell: a stable release (bump + CHANGELOG + vX.Y.Z tag + GitHub Release), a nightly tag on a green, moved HEAD (#2045), or promote — stable from the … →
bob update Converge this machine to a release channel or tag: fetch, fast-forward the BOB_SOURCE checkout to the newest stable/nightly tag (or –to), run deploy.sh, then doctor — refusing a … →
bob tick One unattended maintenance cycle under a lock: bob groom –all –apply → bob plan build –from farm → the host converged on BOB_SOURCE when it is behind source and safe to deploy … →
bob wiki maintain Consolidate one project’s traces into the skill-evolution wiki (#2389, part of #2387): a scrubbed, bounded packet of everything new since the watermark — loop notes, the decision … →
bob wiki propose Propose one change to one skill, command or agent from the skill-evolution wiki (#2391, part of #2387): the item named, or with –auto the one with the most new wiki evidence … →
bob eval run Run one item’s eval suite (#2390, part of #2387): evals/<item>/ in BOB_SOURCE through claude plugin eval with a with/without ablation, from the current directory, under a … →
bob eval gate The acceptance rule for a skill change (#2390): pass only when a skill-eval/1 result’s with score is strictly higher than the best recorded for the same model in … →
bob mirror Reconcile and publish to each repo’s declared second git host (mirrors.json): resolve / reconcile / publish / verify / status — dry run without –apply (#1747). →
bob forge health Forge availability classified from real gh call outcomes — operational / degraded / unreachable / unknown; the exit code is the answer (#1748). →
bob forge queue The durable write-ahead queue of issue mutations the forge could not take — status / list / show / resolve / drop / replay / clear; replay is dry-run by default, –apply delivers … →
bob site publish Publish one site-publish/1 bundle to the operator’s site — the one publisher to it (#3103, decision on #3098): a producer (bob brief, release notes) hands over a section path and … →

Your operator repo — identity, fleet, manifests — the secrets it declares, the phone terminal kit, this machine’s model-route key, the model roles that fail over across routes, and this machine’s Cloudflare token.

Command What it does
bob operator show Print the resolved operator profile and which rung found it — $BOB_OPERATOR → the $BOB_HOME/.bob-operator pointer → ~/projects/bob-operator — after validating operator.json … →
bob operator init Scaffold an operator repo from templates/operator/ — operator.json, machines.json, provisions/, README, .gitignore and the validate workflow that runs BoB’s validators — git-init … →
bob operator migrate Move the operator data out of the BoB source checkout into the resolved operator repo WITH HISTORY — machines.json, mirrors.json, config/cloudflare-accounts.json, … →
bob secrets check Verify every secret the operator profile declares is PRESENT on this machine and name its source — env / file / keychain / gh-secret / op probed for existence and metadata only, … →
bob ibob check Grade the iBoB terminal kit read-only (#2291, cap #2289): the declared phone setup in the operator repo’s config/ibob-kit.json — schema, every target a machines.json id, every … →
bob ibob attach List the live warp and cdfork tmux sessions on one fleet machine and print, for each, the exact command to type in the phone client (mosh or ssh, from the kit’s declared client) … →
bob route status What this machine’s model-route working key has used against its limit (#3590, cap #3866): one request to the route for the key’s own state — its label, usage, limit and what is … →
bob route mint Create this machine’s model-route working key with the management key (#3590): named bob-<machine id>, limited to the monthly amount the machine’s machines.json entry declares … →
bob route roles Every model role BoB declares (#1231, cap #3866) — default, reasoning, fast, cheap — with the Claude Code alias agents name for it and its candidates in the order they are tried, … →
bob route run Run a headless command on a model role with failover (#1231, cap #3866): start it on the role’s first candidate in play; when it exits non-zero and its output shows a Claude API … →
bob route failovers The newest model failovers on this machine (#1231): when, which role, the candidate that failed and why (its class and the matched text), what it fell back to, and the project — … →
bob cloudflare verify Check this machine’s Cloudflare working token (#3583, cap #3581): the project’s account — its manifest _meta.cloudflare_account, else the operator’s default_account in … →
bob cloudflare mint Create this machine’s Cloudflare working token with the operator’s root token (#3583): named bob-<machine id>, scoped to the account and all its zones, holding every permission … →

Agent hours and list-price COGS per project — this machine, and the fleet from its snapshots.

Command What it does
bob labor report Agent active-hours from the Claude Code transcripts on this machine, one clock per project (#4420, cap #3135): every session transcript under ~/.claude/projects/<slug>/ (a Task … →
bob labor reconcile Every transcript on this machine has one priced record in the token ledger (#4421, cap #3135): each session transcript under ~/.claude/projects/<slug>/ written since the window … →

Scheduled reviews: what is due, open, prepare, hold, close, decide.

Command What it does
bob ritual due Which rituals are overdue, due or upcoming per project — the declared _meta.rituals schedule or liveness-scaled defaults, last run derived from closed ritual-run issues (#2230, … →
bob ritual run Start the attended session of a ritual: resume its open run issue or open one, refuse a kit the machine role forbids (#2228), apply the ritual kit to the project checkout as a … →
bob ritual open File one ritual-run issue with the standard body (marker, scope, kit, the declared checklist embedded as tickable items at its version (#2241), evidence placeholder, findings … →
bob ritual prepare Gather a run evidence packet report-only and post (or replace) it as one comment on the run issue; –due prepares every farm-eligible ritual due soon, what bob tick runs (#2233). →
bob ritual close Close a held ritual run with durable outputs: every finding links a bug, req, task, security or todo issue or says no-action (an empty run needs –no-findings, recorded), lessons … →
bob ritual decide Write a portfolio-review decision into a project manifest: _meta.portfolio invest / maintain / park / archive, the dormant default cadence for a parked or archived project (and … →
bob ritual sweep The portfolio sweep (#3609): inventory every directory under ~/projects and ~/Sites on every fleet machine — this one directly, the others over Tailscale SSH, nested repos … →

Every command below lists its usage, each of its flags, its exit codes, the engine that runs it, the issue that introduced it, the release it first shipped in (Since), and the page to read next.

Assert this machine’s BOB_HOME is what deploy.sh produced from the commit it records, across every synced surface, every symlink, the toolchain and the settings.json hook wiring; how far BOB_SOURCE has moved since the deploy is reported, never drift (#3160). The source is resolved through the #1220 chain (scripts/lib/bob-source-resolve.js: $BOB_SOURCE → the engine’s own checkout → ~/projects/bigbrain → BOB_HOME, flagged), never the engine’s own directory; on the BOB_HOME fallback the surfaces, settings_hooks and contract lines report not-measured under unmeasured, never PASS (#2315). Its dashboards INFO section ends each running server’s line with its /warp URL and closes with the machine’s /bob fleet URL (#2639).

bob doctor [--json] [--project <dir>] [--section <surfaces|symlinks|toolchain|settings_hooks>[,...]]
Flag Meaning
--json machine-readable verdict (schema bob-host-drift/1)
--project <dir> also grade that project’s .claude/ links — reported as its own section, never folded into the machine verdict (#1953)
--section <a,b> grade only the named sections: surfaces, symlinks, toolchain, settings_hooks
Exit Meaning
0 converged
1 drift — the output names the remediation
2 error

Engine: node scripts/checks/host-drift.js · Issue: #1921 · Since: v1.272.0 · Read next: Troubleshooting

The front door: with no arguments, one line per scope — host, the project you are in, the fleet — from cached verdicts with no network, the warp run going here, and ONE next: command; with –scope, one health verdict for host (≡ doctor), project (≡ ready –dry-run) or fleet (the audit view; bob dash status’s views as flags) — as one bob-status/1 document. Each section embeds its engine’s own v1 document unchanged.

bob status [--json] [--live] | bob status --scope host|project|fleet [--json] [scope flags]
Flag Meaning
--scope <host|project|fleet> what to grade; omit it for the front door (every scope, one next: command)
--live front door only: re-grade the project (ready –dry-run) and pull the fleet live instead of reading recorded verdicts
--json machine-readable verdict (schema bob-status/1)
--project <dir> host: also grade that project’s .claude/ links; project: the project to grade (or pass it positionally)
--section <a,b> host only: grade only the named bob doctor sections
--reconcile-preview project only: add rebob –report as an informational section
--no-live fleet only: read cached snapshots; build nothing, pull nothing
--<cdb-view> fleet only: –projects-only, –global-only, –matrix, –ports or –check <project> renders that bob dash status view unchanged (human output; no –json)
Exit Meaning
0 ok
1 drift — host drift, NOT READY, or an unreachable/stale fleet machine
2 error or usage error

Engine: node scripts/status/status.js · Issue: #2080 · Since: v1.274.0 · Read next: bob status

Every open ask of the operator across the portfolio, in one list (#3801, cap #3800): one line per open todo without completed and per open brief in brief:new or brief:acting, across every registered, active project, with its project, priority, age in days and link. Each ask says what it unblocks (#3915): an item of a flight plan with a live run (running), of an open plan with no run (ready), an approved issue on no plan (approved), nothing (none), or unknown when the forge could not say; the asks are listed most-blocking first — by that tier, then the items gated, then priority, then oldest first — and a line whose ask holds work up ends with one sentence saying what. The lines are grouped into sittings (#3806), one per place, each headed with its place and total minutes, decisions before commands before checks, the sitting holding the first-listed ask first; an ask that states no minutes or place is listed in a last group, not yet estimated. The attention budget (#3805) caps the list: at most _workflow.ask_budget asks per project and _workflow.ask_budget_portfolio across all of them are shown, and the line under them says how many more are waiting behind the budget. bob asks recheck (#3808) lists every to-do untouched for longer than _workflow.ask_recheck_days with a verdict: moot when every issue it names is closed, else still needed; recheck –apply closes a moot to-do without completed and records the re-check on the rest. bob asks sources (#3810) reports, per filing path named by each to-do’s ask:source marker, the to-dos filed in the last 90 days (–days): filed, done, closed without completed, open and the median days to done, and marks each source whose share closed without completed exceeds _workflow.ask_moot_threshold; sources –file-bugs –apply files one deduplicated bug per marked source in the BoB tracker, naming its counts; –json prints one bob-asks-sources/1 document. bob asks draft / transition / status (#3811) run one ask through the declared lifecycle machine (scripts/asks/machine.json, on the shared machine engine #2975): drafted, admitted, queued, presented, done, declined, snoozed, consumed, one state file per ask under .claude/asks/ in the checkout; an event is named for the phase it reaches, admitted runs the admission gate (#3803) and a refused draft stays at drafted with the refusal recorded, an invalid transition changes nothing, done on a to-do adds completed to its issue before the phase moves, consumed is fired only by todo-consume.js once it has unblocked the issues the to-do named, and an issue-number id with no record is adopted at the phase its labels say; the brief states in scripts/brief/states.json map onto the same phases; –json prints one bob-ask/1 document. A project whose forge read fails is named as a gap with the forge state, never a silently shorter list; –json prints one bob-asks/1 document with the same rows and a count per project. bob asks done <owner/repo#N> (#3807) answers one ask from a shell as the asks page does through the brief-tick Worker: completed on a to-do, brief:done on a brief, anything else refused (exit 1); bob asks snooze <owner/repo#N> –until <date> writes one ask:snooze-until marker into the issue body, and an ask snoozed past today is not listed — –json names it under snoozed; both print one bob-ask-answer/1 document with –json and write nothing when the ask is already so. A to-do that declares a Done-check (#3986) is tested before it is listed: a pass adds completed and closes it with the evidence, so it is never shown, and a failure with a new reason is written into its body; –json counts them under done_checks. bob asks verify runs every open to-do’s done-check, report only without –apply; –apply closes the passing ones, records each new failure reason and re-runs a failed CI run once (what bob tick runs), and –json prints one bob-asks-verify/1 document. A projection: the issues stay the store, the only writes are the ask-waiting label under –reconcile –apply, the two answers and the done-check’s, and a todo carrying completed, a closed issue, or a brief in brief:done or brief:parked is never listed.

bob asks [--json] [--all] [--reconcile [--apply]] | bob asks recheck [--json] [--apply] | bob asks sources [--days <n>] [--json] [--file-bugs [--apply]] | bob asks draft <id> --body-file <path> [--title <t>] [--kind todo|brief] [--label <a,b>] [--repo <owner/repo>] [--source <name>] | bob asks transition <id> <event> [--number <n>] | bob asks status <id> [--cwd <dir>] [--json] | bob asks done <owner/repo#N> [--json] | bob asks snooze <owner/repo#N> --until <YYYY-MM-DD> [--json] | bob asks verify [--apply] [--json]
Flag Meaning
--json one bob-asks/1 document on stdout: verdict, count (asks inside the budget), open (every open ask), by_project {name: open count}, asks [{kind, project, repo, number, title, priority, state, created_at, age_days, ask_kind, minutes, place, url, unblocks {tier, items, plan, summary, reason}}], sittings [{place, minutes, asks}] (one per place, #3806), unestimated (the asks that state no minutes or place), waiting (the same rows, for the asks behind the budget), budget {portfolio, per_project, waiting}, projects {total, read, gaps [{project, repo, state, reason}], not_here}, error
--all also list the asks waiting behind the budget, under the ones inside it
--reconcile make the ask-waiting label match the budget: report each ask beyond the budget that lacks it and each ask inside that carries it (the document gains reconcile {applied, held, released, swept})
--apply with –reconcile: add or remove the label, one gh issue edit per ask, and sweep the handoff of each released to-do so its push is sent. With recheck: close each moot to-do without completed, with a comment naming the closed issues that made it moot, and put one comment recording the re-check date on each to-do still needed. With sources –file-bugs: file the bug of each source above the moot threshold that has no open bug yet
Exit Meaning
0 listed — a project that could not be read is named as a gap
1 transition: the event is not one the ask’s phase allows, or draft: the ask already exists — nothing changed
2 usage error, no readable projects.json, or (transition, status) no such ask
3 no project could be read — every forge read failed; transition admitted: refused by the admission gate, the phase did not move
4 transition: the forge did not take the completed label, or the issue to adopt could not be read — the phase did not move

Engine: node scripts/asks/asks.js · Issue: #3801 · Since: v1.279.0 · Read next: See everything waiting on you

One portfolio briefing as briefing/1 (#2243, cap #2224): Needs you / Done / Doing / Will do across every project since the previous briefing, assembled from source data with links — gh (merged PRs, closed reqs and bugs, open todos, PRs awaiting review, releases, open flight plans), fleet snapshots (active warp sessions per machine, blocked runs, harness defects), this machine’s warp state and tick digests, rituals due (#2222) and rotations due (#2223). A source that cannot be read is one named gaps[] entry; the briefing is never failed for one source. The page (#2244) and the Telegram message (#2245) are views over this document: –write stores it as <generated_at>.json where /briefings lists it, –send stores it and posts a headline of at most 5 lines — the needs-you count, the done / doing / will-do counts, the top needs-you item and the tailnet link to the stored briefing — through bob notify, exiting by bob notify’s contract (0 delivered · 3 no bridge, the message printed · 4 transport); a quiet briefing is one line, or nothing under –on-quiet skip.

bob brief [--install-timer|--uninstall-timer|--timer-status [--machine <id>] [--dry-run]] [--json] [--write] [--send] [--scheduled] [--area <area:label>|all [--apply]] [--project <name>|all [--apply]] [--reconcile [--apply]] [--retain-days <N>] [--url <http://host:port>] [--on-quiet message|skip] [--since <ISO>] [--now <ISO>] [--offline] [--snapshots <dir>] [--ticks <dir>] [--briefings <dir>]
Flag Meaning
--area <area:label>|all one page per area label, rendered to the operator repo’s www/bob/briefings/area-<slug>.html — a view, not a brief; a brief issue is filed only when the area carries a decision (an open needs-clarification or blocked item, an open todo without completed, an untyped open issue, or a cap with no approved requirement past the staleness window), its Next action list naming exactly those items; an open area brief whose area no longer carries a decision is reported for –reconcile, never closed; one line and a URL per area; report-only without –apply; with –scheduled it writes inside the declared hours (#2820, #3101)
--project <name>|all one brief per registered project (projects.json, resolved to its GitHub origin), filed as a brief issue in that project’s own repo on the area-brief model, with its page at the operator repo’s www/bob/briefings/project-<name>.html; all walks every project, an unknown name exits 2 listing the known ones, a project with nothing new in the window is reported quiet; report-only without –apply; with –scheduled it runs after the portfolio briefing is delivered (#3040)
--reconcile tick every brief’s Next action whose named issues (#NN, owner/repo#NN, issue/PR URLs) have all closed — a todo only with completed; an action naming no issue is reported as needs judgment, never ticked; one line per open brief across the portfolio, report-only without –apply; –apply writes each body with –body-file, comments the evidence, moves the state label through states.json (all resolved → brief:done and closed) and, when a brief changed, rebuilds and publishes the index; a forge that answers nothing is reconcile: skipped (forge <state>), exit 3, nothing written; –json emits brief-reconcile/1 (#3100)
--apply with –area: write each area’s page and file or update its brief issue only for a decision; with –project: file or update each project’s brief issue and write its page; with –reconcile: tick resolved actions, move state labels, close finished briefs, rebuild and publish the index
--install-timer render bob-brief.service + bob-brief.timer from this machine’s machines.json bob_workload.brief into ~/.config/systemd/user and enable the timer — it runs bob brief –send –scheduled on the declared cadence (Linux only; idempotent; with –dry-run writes nothing, #2246)
--uninstall-timer disable the briefing timer and remove both units (#2246)
--timer-status the briefing timer declared vs installed: each unit absent / current / differs, the timer state and lingering (#2246)
--machine <id> with a timer flag: the machines.json entry (default: the host it resolves)
--dry-run with –install-timer / –uninstall-timer: report what would be written and run; write and run nothing
--json the briefing/1 document on stdout (schemas/briefing.schema.json); the human rendering otherwise
--write store the document in the briefings directory as <generated_at>.json (2026-09-16T06-00-00Z.json) — what /briefings lists and the next briefing’s window starts from (#2245)
--send store it (implies –write), then post the headline — at most 5 lines: needs-you count, done / doing / will-do counts, the top needs-you item and its link, the page link — through bob notify at level warn when something needs you, else info; the exit code is bob notify’s (#2245)
--scheduled a scheduled briefing (the bob-brief timer, the end of bob tick, #2246): inside this machine’s declared machines.json bob_workload.brief.quiet_hours nothing is made or stored and the exit is 0; an invalid declaration is exit 2; with –area it is the area pass, writing as –apply does (#3101)
--retain-days <N> after a write, prune stored briefing/1 documents older than N days — never the newest, never a file that is not a briefing; default the declared bob_workload.brief.retention_days (90 when a brief block omits it), none when undeclared (#2246)
--url <http://host:port> the Project Monitor base the page link uses instead of this machine’s tailnet address and the project’s ledger dashboard port
--on-quiet message|skip what a quiet briefing (nothing needs you, nothing done in the window) sends: one line (default, or BOB_BRIEF_ON_QUIET) or nothing
--since <ISO> the window start for Done — wins over the previous briefing; default: the newest briefing/1 under $BOB_HOME/briefings/, else 24 h back
--now <ISO> the clock the window and every date comparison use (tests, replays)
--offline read local files only — every gh source, rituals and rotations become offline gaps
--snapshots <dir> the fleet snapshot directory (default $BOB_FLEET_SNAPSHOTS, else $BOB_HOME/fleet/snapshots)
--ticks <dir> this machine’s tick digests (default $BOB_HOME/fleet/ticks)
--briefings <dir> where previous briefings are read from and stored (default $BOB_BRIEFINGS, else the declared bob_workload.brief.dir, else $BOB_HOME/briefings)
Exit Meaning
0 built — every source read in full; with –send: delivered (or quiet and skipped)
2 usage error
3 built — at least one source is a gaps[] entry (the document is still complete); with –send: no bridge configured — the message is printed instead (bob notify’s contract)
4 with –send only: transport error — curl failed or the bridge answered non-2xx (bob notify’s contract)

Engine: node scripts/brief/brief.js · Issue: #2243 · Since: v1.274.0 · Read next: Get your briefing

What is provisioned here but never invoked, from session-ledger evidence: each item with one line on when to reach for it and the command to try, graded unknown / parked / in-use — never useless. Backfills the ledger from transcripts when it is empty; carries the 2026-09-10 review’s unknown bucket as its seed; –tried / –park record the owner’s choice in .claude/.tour.json.

bob tour [--project <dir>] [--days N | --fleet [--min-events N]] [--all] [--no-backfill] [--json] | bob tour --tried <item> | bob tour --park <item> | bob tour --applicability [--no-infer] [--bucket <name>] [--json]
Flag Meaning
--project <dir> the project to tour — its nearest .git/.claude ancestor (default: the current directory)
--days <N> count only ledger events from the last N days (default: all time)
--all also list the in-use items (by default only unknown and parked are listed; the counts always cover all three)
--fleet grade from fleet-wide usage — every project on every fleet machine, from the snapshots, this machine’s rebuilt live (#2899); each grade rests on a stated evidence base, and no use on a base below the minimum or with a machine missing reads insufficient-evidence; all time, so not with –days
--min-events <N> with –fleet: the fewest fleet events a base needs before an unused item may read unknown or parked (default 200)
--no-backfill do not mine transcripts into an empty ledger first (the backfill never runs on a ledger that has events)
--tried <item> record that you tried <item> today — it grades in-use; clears a park
--park <item> record that you chose not to use <item>, dated today — it grades parked; clears a try
--applicability grade every registry item by applicability before usage (#2900): not-applicable-anywhere / applicable-unused / applicable-used / unscoped, from applies_to against each portfolio project’s declared or inferred stack and type, then fleet usage; missing or implausible metadata is flagged for a fix, not graded; –json emits one bob-applicability/1 document (docs/reference/applicability.md)
--no-infer with –applicability: use declared profiles only — never run infer-profile.js on a project checkout
--bucket <name> with –applicability: list one bucket only (the counts stay whole)
--json one bob-tour/1 document on stdout: project, days, state_file, seeded_from, ledger {events, backfill}, counts {unknown, parked, in_use}, items [{name, type, grade, when, try, evidence}], action, error
Exit Meaning
0 tour rendered, or the choice recorded
2 usage error, an item neither provisioned here nor in the seed, or an unreadable .claude/.tour.json

Engine: node scripts/tour/tour.js · Issue: #2075 · Since: v1.274.0 · Read next: Tour what is provisioned

Bob University (BobU) from a shell — a thin router over the disposition record (#2901), applicability and fleet usage (#2900, #2899) and the eval suites (#2390): status counts each disposition, lists every undisposed item with its applicability bucket and usage, and names the certifications due for re-examination; exam runs an item’s suite under the project’s kit overlay and prints the disposition the result supports; dispose builds the item’s record from that evidence, checks it against the record’s gate, and writes it only under –apply — retire also drafts the retired-items.json entry.

bob u status [--no-infer] [--json] | bob u exam <item> [--model M] [--runs N] [--kit K | --no-overlay] [--project DIR] [--out FILE] [--json] | bob u dispose <item> <certified|needs-work|not-applicable|retire> --reason "…" [--exam FILE] [--model M] [--baseline PATH] [--retired-by #N] [--date YYYY-MM-DD] [--no-infer] [--apply] [--json]
Flag Meaning
--no-infer status, dispose: use declared project profiles only when grading applicability — never run infer-profile.js on a checkout
--model <M> exam: the model to examine against (passed to the #2390 runner); dispose certified: the model the certification holds for (default: the exam’s model)
--runs <N> exam: runs per case (passed to the runner)
--kit <K> exam: apply session kit K as the provision overlay for the exam and restore it afterwards (default: the machine’s default kit; an overlay already active is used as is)
--no-overlay exam: run the suite bare, with no kit overlay
--project <dir> exam: the project checkout the exam runs in and whose overlay it uses (default: the current directory)
--out <file> exam: also save the skill-eval/1 result to <file>, for dispose –exam
--reason "…" dispose (required): the rationale — one or two sentences a reviewer can check against the evidence
--exam <file> dispose: a skill-eval/1 result recorded as evidence.exam — required for certified
--baseline <path> dispose certified: the eval baseline graded against (default: evals/<name>/baseline.json when it exists)
--retired-by <#N|sha> dispose retire (required): the issue or commit that retires the item — goes into the record and the retired-items.json draft
--date <YYYY-MM-DD> dispose: the decision date (default: today, UTC)
--apply dispose: write the record to registry/dispositions.json (without it: report only)
--json one versioned document on stdout, error set on failure: status → bob-u-status/1 (counts, undisposed [{type, name, bucket, usage, metadata_fix}], certifications [{type, name, certified_model, examined, runs_on, runs_on_id, runs_on_source, state, reason, message}], reexamine (the state re-examine subset), usage_base, gate); exam → bob-u-exam/1 (item, suite, model, overlay, result, supports, next); dispose → bob-u-dispose/1 (item, record (the replaced one moved into its history), replaces, ok, violations, applied, retire_draft, next_steps)
Exit Meaning
0 status rendered · exam supports certified · dispose record valid (written with –apply)
1 status: the disposition record fails its gate · exam: the result supports needs-work (no-signal or regressed) · dispose: the record would fail its gate — nothing written
2 usage error, an unknown or ambiguous item, an item with no eval suite (exam), or an unreadable record
3 exam: the #2390 runner is missing or failed, or the kit overlay could not be applied

Engine: node scripts/bobu/u.js · Issue: #2903 · Since: v1.276.0 · Alias: bob learn · Read next: Dispose of an item with Bob University

Send a Telegram message over the remote-decision bridge from a shell: reads BRIDGE_WORKER_URL/BRIDGE_SECRET from the environment, the project’s .mcp.json, or $BOB_HOME/.mcp.json, POSTs /notify, and prints the message instead when no bridge is configured — never lost, never a silent drop.

bob notify <message> [--level info|warn|block] [--project <name>] [--session-id <id>] [--cwd <dir>] [--json]
Flag Meaning
--level <info|warn|block> severity shown on the message: info (default) · warn → warning · block → error
--project <name> project label on the message (default: BRIDGE_PROJECT from the config, else the project root’s basename)
--session-id <id> the sessionId the bridge groups by (default bob-notify)
--cwd <dir> where to start looking for .mcp.json — the nearest .git/.claude ancestor is the project root (default $PWD)
--json one bob-notify/1 document on stdout (the secret is never in it)
Exit Meaning
0 delivered (2xx)
2 usage error
3 bridge not configured — message printed to stdout instead
4 transport error — curl failed or the bridge answered non-2xx

Engine: bash scripts/rdb/notify.sh · Issue: #2048 · Since: v1.274.0

Open bob viz — every project on every fleet machine as small multiples, from the fleet feed (/bob on the dashboard server, same freshness and self-update path as bob warp viz); each tile links to its bob warp viz card, and –tailnet serves it on this machine’s Tailscale address (#2070).

bob viz [--tailnet] [--page briefings] [--json] | --install-service | --uninstall-service [--dry-run]
Flag Meaning
--tailnet serve on the Tailscale address (reachable from any machine on the tailnet). Prints the MagicDNS URL first, then labelled MagicDNS: and tailnet IP: lines. A localhost bind on a tailnet host prints local only — not reachable from other machines and names this flag; a URL that would not open is never printed (#2918)
--page briefings open /briefings instead — the latest briefing and its history on the same server (#2244)
--json one bob-viz-launch/1 document instead of the lines: bind, url and the {magicdns, ip, localhost} URL set, null where the dashboard does not answer; implies no browser (#2918)
--install-service install the always-on dashboard server (#3001): a launchd agent (com.bob.viz) on macOS or a systemd user unit (bob-viz.service) on Linux that starts it at login on this machine’s resolved bind and restarts it on exit; idempotent, prints what changed. bob viz and bob warp viz then reuse it instead of starting a second server
--uninstall-service stop and remove the dashboard service; idempotent
--dry-run with –install-service / –uninstall-service: report what would be written and run, change nothing
Exit Meaning
0 served
1 no project here and no BoB source checkout, or the server failed to start; or a systemctl / launchctl step of –install-service failed
2 usage error (–dry-run without a service flag, an unknown flag)

Engine: bash scripts/cli/warp viz --page bob · Issue: #2070 · Since: v1.274.0 · Read next: bob viz

Open BoB Control (#3813, cap #3812): /control on the dashboard server, one frame whose navigation is Now, Projects, Fleet and Costs (#3914, #4034), then the crumbs of where you are (#4025) — /control is the Now page, /control?view=projects every registered, active project, /control?view=fleet bob viz’s notices, reports and briefings and /control?view=costs its GitHub quota line, neither with project tiles, /control?project=<name> that project’s own page, /control?project=<name>&session=<tmux name>[&host=<machine>] what runs in that tmux session (#4026): a run’s session screen (#3929) with its kind in the heading — what it is working on, its stepped state row, its status, tabs for acceptance criteria, feed, plan, commits and files, Steer this run, and its terminal — a bare tmux session’s terminal labelled terminal, or ended with a link back to the project; a warp run’s old segment name redirects to the session the run is in now, and an old session=<kind> address to the tmux session running that kind (bob warp viz keeps the full graph page). The same server, freshness and bind as bob viz; an unknown project or view is the frame with the reason and HTTP 404. bob control runs (#3821) prints every step run from an Ask screen’s Run button, and every action run from a project’s page (#3920), on this machine: the ask and step, or the project and command, the host, the time and who asked, read from $BOB_HOME/control-runs.jsonl, the one thing Control writes; –json prints one bob-control-runs/1 document.

bob control [--tailnet] [--json] | bob control runs [--json]
Flag Meaning
--tailnet serve on the Tailscale address, as bob viz –tailnet does
--json one bob-viz-url/1 document for /control instead of the lines: running, url, the {magicdns, ip, localhost} URL set, port and bind; implies no browser. With runs: one bob-control-runs/1 document: log, count, unreadable and runs [{at, ask, step | project, action, command, dry_run, host, caller {identity, machine, local, address}}]
Exit Meaning
0 served; runs: printed (an empty log is zero runs)
1 no project here and no BoB source checkout, or the server failed to start; runs: the log could not be read
2 usage error (an unknown flag)

Engine: node scripts/dashboard/control-cli.js · Issue: #3813 · Since: v1.279.0 · Read next: BoB Control

Initialize a project with BoB tooling: the .claude/ directory, universal symlinks into BOB_HOME, and — when no manifest exists — an offer of one-shot auto-provisioning (bob provision –init –auto).

bob init [-y|--yes] [--auto-provision] [--force] [project-dir]
Flag Meaning
-y, --yes non-interactive: accept every default
--auto-provision when no manifest exists, run bob provision –init –auto without prompting (#1161)
--force init even if warp-drive is active; also overrides the non-project marker check (#707) — $HOME and BOB_HOME are always refused
Exit Meaning
0 initialized (or already converged)
1 refused or failed — non-project target, protected directory, or a link step failed

Engine: exec scripts/cli/cdi · Issue: #2059 · Since: v1.274.0 · Was: cdi · Read next: Project setup

The one command for starting or resuming a project: takes a new or existing directory, or an owner/repo it clones, to warp-ready and visible on bob viz — idempotent, no prompts, never blocked by other running projects: repo → host → links → init → provision → labels → ports → manifests → viz, plus CI, automation level, RDB and mirror for a project it creates.

bob ready [project-dir | owner/repo | --all] [--new] [--start] [--vision <file|->] [--dry-run] [--json] [--name <project-name>]
Flag Meaning
--all grade every project projects.json declares that is checked out on this machine — one table, each verdict persisted (#2068)
--dry-run report what each step would do; mutate nothing
--json machine-readable verdict (schema project-ready/1; project-ready-all/1 with –all)
--name <project-name> override the project name used for the provisions manifest
--new create the forge repo for a directory that already has files (a missing or empty directory gets one without it) (#3158)
--start once READY with approved work, run bob warp start and print its attach command (#3158)
--vision <file|-> write docs/vision.md from the text (- reads stdin) when the project has none — the /vision template, the text under ## Vision; an existing one is never overwritten (#4033)
Exit Meaning
0 READY
1 NOT READY — each blocker names its fix; with –all, any present project NOT READY
2 usage error

Engine: node scripts/ready/ready.js · Issue: #1922 · Since: v1.272.0 · Was: bob-ready · Read next: bob ready

The warp-drive preflight gate: doctor + ready --dry-run as one verdict. Non-mutating; a failure files one todo per machine + cause (host causes in bigbrain, project causes in the project repo), comments on it when it recurs, and a later pass closes it (#3161).

bob preflight [--project <dir>] [--converge] [--section host,project] [--issue <N>] [--no-file] [--json]
Flag Meaning
--project <dir> the project to grade (default: the current directory)
--converge apply bob ready first (idempotent), then re-check
--section host,project run only the named checks
--issue <N> the requirement a filed todo should reference
--no-file never file or bump a todo
--json machine-readable verdict (schema warp-preflight/1)
Exit Meaning
0 pass
1 fail — todo filed or bumped
2 usage error
3 engine error (fails closed)

Engine: node scripts/warp-drive/host-preflight.js run · Issue: #1923 · Since: v1.272.0 · Read next: Warp Drive

Provision a project from its manifest — status / diff / check / refresh / prune / init / interview / detect / add / remove / decline / reconcile / overlay / untrack / ignore-paths — through the node engine scripts/orchestrator/provision.js with argv passed through unchanged.

bob provision [--status [--context [--json]] | --diff [--json] | --check | --refresh | --prune | --init [--auto] [--no-infer] | --interview | detect | add <type> <name> | remove <type> <name> | decline <type>/<name> --reason <why> | reconcile [--apply] [--allow-remove] | overlay <apply|restore|status> ... | untrack [<dir>... or --fleet] [--apply] [--push] [--json] | ignore-paths [--json]] [project-dir]
Flag Meaning
--status the current provisioning state (exit 3 on drift)
--context with –status: the description tokens a session here loads — global set, project manifest, manifest + each kit — per item type; –json = bob-context-cost/1 (#2229)
--diff dry run — what would change, with a why: line per recommended item (#1879); –json = the explain.js document
--check IaC compliance check: drift and undeclared items
--refresh re-provision from the manifest (the default action)
--init generate the manifest from stack detection; –auto = detect → write → refresh with no prompts (#506)
--interview the orchestrator interview (#163) — the same engine bin/cdprov-interview wraps
--prune remove dangling BoB symlinks (#304)
--untrack untrack provisioned .claude/ symlinks a repo still commits — the #1479 migration (#2519); report-only without –apply, one commit per repo with it, –fleet for every checkout on this machine
--ignore-paths print the path set the managed ignore block covers here (bob-ignore-paths/1 with –json) — read-only; what untrack selects against (#2536)
Exit Meaning
0 converged, applied, or dry run printed
1 failure — a refused write, a broken link, or an engine error
2 usage error
3 drift (–status)

Engine: exec scripts/cli/cdprov · Issue: #2059 · Since: v1.274.0 · Was: cdprov · Read next: Project setup

Link a global item (command, agent, hook) into the current project’s .claude/, link every missing one, or list what is available.

bob link <type> <name> | --all | --list [type]
Flag Meaning
--all link every missing global item
--list [type] list the available global items, optionally one type
Exit Meaning
0 linked or listed
1 usage error, unknown type or item, or no project .claude/ found

Engine: exec scripts/cli/cdl · Issue: #2059 · Since: v1.274.0 · Was: cdl · Read next: Project setup

Promote a local .claude/ item (command, agent, hook, skill) to the global source and replace the local file with a symlink back.

bob promote <file>
Exit Meaning
0 promoted and linked back
1 usage error, unsupported item type, the SkillSpector scan refused the item (#1328), or the copy / link failed

Engine: exec scripts/cli/cdp · Issue: #2059 · Since: v1.274.0 · Was: cdp · Read next: Authoring a skill

Scaffold a project’s dev → test → prod promotion ladder — detect → dev.json → wrangler → provision handoff → todo → verify; dry run by default, –apply writes (#931).

bob promotion setup [--apply] [--json] [project-dir]
Flag Meaning
--apply write dev.json + wrangler [env.test] and file the redaction / secrets-gate todo; idempotent, no-clobber
--json the machine-readable report
Exit Meaning
0 ladder green, or dry run printed
1 a red verify gate — the ladder is not done
2 usage error

Engine: exec scripts/cli/setup-promotion · Issue: #2059 · Since: v1.274.0 · Was: setup-promotion · Read next: Set up dev → test → prod

Deploy this project to its test or prod environment through scripts/deploy/deploy.sh — the resolved adapter’s check → build → migrate → deploy → verify contract — with a D1 backup taken before migrating when the env declares one and migrations are pending (#3087) — refused past the promotion ceiling (dev.json promotion.ceiling × automation level, the gate warp-drive’s promoting phase uses) with the gate’s reason; –dry-run prints the exact wrangler commands for that env. bob deploy --env prod is how TEST is promoted to PROD by hand; the release tag is its CI expression (#3081).

bob deploy [--env test|prod] [--dry-run] [--project <dir>] [--adapter <name>] [--skip-tests] [--skip-build] [--skip-backup] [--force] [--list]
Flag Meaning
--env <test|prod> target environment (default prod)
--dry-run run the checks and print every step — the exact wrangler migrate and deploy commands for the env — without shipping; a ceiling breach only warns
--project <dir> project root to deploy (default: the current directory)
--adapter <name> force an adapter (cloudflare, node, drupal) instead of resolving one
--skip-tests skip the contract’s check step
--skip-build skip the contract’s build step
--skip-backup migrate without the pre-migrate backup — the explicit override, printed as a warning (#3087)
--force bypass the promotion-ceiling gate — a deliberate human override
--list list the available adapters and exit
Exit Meaning
0 deployed, or the dry run printed
1 a contract step failed, or a usage error
3 refused — past the promotion ceiling, or the adapter cannot map the env (reason on stderr)

Engine: bash scripts/deploy/deploy.sh · Issue: #3081 · Since: v1.277.0 · Read next: Set up dev → test → prod

Render a project’s backup Worker from its dev.json environments.<env>.backup block (#3084, cap #3067): the Worker and its scheduled Workflow (templates/backup-worker/) written to <project>/backup-worker/ with the project’s D1 id, account and schedule; the backup R2 bucket created if absent; the declared retention set as two R2 lifecycle rules (bob-backup-daily on <db>/, bob-backup-monthly on monthly/<db>/). Dry run by default; –apply writes and converges, and a second –apply reports no change. The Worker’s deploy and its D1_REST_API_TOKEN secret are printed as next steps, never run.

bob backup setup [--project <dir>] [--env <env>] [--apply] [--json]
Flag Meaning
--project <dir> project root (default: the current directory)
--env <env> the environment whose backup block to render (default prod)
--apply write the Worker, create the bucket and set the lifecycle rules; without it, print the plan
--json one bob-backup-setup/1 document: files, bucket and rules with their action, changed, next steps
Exit Meaning
0 planned, or applied and converged
1 a wrangler step failed under –apply
2 usage
3 the backup declaration, the project’s wrangler config or its D1 database is missing or invalid (named on stderr)

Engine: node scripts/backup/setup.js · Issue: #3084 · Since: v1.277.0 · Read next: Set up dev → test → prod

How old a project’s newest D1 backup is (#3085, cap #3067): per env whose dev.json declares environments.<env>.backup, the newest dump the backup Worker wrote (read from its latest/<db>.json pointer in the backup bucket), its age, size and per-table row counts from its sidecar, and the last restore drill; fresh when it is no older than the run the declared schedule last fired, with an hour’s grace, stale when it is older or absent, and unknown — never fresh — when the bucket cannot be read (#3086).

bob backup status [--project <dir>] [--json]
Flag Meaning
--project <dir> project root (default: the current directory)
--json one bob-backup-status/1 document: verdict and, per env, newest, age_seconds, expected_by, drill, fresh, reason
Exit Meaning
0 every declared backup is fresh
1 a backup is stale — older than the schedule allows, absent or unreadable
2 usage
3 no backup declared, or the declaration or wrangler config is invalid (named on stderr)

Engine: node scripts/backup/ops.js status · Issue: #3085 · Since: v1.277.0 · Read next: Set up dev → test → prod

Take a D1 backup now (#3085, cap #3067): trigger the project’s backup Workflow — the one its nightly cron starts — through wrangler workflows trigger, then wait until the latest/<db>.json pointer names a dump taken after the trigger. The primitive the deploy path’s backup-before-migrate calls.

bob backup run [--project <dir>] [--env <env>] [--timeout <min>] [--json]
Flag Meaning
--project <dir> project root (default: the current directory)
--env <env> the env whose declared backup to run (default prod, or the one env that declares a backup)
--timeout <min> how long to wait for the dump (default 30)
--json one bob-backup-run/1 document: ok, worker, instance, sidecar, waited_seconds, error
Exit Meaning
0 the new dump landed
1 the trigger failed, or no new dump within –timeout
2 usage
3 no backup declared, or the declaration or wrangler config is invalid (named on stderr)

Engine: node scripts/backup/ops.js run · Issue: #3085 · Since: v1.277.0 · Read next: Set up dev → test → prod

Load a backup into the restore-target env’s D1 and verify it (#3085, cap #3067): the newest dump (or –from <key>) fetched from the backup bucket, the target’s existing tables and views dropped, the dump loaded with wrangler d1 execute –file, and each table’s row count checked against the dump’s sidecar; the elapsed time is printed as the measured RTO, and a restore whose counts all match records itself as the drill at latest/<db>.drill.json, which bob backup status shows (#4266). The target is environments.<prod>.backup.restore_target (default test). Restoring into prod is refused unless a human gate passes — automation Level 1 or –i-understand-this-overwrites-prod, and the database name typed at a terminal — and never runs unattended. For a recent mistake in prod, D1 Time Travel comes first: runbooks/project-data-restore.md.

bob backup restore [--project <dir>] [--env <env>] [--from <key>] [--i-understand-this-overwrites-prod] [--json]
Flag Meaning
--project <dir> project root (default: the current directory)
--env <env> the env to restore into (default the declared restore_target, test)
--from <key> the dump to restore, e.g. app-db/2026-09-20T0300Z.sql (default the newest)
--i-understand-this-overwrites-prod with –env prod above automation Level 1: allow the prod restore, still only after the typed confirmation
--json one bob-backup-restore/1 document: from, target, dropped, counts, rto_seconds, drill, error
Exit Meaning
0 restored and every row count matches the sidecar
1 a step failed, or a row count differs
2 usage
3 no backup declared, or the declaration, wrangler config or restore target is missing or invalid (named on stderr)
4 refused by the prod gate — nothing was touched

Engine: node scripts/backup/ops.js restore · Issue: #3085 · Since: v1.277.0 · Read next: Set up dev → test → prod

Run the /groom pass headless from a shell: claude -p over the inlined /groom command text and scope — an explicit DRY-RUN by default, –apply at automation Level 3 (read-then-write logs and applies). AskUserQuestion and the RDB ask_remote tool are disallowed, so a decision that needs a human becomes a conforming todo and the item is left blocked; the run’s GROOM-RESULT summary line is the exit code.

bob groom [--area <slug> | --issues N,N | --all] [--apply] [--timeout <min>] [--route <name>[:<model>]] [--cwd <dir>] [--json]
Flag Meaning
--area <slug> groom every cap/req carrying area:<slug> as one set (/groom area:<slug>)
--issues <N,N> groom these issues — one N is the single-target /groom N; several are groomed as one set
--all every open cluster (bare /groom) — the default
--apply Level 3: log the read-then-write plan inline and apply it; the project is switched to Level 3 first when below it (a settings.local.json edit, named on stderr)
--timeout <min> kill the run after this many minutes (default 30) — reported as timed_out, exit 4
--route <name>[:<model>] run the groom on a model route (#3590), e.g. openrouter or openrouter:<model slug> — refused before anything runs for a client project, a key at its limit or an unknown model; without it the groom runs on the subscription
--cwd <dir> the project to groom (default: the current directory)
--json one bob-groom/1 document on stdout: scope, mode, level, timed_out, claude_exit, result {groomed, approved, blocked, todos, deferred}, output, verdict, exit
Exit Meaning
0 groomed
1 the groom reported blockers (blocked>0), or produced no GROOM-RESULT summary line
2 usage or config error — bad flag, two scopes, no groom.md, the Level 3 switch failed
3 claude unavailable (not on PATH) or it failed to run
4 killed at –timeout

Engine: bash scripts/groom/groom.sh · Issue: #2051 · Since: v1.274.0 · Read next: Warp Drive

Decompose an approved capability or use case into filed child requirements through six evidence-gated phases on the shared machine engine (#2975): sourcing (cap-status) → drafting → deduping (issue-dedupe) → testability (the decompose-testability judge) → tracing → filed (gh read-back). Runs beside an active warp-drive session; creates no report, commit or branch (#2976).

bob decompose <N> | status | transition <event> [--data JSON | --file F] | stop [--cwd <dir>] [--json]
Flag Meaning
--data <JSON> the event’s payload — drafted: {children:[{title, body, labels}]}; deduped: {resolve:{c1:‘drop’|‘merge #N’}}; judged: {override:{child, n, by, why}}
--file <path> read the event’s payload from a JSON file instead of –data
--cwd <dir> the checkout whose .claude/.decompose-state.json holds the run (default: the current directory)
--json one bob-decompose/1 document: phase, parent, refusal {gate, reason, detail, children}, children, co_running_warp, viz (bob-viz-url/1 for /warp?kind=decompose, #2978) — status without –json ends with the same link as a viz: line, or the command that starts the dashboard
Exit Meaning
0 started, advanced, or status printed
1 invalid transition from the current phase, or a run already active
2 usage error, or no decompose run in this checkout
3 refused by the phase’s gate — the named refusal is recorded on the run’s state

Engine: node scripts/decompose/decompose.js · Issue: #2976 · Since: v1.276.0 · Read next: Decompose a capability

Run an hour of unstructured work as a state machine on the shared engine (#2975): framing (a one-line question and an artifact from the closed set decision · lesson · doc · spike · issue-set · discard) → working (bounded by a minutes or tokens budget, or ended by declaring enough) → landing (read-back evidence of the declared artifact) → recording (the artifact and its prompt linked both ways) → done, or discarded — a green terminal that requires a filed decision issue. Writes files, so it refuses to start while a warp-drive run is active here, and warp-drive refuses while it is (#2979).

bob do "<question>" [--artifact <type>] [--budget <N>m|<N>t|<N>k] | status | transition <event> [--data JSON] | stop [--cwd <dir>] [--json]
Flag Meaning
--artifact <type> frame the run at start: decision, lesson, doc, spike, issue-set or discard — anything else is refused at the framing gate
--budget <N>m|<N>t|<N>k the working-phase budget — minutes (bare N or Nm), tokens (Nt) or thousands of tokens (Nk); default _workflow.do_budget_minutes
--data <JSON> the event’s payload — framed: {artifact, question?}; worked: {enough:“<why>”}; landed: {issue:N} | {issues:[N…]} | {path:“docs/…”}; recorded: {prompted_by:“#N” | “<path>” | “none”}; discard: {decision:N}
--pid <N> the process the run belongs to (default: the nearest claude ancestor) — the liveness anchor the concurrency rule reads
--cwd <dir> the checkout whose .claude/.do-state.json holds the run (default: the current directory)
--json one bob-do/1 document: phase, question, artifact, budget, budget_use, budget_exhausted, decision, outcome, artifact_ref, prompted_by, run_id, refusal, viz (bob-viz-url/1 for /warp?kind=do, #2978) — status without –json ends with the same link as a viz: line, or the command that starts the dashboard
Exit Meaning
0 started, advanced (discarded included), stopped, or status printed
1 invalid transition from the current phase, or a run already active
2 usage error, or no do run in this checkout
3 refused by the phase’s gate, or by the concurrency rule (an active warp-drive run owns the checkout)

Engine: node scripts/do/do.js · Issue: #2979 · Since: v1.276.0 · Read next: Run unstructured work with bob do

Derive a flight plan once and write/refresh its issue — flightplan.js build –no-interview with the mapped scope flags; prints the plan number. Without –allow-unapproved un-approved work is never seated (the engine names each dropped issue).

bob plan build [--from approved|farm] [--from-issues N,N] [--area <slug>] [--plan <N>] [--name <name>] [--branch <name>] [--max-items <n>] [--after <N> | --no-after] [--allow-unapproved] [--allow-overlap] [--json]
Flag Meaning
--from <approved|farm> approved (default): the approved queue, no scope flag passed · farm: the unattended scope (#2052) → flightplan.js –from farm — only farm-eligible work is seated (eligibility.js), every exclusion named
--from-issues <N,N> an explicit issue list → flightplan.js –issues N,N
--area <slug> one workstream → flightplan.js –area <slug>
--plan <N> with –from-issues: grow or re-scope THAT open issues: plan in place → flightplan.js –plan N — its scope marker is rewritten and every tick, branch, gate mode, depends_on edge and name carried, instead of a second plan for the new list (#2283)
--branch <name> declare the plan’s integration branch (#1181)
--name <name> name the plan: title Flight plan: <name> + a flightplan:name marker (#2309) — omitted, a new plan takes the name derived from its area labels and a refresh keeps the recorded one
--max-items <n> seat at most n req/bug items in run order, each with the in-scope items it depends on; the rest are dropped and named (#2055 — the farm tick’s issue budget)
--after <N> run after flight plan #N (#2298) → flightplan.js –after N — the plan waits while #N is open with unfinished items; repeatable or N,N
--no-after clear the plan’s declared predecessor(s) → flightplan.js –no-after
--allow-unapproved seat issues lacking approved (off by default)
--allow-overlap with –from-issues: build even though an open plan already holds some of the items — without it the engine exits 3 naming that plan and the –plan <N> command to grow it (#3199)
--json the engine’s JSON document: plan, scope, items, dropped, unapproved …
Exit Meaning
0 plan created or refreshed
1 the engine rejected an argument (e.g. a non-git-safe –branch)
2 usage error — unknown flag, two scope sources, bad –from — or a gh/repo error from the engine
3 refused: a –from-issues plan shares items with an open plan (#3199) — grow it with –plan <N>, or pass –allow-overlap

Engine: bash scripts/bob/plan.sh build · Issue: #2050 · Since: v1.274.0 · Read next: Flight plan

Runnable plan items in run order — flightplan.js remaining <N>, argv passed through unchanged.

bob plan remaining <N> [--json] [--all]
Flag Meaning
--json an ARRAY of runnable items (the warp-drive consumer contract)
--all widen –json to { gateMode, runnable, gated, withheld, moot, waiting }
Exit Meaning
0 printed
1 usage — missing/invalid <N>, or a broken depends_on declaration
2 gh/repo error

Engine: bash scripts/bob/plan.sh remaining · Issue: #2050 · Since: v1.274.0 · Read next: Flight plan

Plan progress — runnable vs gated vs withheld vs moot vs waiting, todo gate states, gate mode, integration branch, lifecycle — flightplan.js status <N>, argv passed through unchanged.

bob plan status <N> [--json]
Flag Meaning
--json machine-readable status document
Exit Meaning
0 printed
1 usage — missing/invalid <N>
2 gh/repo error

Engine: bash scripts/bob/plan.sh status · Issue: #2050 · Since: v1.274.0 · Read next: Flight plan

The plan’s ordered items, todo rows marked — flightplan.js items <N>, argv passed through unchanged.

bob plan items <N> [--json]
Flag Meaning
--json machine-readable item list
Exit Meaning
0 printed
1 usage — missing/invalid <N>
2 gh/repo error

Engine: bash scripts/bob/plan.sh items · Issue: #2050 · Since: v1.274.0 · Read next: Flight plan

Launch a warp-drive run in a named tmux session from any shell: bob preflight first (exit 1 with the verdict when it fails; on the BoB source checkout a failure that is only this machine being behind source is fixed first — deploy.sh then bob doctor, when the checkout is the clean main branch and no Claude Code session is live, #2472), then the project’s dashboard on this machine’s resolved bind (reported, never blocking; –no-viz opts out, #2636), then a tmux session named warp-STEM[-SCOPE] in the project root (STEM is the project resolved from the main repository, or PROJECT-WORKTREE in a linked git worktree, #4041; the dashboard is the project’s own) receives the claude line with the level, -rdb and scope flags; prints the session, its tmux -CC attach line and the viz URL; refuses when that session already exists. Not bob warp session start — that binds an integration-branch stream and launches nothing.

bob warp start [--flightplan N | --issue N | --area <slug>] [--level 1-4] [--rdb] [--session <name>] [--attach] [--root <dir>] [--max-tokens <n>] [--dry-run] [--no-converge-host] [--no-viz] [--json]
Flag Meaning
--flightplan <N> scope the run to a flight-plan issue (session warp-<stem>-fp-N)
--issue <N> scope the run to one issue (session warp-<stem>-issue-N)
--area <slug> scope the run to one area workstream (session warp-<stem>-area-<slug>)
--level <1-4> automation level passed as -a<level> (default: _automation.active_level in .claude/settings.local.json, else 3)
--rdb pass -rdb so the run uses the remote-decision bridge (Telegram)
--session <name> tmux session name instead of the derived warp-<stem>[-<scope>]
--attach surface the session: iTerm2 control-mode window on an interactive Mac, plain tmux attach on a Linux TTY, the attach line otherwise
--root <dir> project root (default: the git toplevel of –cwd / $PWD)
--dry-run run the preflight (files nothing) and print the plan; no session created
--no-preflight skip bob preflight (never the default)
--no-converge-host do not converge the host at kickoff (also WARP_LAUNCH_CONVERGE_HOST=0). By default, on the BoB source checkout, a preflight that names this machine behind source (the host:behind advisory, or a host:surfaces finding — #3160) and no other failure, with the checkout on the clean main branch and no live Claude Code session, runs scripts/deploy.sh and bob doctor, then preflight again, before launching — recorded as host_converged {ran, verdict, deploy_rc, doctor_verdict, reasons} in warp-start/1 (#2472)
--no-viz do not ensure the project’s dashboard (by default warp start runs bob warp viz –no-open — reuse a fresh server or start one on the machine’s resolved bind — prints the URL beside the attach line and carries it as viz.url in warp-start/1; a failure is reported, never blocking — #2636)
--max-tokens <n> the run’s token ceiling — passed on the /warp-drive line as the kickoff flag, enforced by the session breaker (#2055)
--json one warp-start/1 document on stdout
Exit Meaning
0 started (or dry-run plan printed)
1 preflight failed — the verdict is printed, nothing started
2 usage error
3 refused — that tmux session already exists
4 tmux unavailable or session creation failed
5 refused — an active bob do run owns this checkout (it writes files; #2979), named with its question and phase

Engine: bash scripts/warp-drive/launch.sh start · Issue: #2049 · Since: v1.274.0 · Read next: Warp Drive from the command line

Attach to the project’s live warp-drive run and follow it across segments: one name per run, no warp-seg-N to know. When the run hands off to a new segment this terminal moves to it; it stops when you detach or the run ends (#3163).

bob warp attach [project] [--cc | --plain] [--print] [--command] [--json] [--session <name>] [--wait <s>] [--poll <s>]
Flag Meaning
--cc tmux -CC attach — iTerm2 control mode, the default inside iTerm2 (also over SSH); each segment gets its own -CC attach, so a continuation still opens as its own window (#1022)
--plain tmux attach — the default on any other terminal
--print print the run’s current tmux session and its tmux attach line; attach nothing
--command print the one attach command for the project — by its projects.json name, else by path; needs no live run (what bob warp start, bob warp status and the viz card show)
--json one warp-attach/1 document on stdout: root, live, phase, session, segment, basis (handoff | recorded | pid | newest | launcher), mode, command, tmux; attaches nothing
--session <name> the tmux session to start on when the run has recorded none yet — bob warp start –attach passes the session it just made
--wait <s> seconds to wait for the next segment’s session after one ends (default 120)
--poll <s> seconds between checks for a handoff while attached (default 2)
Exit Meaning
0 followed the run to its end, detached, or printed
1 no project found
2 usage error
3 no live run to attach to, or no tmux session hosts it
4 tmux unavailable, not a terminal, or the attach failed — the tmux line is printed

Engine: node scripts/warp-drive/attach.js · Issue: #3163 · Since: v1.277.0 · Read next: Warp Drive from the command line

Show the active warp-drive phase, issue, chunk and metrics; –watch redraws in place, –log appends the phase history.

bob warp status [--watch|--live|-w] [--interval <s>] [--log] [--json]
Flag Meaning
--watch, --live, -w live view — redraw in place
--interval <s> refresh interval in seconds (default 5)
--log append the phase-history log below the session info
--json one-shot: the state machine’s status document plus viz (bob-viz-url/1) — the dashboard’s {magicdns, ip, localhost} URL set, or the command that starts it (#2639); {active: false, viz} when no session is active
Exit Meaning
0 rendered
1 no project root, or the state file is unreadable
2 –json combined with –watch

Engine: exec scripts/cli/warp status · Issue: #2059 · Since: v1.274.0 · Was: warp · Read next: Warp Drive from the command line

The warp-drive phase-transition history for this project.

bob warp log
Exit Meaning
0 rendered
1 no project root, or the state file is unreadable

Engine: exec scripts/cli/warp log · Issue: #2059 · Since: v1.274.0 · Was: warp · Read next: Warp Drive from the command line

Show the resolved workflow configuration (_workflow keys, kickoff options) for this project.

bob warp config
Exit Meaning
0 rendered
1 no project root

Engine: exec scripts/cli/warp config · Issue: #2059 · Since: v1.274.0 · Was: warp · Read next: Warp Drive from the command line

Open the live session graph in the browser (#1552); –tailnet serves it on this machine’s Tailscale address, the default where machines.json declares dashboard.bind: tailnet (#2636).

bob warp viz [--tailnet] [--no-open] [--json]
Flag Meaning
--tailnet serve on the Tailscale address (farm-hosted project, reachable from a laptop on the tailnet); prints the MagicDNS URL first, then labelled MagicDNS: and tailnet IP: lines (#2918). Alias –tailscale. With no flag the bind is DASH_BIND, then this machine’s machines.json dashboard.bind, then localhost; any other -flag exits 2 (#2636)
--no-open ensure the server and print the URL without opening a browser (what bob warp start runs, #2636)
--json one bob-viz-launch/1 document instead of the lines: bind, url, the {magicdns, ip, localhost} URL set (null where the dashboard does not answer), project, bind_source, reused; implies –no-open (#2918)
Exit Meaning
0 served
1 no project root, or the server failed to start

Engine: exec scripts/cli/warp viz · Issue: #2059 · Since: v1.274.0 · Was: warp · Read next: Warp Drive from the command line

Abort the active warp-drive session — graceful (transitions to aborted) or –hard (deletes the state file, no cleanup). Mutating, no dry run: the engine has no –help of its own, so bob warp stop --help is answered by the router and never reaches it (#2049).

bob warp stop [--hard|--reset]
Flag Meaning
--hard, --reset emergency reset — delete the state file with no cleanup
Exit Meaning
0 aborted or reset
1 no active session, or the transition failed

Engine: exec scripts/cli/warp stop · Issue: #2059 · Since: v1.274.0 · Was: warp · Read next: Warp Drive from the command line

GC leaked warp-seg-* tmux sessions and orphaned REPLs, and find Claude Code in every other tmux session graded stale or live by idle time (#3302) — dry run by default, –force executes, –yes also reaps attached or warp-running sessions, –idle-shells also kills idle shell-only sessions; Claude outside tmux is reported only.

bob warp reap [--force] [--yes] [--idle <minutes>] [--idle-shells] [--json]
Flag Meaning
--force execute the reap (default: dry run); each pane’s scrollback is saved to .claude/scrollback/ first, then a stale Claude pane gets Escape, /exit, a wait, and the pane is killed
--yes with –force, also reap attached sessions and Claude panes whose project has an active warp-drive run
--idle <minutes> idle time after which a Claude pane is stale and a shell-only session is reported (default: _workflow.reap_idle_minutes, 240)
--idle-shells with –force, also kill idle shell-only tmux sessions
--json machine-readable plan: warp-seg classes plus claude, idle_shells, outside and the actions taken
Exit Meaning
0 reported or reaped
1 a kill failed

Engine: exec scripts/cli/warp reap · Issue: #2059 · Since: v1.274.0 · Was: warp · Read next: Warp Drive from the command line

The integration-branch session: start <branch> [–area <slug>|–flightplan <N>] creates + checks out a scope-bound session branch (#1177), end clears it, status shows the resolved branch config.

bob warp session <start <branch> [--area <slug>|--flightplan <N>] | end | status>
Flag Meaning
--area <slug> (start) bind the session branch to one workstream
--flightplan <N> (start) bind the session branch to a flight plan
Exit Meaning
0 ok
1 usage error, or the branch could not be created / resolved

Engine: exec scripts/cli/warp session · Issue: #2059 · Since: v1.274.0 · Was: warp · Read next: Warp Drive from the command line

Ship the integration branch to main — one PR at Level 2, rebase + merge at Level 3 (#268).

bob warp finalize [--dry-run]
Flag Meaning
--dry-run print what would be shipped without pushing or merging
Exit Meaning
0 shipped or previewed
1 no session branch, or the push / merge failed

Engine: exec scripts/cli/warp finalize · Issue: #2059 · Since: v1.274.0 · Was: warp · Read next: Warp Drive from the command line

Fan out parallel warp-drive sessions into isolated git worktrees + tmux windows: fork <branch...> | fork –from-issues [N] | fork –from-flightplan <N> | status | drop | watch | pair.

bob fork <fork <branch>... | fork --from-issues [N] | fork --from-flightplan <N> | status [--json] | drop <branch>|--all [--force] | watch [--once] [--json] | pair ...>
Flag Meaning
--from-issues [N] (fork) auto-discover up to N approved issues (default 4), serial-only excluded
--from-flightplan <N> (fork) fan out flight-plan #N’s runnable wave (#1613)
--dry-run (fork) preview the plan
--include-serial (fork) include serial-only issues
--json (status) machine-readable
--force (drop) remove even with unmerged work
Exit Meaning
0 ok
1 a fork, drop or status step failed
2 usage error, or git / tmux missing

Engine: exec scripts/cli/cdfork · Issue: #2059 · Since: v1.274.0 · Was: cdfork · Read next: cdfork

The cross-repo, contract-driven shape of fork: paired worktrees in a backend and a frontend repo on one shared branch (the standalone form of bob fork pair).

bob pair --contract <path> --backend <repo> --frontend <repo> --branch <name>
Flag Meaning
--contract <path> the shared contract document (required, non-empty)
--backend <repo> the backend repo’s working tree (required)
--frontend <repo> the frontend repo’s working tree (required)
--branch <name> the shared branch name, same on both sides (required)
Exit Meaning
0 both worktrees spawned
1 a worktree or tmux step failed
2 usage error, or git / tmux missing

Engine: exec scripts/cli/cdfork-pair · Issue: #2059 · Since: v1.274.0 · Was: cdfork-pair · Read next: cdfork

Run the full agent-swarm loop as one command — decompose → approve → capped dispatch via bob fork → gate → integrate → summary (#582).

bob swarm <run [--approval <path>] [--cap <n>] [--cwd <dir>] [--dry-run] [--finalize] | plan --plan <file> [--cap <n>] | summary [--plan <file>] [--results-dir <dir>]>
Flag Meaning
--approval <path> (run) the approved decomposition plan
--cap <n> concurrency ceiling (default 4)
--dry-run (run) verify and plan waves without dispatching
--finalize (run) ship the integration branch when every wave passed
--plan <file> (plan / summary) the decomposition plan
Exit Meaning
0 ok
1 a gate, dispatch or integrate step failed
2 unknown subcommand

Engine: exec scripts/cli/swarm · Issue: #2059 · Since: v1.274.0 · Was: swarm · Read next: Swarm decompose

Bring the dev environment to a fully testable state from dev.json: start the server, migrate, seed, provision test users, health-check, report the URL.

bob dev up [--verbose | --check | --regen | --regen-seed | --no-auto-seed] [project-dir]
Flag Meaning
--verbose full lifecycle with detailed output (the default)
--check quick health check only
--regen regenerate dev.json from the stack recipe (overwrites)
--regen-seed delete auto-generated seed files (010+) and regenerate
--no-auto-seed skip automatic seed generation
Exit Meaning
0 every step completed
1 dev.json not found or invalid
2 server failed to start or the health check failed
3 migration failed
4 seed failed

Engine: exec scripts/cli/dev-up · Issue: #2059 · Since: v1.274.0 · Was: dev-up · Read next: Dev lifecycle

Quick health check of the dev environment — the shortcut for dev up --check.

bob dev health [project-dir]
Exit Meaning
0 healthy, or n-a — the project has no dev environment to bring up (#853)
1 dev.json not found or invalid
2 server unreachable or the health check failed

Engine: exec scripts/cli/dev-health · Issue: #2059 · Since: v1.274.0 · Was: dev-health · Read next: Dev lifecycle

Reap regenerable working-tree residue per the project’s reap.json — dry run by default, –apply deletes; keep-list and liveness guards (#1664).

Warp-drive runs it at session end against the project’s declared reap.json, and it is a dry run by default; docs/reference/bob-reap.md documents the manifest, the keep-list and the liveness guards.

bob reap [project-root] [--apply] [--sync-ignore] [--owner <tool>[,<tool>]] [--manifest <path>] [--json]
Flag Meaning
--apply actually delete (default: dry-run report)
--sync-ignore write the managed ignore block for every declared surface (.gitignore, or .git/info/exclude per _meta.ignore_placement) (#1688)
--owner <t>[,<t>] only surfaces owned by these tools (warp-drive|swarm|dev-up|docs-site|dash|qa|misc)
--manifest <path> explicit manifest path (default <root>/reap.json)
--json machine-readable report
Exit Meaning
0 clean
1 a deletion failed
2 config / usage error, including a keep-list refusal

Engine: exec scripts/cli/bob-reap · Issue: #2059 · Since: v1.274.0 · Was: bob-reap · Read next: bob-reap

The tooling dashboard: global items and every registered project’s symlink status, port band, warp-drive harness defects, and last bob ready verdict.

bob dash status [--projects-only | --global-only | --matrix | --ports | --check <project>]
Flag Meaning
--projects-only only the per-project symlink status
--global-only only the global tooling inventory
--matrix the project × item provisioning matrix
--ports the per-project dev-port bands
--check <project> grade one project and exit non-zero on a broken link
Exit Meaning
0 rendered
1 usage error, unknown project, or –check found a broken link

Engine: exec scripts/cli/cdb · Issue: #2059 · Since: v1.274.0 · Was: cdb · Read next: Port allocation

Generate a project’s static dashboard (bugs, releases, changes, incidents, journal, cross-refs) into .dash/ from the current directory.

bob dash generate [project-dir]
Exit Meaning
0 generated
1 build failed

Engine: exec scripts/cli/cdg · Issue: #2059 · Since: v1.274.0 · Was: cdg · Read next: Port allocation

Start the dashboard server for the current project on its ledger-assigned port, or list / stop running dashboards and show port allocations.

bob dash serve [--tailnet | --list | --stop <name> | --stop --all | --ports]
Flag Meaning
--tailnet bind this machine’s Tailscale address instead of localhost (#1736); refuses to start when Tailscale is down
--list every dashboard with its running status
--stop <name> stop every dashboard server for a project, any port and bind (#2563); –all stops every BoB dashboard on this machine
--ports each project’s port band
Exit Meaning
0 started, listed, or stopped
1 server failed to start, Tailscale down under –tailnet, or a server that would not stop

Engine: exec scripts/cli/cds · Issue: #2059 · Since: v1.274.0 · Was: cds · Read next: Port allocation

Converge this machine’s declared tailscale serve front door (#2407): one MagicDNS address, no port, with /bob and every declared project’s /<project>/warp path-routed to its loopback dashboard port, from the machines.json serve block; a report by default, –apply adds or updates BoB’s own routes, never removes a handler it did not declare, and installs and starts every routed project’s always-on dashboard unit; HTTP with https unavailable until tailnet certificates are on; tailscale funnel is refused in code (decision #1773).

bob serve [--apply] [--machine <id>] [--json]
Flag Meaning
--apply converge: add or update each declared route on the effective listener (:443 with certificates, else :80), remove BoB’s own routes from the other one, and install and start each routed project’s dashboard unit that is missing, stopped or out of date
--machine <id> the machines.json entry to use (default: this machine, or BOB_MACHINE_ID)
--json one bob-serve/1 document: host, scheme, https (on / unavailable / off), routes with state (ok / missing / differs / stale), upstream and URL, undeclared handlers, commands, services (each routed project’s dashboard unit and its state), verdict, error
Exit Meaning
0 converged, applied, or no serve block declared
1 drift remains (a route, or a dashboard unit not running), or an apply step failed (named, with its fix)
2 usage or config error, including a declaration or argument naming funnel
3 Tailscale is not installed or not running

Engine: node scripts/fleet/serve.js · Issue: #2407 · Since: v1.277.0 · Read next: Warp Drive — one address for the whole machine

The BoB release engine from a shell: a stable release (bump + CHANGELOG + vX.Y.Z tag + GitHub Release), a nightly tag on a green, moved HEAD (#2045), or promote — stable from the newest nightly, refused on an open p1-critical harness defect (#2057) and held (exit 4) while a release-gating ritual is overdue (#2236); every stable release and promote reports a docs currency gate line — stale pages and commands without a how-to — held when _workflow.docs_release_gate is on (#2554); publish <tag> backfills a missing GitHub Release, and a Release body over GitHub’s limit is published capped (#2557).

bob release [promote [--auto] [--allow-overdue <ritual>] | publish <vX.Y.Z> | notes --draft|--unreleased|check|next-version|render|index|url|show|site] [--channel stable|nightly] [--allow-stale-docs] [--dry-run] [--release-as patch|minor|major]
Flag Meaning
--channel <stable|nightly> stable (default): bump + CHANGELOG + vX.Y.Z tag + Release · nightly: lightweight nightly-YYYY-MM-DD tag
--auto promote only: also refuse a nightly younger than 24 h, counted from the end of its UTC day
--allow-overdue <ritual> promote only: promote over this overdue release-gating ritual (repeatable) — logged, and recorded as a decision issue before anything is released (#2236)
--allow-stale-docs stable / promote: release over a held docs currency gate (stale pages or commands without a how-to) — logged, and recorded as a decision issue before anything is released (#2554)
--dry-run run every gate, then preview without committing, tagging, pushing or publishing
--release-as <patch|minor|major> stable only: force the bump type instead of deriving it from Conventional Commits
Exit Meaning
0 released, tagged, or nothing to do
2 usage error
3 refused — a gate names why
4 held — a release-gating ritual is overdue while _workflow.ritual_release_gate is on; each ritual, why, and its run are named (#2236) — or the docs currency gate found stale pages or commands without a how-to while _workflow.docs_release_gate is on; each is named (#2554)
5 partial — the tag landed but its GitHub Release was not published; the cause, what landed and the finishing command (bob release publish <tag>) are named (#2557)

Engine: exec scripts/cli/bob-release · Issue: #2059 · Since: v1.274.0 · Was: bob-release · Read next: Versioning

Converge this machine to a release channel or tag: fetch, fast-forward the BOB_SOURCE checkout to the newest stable/nightly tag (or –to), run deploy.sh, then doctor — refusing a dirty tree or a live Claude Code session.

bob update [--channel stable|nightly] [--to <tag>] [--dry-run] [--json]
Flag Meaning
--channel <stable|nightly> which tag family to move to: stable = newest vX.Y.Z (default), nightly = newest nightly-YYYY-MM-DD
--to <tag> an explicit tag instead of a channel’s newest (its name records the channel); excludes –channel
--dry-run print the tag it would move to; fetches, writes nothing
--json machine-readable result (schema bob-update/1)
Exit Meaning
0 updated and bob doctor converged
1 updated; bob doctor reports drift
2 usage error, or no source checkout to update
3 refused — dirty tree, off the main branch, cannot fetch, unknown / no tag, not fast-forwardable, or deploy failed (the reason is named)
4 live-session — a Claude Code session is running on this machine (#2040 guard; no –force-live here)

Engine: bash scripts/update/update.sh · Issue: #2046 · Since: v1.274.0 · Read next: Versioning

One unattended maintenance cycle under a lock: bob groom –all –apply → bob plan build –from farm → the host converged on BOB_SOURCE when it is behind source and safe to deploy (deploy.sh + bob doctor, #2472) → one bob warp start run, waited for → flightplan reconcile → fleet snapshot → the wiki maintainer (bob wiki maintain, a real run only at automation Level 3, #2389) → the skill proposer on bigbrain only (bob wiki propose –auto, a real run only at Level 3, #2391) → nightly and promote –auto on BOB_SOURCE → bob update, whose guard refuses a live session only when the nightly would rewrite settings.json hooks (#2746) → a tick-digest/1 digest, commented on the plan and sent with bob notify → brief reconcile (bob brief –reconcile –apply, #3100) → the portfolio briefing (bob brief –send –scheduled, none inside the declared quiet hours, #2246). –dry-run runs every step read-only and files nothing.

bob tick [--dry-run] [--cwd <dir>] [--json] | bob tick --pause | --resume | bob tick --install-timer [--machine <id>] [--dry-run] [--json] | --uninstall-timer
Flag Meaning
--dry-run every step read-only — groom without –apply, the farm queue instead of a plan build, warp start –dry-run, release/promote/update –dry-run; creates no issue, branch, tag, PR or commit
--cwd <dir> the project the tick maintains (default: the current directory); release, promote and update act on BOB_SOURCE
--json the tick-digest/1 document on stdout (human lines to stderr)
--pause write $BOB_HOME/.bob-tick.pause by hand — every later tick exits 3 as paused (two consecutive ticks ending 1 or 4 write it themselves and send one bob notify –level block, #2055)
--resume remove the pause file and reset the failed-tick count
--install-timer render bob-tick.service + bob-tick.timer from this machine’s machines.json bob_workload into ~/.config/systemd/user and enable the timer — Linux only (refused on macOS, where launchd is the path), idempotent, –dry-run writes nothing (#2056)
--uninstall-timer disable the timer and remove both units (#2056)
--machine <id> with –install-timer: the machines.json entry whose bob_workload is installed (default: the host machines.json resolves)
Exit Meaning
0 tick complete or dry-run complete
1 run blocked — a pipeline step failed (named in the digest)
2 usage error
3 another tick holds $BOB_HOME/.bob-tick.lock, the tick is paused ($BOB_HOME/.bob-tick.pause — bob tick –resume), or the project is decided archive (#3609)
4 budget — the run outlived _workflow.tick_wall_clock_minutes (stopped gracefully) or spent more than _workflow.tick_max_tokens

Engine: bash scripts/tick/tick.sh · Issue: #2054 · Since: v1.274.0 · Read next: Farm tick

Consolidate one project’s traces into the skill-evolution wiki (#2389, part of #2387): a scrubbed, bounded packet of everything new since the watermark — loop notes, the decision log, harness defects, ledger no-trigger and improvised records, lesson and session-report issues — handed to one headless claude -p run of the wiki-maintainer prompt, whose patch edits, one log row and the regenerated index are opened as one PR on BOB_SOURCE; never a commit to master, and a second run over the same inputs is a no-op.

bob wiki maintain [--project DIR] [--source DIR] [--dry-run] [--max-records N] [--max-chars N] [--since YYYY-MM-DD] [--json]
Flag Meaning
--project <dir> the project whose traces are read (default: the current directory)
--source <dir> the BOB_SOURCE checkout the PR is opened on (default: the BOB_SOURCE resolver)
--dry-run collect and scrub only: print what a run would consume; no agent call, no watermark, no branch
--max-records <n> the packet cap, oldest first (default 8); the rest waits for the next run
--max-chars <n> each record is cut to this many characters (default 15000)
--since <date> where a source with no watermark starts (default 30 days ago)
--json one wiki-maintain/1 document
Exit Meaning
0 done — a PR opened, a no-op, or a dry run
1 the run failed: the agent, the wiki lint, the push or the PR — nothing is consumed
2 usage or config error (no BOB_SOURCE checkout, no wiki store)

Engine: node scripts/wiki/maintain.js · Issue: #2389 · Since: v1.281.0

Propose one change to one skill, command or agent from the skill-evolution wiki (#2391, part of #2387): the item named, or with –auto the one with the most new wiki evidence among items with an eval suite, handed to one headless Read-only claude -p run of the skill-proposer prompt in a worktree; the change is run through the eval gate (bob eval run + gate) and opened as one PR labelled skill-proposal on BOB_SOURCE — a draft when the gate rejects it — whose body cites the pages, their traces and the gate document, with the skill-impact row recorded on the same branch; a person merges, never the proposer.

bob wiki propose (<item> | --auto) [--source DIR] [--dry-run] [--model M] [--max-cost-usd USD] [--runs N] [--json]
Flag Meaning
--auto propose for the item with the most new wiki evidence that has an eval suite
--source <dir> the BOB_SOURCE checkout the PR is opened on (default: the BOB_SOURCE resolver)
--dry-run pick the target and print what a run would read; no agent, no eval, no branch
--model <model> the model the eval runs on (default: the session default)
--max-cost-usd <usd> the eval cost ceiling (default _workflow.eval_max_cost_usd)
--runs <n> eval runs per case
--json one skill-propose/1 document
Exit Meaning
0 done — a PR opened (a draft when the gate rejected), a no-op or a dry run
1 the run failed: the agent broke the contract, the eval or gate did not run, the push or the PR — nothing is left behind unless the branch was pushed
2 usage or config error (no item or –auto, an item with no eval suite, no BOB_SOURCE checkout)

Engine: node scripts/wiki/propose.js · Issue: #2391 · Since: v1.281.0

Run one item’s eval suite (#2390, part of #2387): evals/<item>/ in BOB_SOURCE through claude plugin eval with a with/without ablation, from the current directory, under a mandatory cost ceiling (–max-cost-usd, else _workflow.eval_max_cost_usd), and print one skill-eval/1 result — the mean case score with and without the item, the delta, the verdict (improved / no-signal / regressed), the trigger rate of the tool_used: Skill graders, cost, model, run id and date, validated against schemas/skill-eval.schema.json. A regressed verdict is a result, not a failure: rejecting a change is bob eval gate’s exit. bob u exam runs it.

bob eval run <item> [--model M] [--runs N] [--max-cost-usd USD] [--out FILE] [--root DIR] [--keep] [--json]
Flag Meaning
--model <M> the model every case runs on (default: the session default — $ANTHROPIC_MODEL, else BOB_HOME’s settings.json model)
--runs <N> runs per case (default: each case’s runs:, else 3)
--max-cost-usd <usd> the cost ceiling for the whole run (default: _workflow.eval_max_cost_usd, 2); 0 or less is refused
--out <file> also write the skill-eval/1 result to <file>, for bob eval gate or bob u dispose –exam
--root <dir> the BOB_SOURCE checkout to read the item and its suite from (default: the BOB_SOURCE resolver)
--keep keep the temp dir (the assembled plugin, the platform’s result and its HTML report) and name it in the output
--json print the skill-eval/1 document
Exit Meaning
0 the eval completed — any verdict, a run the ceiling cut short included (partial: true)
2 usage: an unknown item, an item with no suite, a bad flag or no cost ceiling
3 it could not run: no claude, the platform failed or wrote no result, or the result is not a valid skill-eval/1 document

Engine: node scripts/evals/run.js · Issue: #2390 · Since: v1.281.0 · Read next: Skill evals

The acceptance rule for a skill change (#2390): pass only when a skill-eval/1 result’s with score is strictly higher than the best recorded for the same model in evals/<item>/baseline.json (with no best yet, the result’s own no-item arm is the floor); a neutral change and a partial run are rejected. –record raises the model’s best on accept and, accepted or rejected, appends one wiki/skill-impact.md row naming the proposal’s PR and the wiki pages it was built on.

bob eval gate <item> <result.json> [--model M] [--record --pr <#N|owner/repo#N> --pages <slug,slug>] [--date YYYY-MM-DD] [--root DIR] [--json]
Flag Meaning
--model <M> the model whose best is compared (default: the result’s model)
--record write the outcome: raise the best in baseline.json on accept, append a wiki/skill-impact.md row either way
--pr <#N> –record (required): the proposal’s pull request, #N or owner/repo#N
--pages <slug,slug> –record (required): the wiki/patterns/ pages the proposal was built on
--date <YYYY-MM-DD> –record: the row’s date (default: the result’s date)
--root <dir> the BOB_SOURCE checkout holding evals/ and wiki/ (default: the BOB_SOURCE resolver)
--json one skill-eval-gate/1 document
Exit Meaning
0 accept — strictly above the recorded best
1 reject — equal, lower, or a partial run
2 usage: not a skill-eval/1 result, a result for another item, –record without –pr or –pages, or a page that does not exist

Engine: node scripts/evals/gate.js · Issue: #2390 · Since: v1.281.0 · Read next: Skill evals

Reconcile and publish to each repo’s declared second git host (mirrors.json): resolve / reconcile / publish / verify / status — dry run without –apply (#1747).

Operator-level plumbing configured once per repo in mirrors.json and run by the release and tick paths; docs/reference/mirror-remote.md is its home — declared state, commands, safety model and how to read a status report.

bob mirror <resolve|reconcile|publish|verify|status> [project|--all] [--apply] [--local] [--ref <branch>] [--path <dir>] [--json] [--no-probe]
Flag Meaning
--all every project with an enabled mirror
--apply actually mutate (reconcile / publish are dry-run without it)
--local (reconcile) wire the local remote only, never touching the mirror host
--ref <branch> (publish / verify) this branch instead of the checked-out one
--path <dir> operate on this working copy instead of the one in projects.json
--json machine-readable output
--no-probe (status) declared state only, no network probe
Exit Meaning
0 ok
1 operational failure — unreachable, push rejected, or a stale mirror
2 declaration error — bad manifest, unknown project or host

Engine: exec scripts/cli/bob-mirror · Issue: #2059 · Since: v1.274.0 · Was: bob-mirror · Read next: Mirror remote

Forge availability classified from real gh call outcomes — operational / degraded / unreachable / unknown; the exit code is the answer (#1748).

bob forge health [status|record|observations|reset] [--json] [--no-probe] [--ttl <s>] [--window <s>]
Flag Meaning
--json machine-readable status
--no-probe never probe; classify from the observation window alone
--ttl <s> how long a probe result is trusted
--window <s> the observation window
Exit Meaning
0 operational
3 degraded — an empty result cannot be trusted
4 unreachable
5 unknown — no evidence and probing suppressed

Engine: exec scripts/cli/forge-health · Issue: #2059 · Since: v1.274.0 · Was: forge-health · Read next: Forge health

The durable write-ahead queue of issue mutations the forge could not take — status / list / show / resolve / drop / replay / clear; replay is dry-run by default, –apply delivers (#1750); an edit with an empty body is never queued or replayed, and drop sets one entry aside (#3186).

bob forge queue [status|list|show <id>|resolve <id>|drop <id>|replay [--apply]|clear] [--json]
Flag Meaning
--apply (replay) deliver the spooled mutations instead of previewing
--json machine-readable output
Exit Meaning
0 nothing pending, or replay drained cleanly and completely
3 (replay) something was skipped, failed, or left pending; (drop) no such pending entry

Engine: exec scripts/cli/forge-queue · Issue: #2059 · Since: v1.274.0 · Was: forge-queue · Read next: Forge health

Publish one site-publish/1 bundle to the operator’s site — the one publisher to it (#3103, decision on #3098): a producer (bob brief, release notes) hands over a section path and its files; the publisher refuses a file outside the section (exit 2), an undeclared section or one neither Access-gated nor public, a gated section any served host exposes without Access (#2895), an unresolvable Cloudflare account (#2984), and a live site built from a commit origin does not hold (#4418), then commits, pushes and deploys from a clean checkout of the declared target. Report-only without –apply; the site is config/site-publish.json in the operator repo.

bob site publish <bundle-dir> [--apply] [--deploy] [--force-live] [--json]
Flag Meaning
--apply copy, commit, push and deploy; without it the plan and the gate probes are printed and nothing is written
--deploy with –apply, redeploy even when nothing changed
--force-live deploy even when the live site was built from a commit origin does not hold, or what it was built from cannot be read (#4418) — the deploy replaces the whole site
--json one site-publish/1 document — section, producer, files added / updated / unchanged / orphaned, gate probes, deploy account, commit, deploy
Exit Meaning
0 reported, published or unchanged
2 usage, an invalid bundle, or a bundle file outside its section
3 no site declared, an invalid site, a refusal (undeclared section, ungated, exposed host, account) or a git failure
4 the deploy failed after the push landed

Engine: node scripts/site/publish.js publish · Issue: #3103 · Since: v1.276.0 · Read next: Add a site producer

Print the resolved operator profile and which rung found it — $BOB_OPERATOR → the $BOB_HOME/.bob-operator pointer → ~/projects/bob-operator — after validating operator.json against schemas/operator.schema.json (#2267, decision #2266).

bob operator show [--json]
Flag Meaning
--json one bob-operator/1 document — resolution rungs, root, validity, the profile when valid
Exit Meaning
0 resolved and valid
2 invalid profile — missing, unparseable or failing the schema; or usage
3 no operator declared — unresolved on every rung

Engine: node scripts/operator/operator.js show · Issue: #2267 · Since: v1.274.0 · Read next: Set up your operator repo

Scaffold an operator repo from templates/operator/ — operator.json, machines.json, provisions/, README, .gitignore and the validate workflow that runs BoB’s validators — git-init it, and write the $BOB_HOME/.bob-operator pointer only with –link (#2267).

bob operator init <dir> [--id <slug>] [--label <name>] [--forge-host <host>] [--forge-owner <owner>] [--upstream <owner/repo>] [--link] [--force] [--into-existing] [--json]
Flag Meaning
--id <slug> the operator id (default: the directory’s basename, kebab-cased)
--label <name> the display name (default: the id)
--forge-host <host> forge hostname (default github.com)
--forge-owner <owner> the forge account or org that owns the operator’s repos (default: the id)
--upstream <owner/repo> the BoB source repo this operator installs from (default: the declared BoB upstream, scripts/bob/upstream.json)
--link also write $BOB_HOME/.bob-operator pointing at <dir> — the only way init touches BOB_HOME
--force rewrite the scaffold files in a directory that already holds operator.json
--into-existing scaffold into an existing git repo that already has tracked files (refused without it); never overrides the refusal of the BoB source checkout, BOB_HOME or a BoB worktree (#2627)
--json one bob-operator-init/1 document
Exit Meaning
0 scaffolded
1 refused — <dir> is inside the BoB source checkout, BOB_HOME or a worktree of the BoB repo (no override); already an operator repo (–force); an existing repo with tracked files (–into-existing); a bad id; or the scaffold failed validation
2 usage

Engine: node scripts/operator/operator.js init · Issue: #2267 · Since: v1.274.0 · Read next: Set up your operator repo

Move the operator data out of the BoB source checkout into the resolved operator repo WITH HISTORY — machines.json, mirrors.json, config/cloudflare-accounts.json, apps/intake/config/ and every provisions/*.json except the product’s _bob-home.json and _default.json: git format-patch –root from the source, git am –3way in the operator repo, then the files removed from the source on the branch chore/2270-move-operator-data for a PR; dry run by default (#2270).

bob operator migrate [--source <bigbrain checkout>] [--apply] [--force] [--json]
Flag Meaning
--source <dir> the BoB source checkout to move from (default: the resolved BOB_SOURCE)
--apply perform the move; without it the plan is printed and nothing changes
--force replace files the operator repo already holds (a real machines.json included)
--json one bob-operator-migrate/1 document — source, operator, paths with commit counts, keep list, notes
Exit Meaning
0 planned or moved
1 refused — a dirty tree, an existing file or branch, a git failure (am aborted, nothing applied)
2 usage
3 no operator repo resolved

Engine: node scripts/operator/operator.js migrate · Issue: #2270 · Since: v1.274.0 · Read next: Set up your operator repo

Verify every secret the operator profile declares is PRESENT on this machine and name its source — env / file / keychain / gh-secret / op probed for existence and metadata only, never a value (#2286): each secret is present, missing, insecure (a file readable by group or others) or unknown (a missing or unauthenticated op / gh CLI, no present_at locator) with a one-line fix; exit 1 when a required secret is not present.

bob secrets check [--json]
Flag Meaning
--json one bob-secrets/1 document — the operator, counts, one row per declared secret (name, kind, ref, state, source, fix); never a value
Exit Meaning
0 every required secret is present (an unrequired gap is reported, never graded)
1 a required secret is missing, insecure or unknown
2 invalid operator profile, or usage
3 no operator resolved — bob operator init <dir> –link

Engine: node scripts/security/secrets.js check · Issue: #2286 · Since: v1.274.0 · Read next: Check your secrets

Grade the iBoB terminal kit read-only (#2291, cap #2289): the declared phone setup in the operator repo’s config/ibob-kit.json — schema, every target a machines.json id, every device key in secrets-inventory.json and operator.json secrets[] — then, for each target machine, reachable over the tailnet, SSH accepted (macOS Remote Login reported, never enabled), each device key authorized, mosh-server and tmux present, and the live warp/cdfork sessions listed; every failure names its fix.

bob ibob check [--machine <id>] [--json]
Flag Meaning
--machine <id> probe one target machine only
--json one ibob-kit/1 document — the kit file, the declaration rows and one row per machine with its checks, fixes and sessions
Exit Meaning
0 converged — every declaration row and every machine check passes
1 drift — a missing or invalid kit, an undeclared key, or a machine check failed
2 usage

Engine: node scripts/ibob/kit.js check · Issue: #2291 · Since: v1.281.0

List the live warp and cdfork tmux sessions on one fleet machine and print, for each, the exact command to type in the phone client (mosh or ssh, from the kit’s declared client) to attach to it (#2291). One SSH call through the fleet transport; the sessions are enumerated by seg-windows.js on the target.

bob ibob attach <machine> [--json]
Flag Meaning
--json one ibob-attach/1 document — the machine and each session with its command
Exit Meaning
0 at least one session listed
1 nothing to attach to, or the machine could not be reached (the fix is printed)
2 usage

Engine: node scripts/ibob/kit.js attach · Issue: #2291 · Since: v1.281.0

What this machine’s model-route working key has used against its limit (#3590, cap #3866): one request to the route for the key’s own state — its label, usage, limit and what is left this period — read with the working key from the environment or the keychain. The key value is never printed.

bob route status [--route <name>] [--json]
Flag Meaning
--route <name> the route to report (default openrouter; the routes are declared in scripts/route/routes.json)
--json one bob-route/1 document — route, key label, usage_usd, limit_usd, remaining_usd, limit_reset; never a value
Exit Meaning
0 the key’s state was read
1 the route’s API failed
2 usage, or an unknown route
3 no working key on this machine, or the route rejected it

Engine: node scripts/route/route.js status · Issue: #3590 · Since: v1.279.0

Create this machine’s model-route working key with the management key (#3590): named bob-<machine id>, limited to the monthly amount the machine’s machines.json entry declares (routes.<route>.monthly_limit_usd, enforced by the route), and stored in this machine’s keychain — a dry run without –apply. The key value is never printed. A key of that name that already exists is left alone; –replace deletes it and mints again. A key that cannot be stored is deleted again.

bob route mint --machine <id> [--route <name>] [--apply] [--replace] [--json]
Flag Meaning
--machine <id> the machine the key is for — it must be the machine this runs on
--route <name> the route to mint for (default openrouter)
--apply create and store the key; without it, report what would be created
--replace with –apply: delete the existing key of that name first, for a machine that no longer holds its value
--json one bob-route/1 document — machine, key name, limit_usd, verdict, stored_at; never a value
Exit Meaning
0 minted, already present, or a dry run
1 the route’s API failed, or the key could not be stored
2 usage, an unknown machine, a machine with no declared limit, or not this machine
3 no management key on this machine, or a key exists whose value this machine does not hold

Engine: node scripts/route/route.js mint · Issue: #3590 · Since: v1.279.0

Every model role BoB declares (#1231, cap #3866) — default, reasoning, fast, cheap — with the Claude Code alias agents name for it and its candidates in the order they are tried, each a model on the subscription or a route, marking any switched off: routes.<name>.enabled: false in scripts/route/routing.json, or BOB_ROUTING_DISABLE for this run.

bob route roles [--json]
Flag Meaning
--json one bob-failover/1 document — every role, its alias and its candidates with in_play and out_reason
Exit Meaning
0 the roles were listed
2 scripts/route/routing.json does not load (each problem is named)

Engine: node scripts/route/failover.js roles · Issue: #1231 · Since: v1.281.0

Run a headless command on a model role with failover (#1231, cap #3866): start it on the role’s first candidate in play; when it exits non-zero and its output shows a Claude API failure — the usage limit, a 429, a 5xx or overloaded API, a retired model — or a route refuses before it starts (key at its limit, no key), start it again on the next candidate. Any other failure is the command’s own and is returned as it is. Each failover prints one line, tells the command what it fell back from (BOB_ROLE_FALLBACK_FROM) and is recorded in $BOB_HOME/route-failover.jsonl. BOB_ROUTING_DOWN=<route>[:<model>] simulates an outage. A route is per process, so failover restarts the command; an interactive session is never run through it.

bob route run --role <role> [--cwd DIR] [--result FILE] [--fresh-session-id] -- <command> [args…]
Flag Meaning
--role <role> the role to run on (bob route roles lists them)
--cwd DIR the project to run in (default the current directory)
--result FILE write a bob-failover/1 document: the candidate the command ran on, and every attempt
--fresh-session-id give each restart of a command that passes –session-id <id> a new id, recorded on its attempt in –result
Exit Meaning
0 the command succeeded
2 usage, an unknown role, or routing.json does not load
3 every candidate failed over or was out of play — nothing ran to completion
* the command’s own exit, when it failed for a reason that is not the model’s

Engine: node scripts/route/failover.js run · Issue: #1231 · Since: v1.281.0

The newest model failovers on this machine (#1231): when, which role, the candidate that failed and why (its class and the matched text), what it fell back to, and the project — read from $BOB_HOME/route-failover.jsonl, which bob route run appends to.

bob route failovers [--limit N] [--json]
Flag Meaning
--limit N how many records to show (default 20)
--json one bob-failover/1 document — the log path and the records
Exit Meaning
0 the records were printed, or none were recorded

Engine: node scripts/route/failover.js log · Issue: #1231 · Since: v1.281.0

Check this machine’s Cloudflare working token (#3583, cap #3581): the project’s account — its manifest _meta.cloudflare_account, else the operator’s default_account in config/cloudflare-accounts.json — the working token that account names as its credential, read from the environment or the keychain, and one GET /accounts/{id}/tokens/verify: prints the account id, the token name and its status. With –write it also creates and deletes a KV namespace bob-verify-<timestamp> in the account and shows that a read of every other declared account with the same token is refused. The token value is never printed.

bob cloudflare verify [--cwd <dir>] [--account <key>] [--write] [--json]
Flag Meaning
--cwd <dir> the project whose account to use (default the current directory)
--account <key> an account key from config/cloudflare-accounts.json, in place of the project’s
--write also create and delete a KV namespace in the account, and read every other declared account to show it is refused
--json one bob-cloudflare/1 document — account, account_id, token, status; never a value
Exit Meaning
0 the working token is active in the account
1 the Cloudflare API failed
2 usage, or an unknown account
3 no working token on this machine, or Cloudflare rejected it
4 –write: the token could not write in its account, or another account answered it

Engine: node scripts/cloudflare/cloudflare.js verify · Issue: #3583 · Since: v1.282.0

Create this machine’s Cloudflare working token with the operator’s root token (#3583): named bob-<machine id>, scoped to the account and all its zones, holding every permission group Cloudflare lists except the API Tokens groups, and stored in this machine’s keychain under the account’s credential name — a dry run without –apply. The token value is never printed. A token of that name that already exists is left alone; –replace deletes it and mints again. A token that cannot be stored is deleted again. When Cloudflare refuses to let the root token grant some groups, it exits 4 naming them and files one todo for a dashboard-built token; a second run files no second todo.

bob cloudflare mint --machine <id> [--account <key>] [--apply] [--replace] [--json]
Flag Meaning
--machine <id> the machine the token is for — it must be the machine this runs on
--account <key> an account key from config/cloudflare-accounts.json (default the default_account)
--apply create and store the token; without it, report what would be created
--replace with –apply: delete the existing token of that name first, for a machine that no longer holds its value
--json one bob-cloudflare/1 document — machine, account_id, token, groups, excluded, verdict, stored_at; never a value
Exit Meaning
0 minted, already present, or a dry run
1 the Cloudflare API failed, or the token could not be stored
2 usage, an unknown machine or account, or not this machine
3 the root token is missing or rejected, or a token exists whose value this machine does not hold
4 Cloudflare refused to let the root token grant some permission groups — the todo for a dashboard-built token is filed, or already open

Engine: node scripts/cloudflare/cloudflare.js mint · Issue: #3583 · Since: v1.282.0

Agent active-hours from the Claude Code transcripts on this machine, one clock per project (#4420, cap #3135): every session transcript under ~/.claude/projects/<slug>/ (a Task subagent’s transcript under <session>/subagents/ folded into its parent session) is turned into active spans by the gap rule — consecutive transcript events closer than G (gap_minutes in the operator repo’s config/billing.json, else 10 minutes, else –gap; the report says which) form one span, a longer gap is idle — and the tool rule — the interval from a tool_use to its own tool_result is never idle, whatever its length. The spans of every session on one project (parallel terminals, bob fork worktrees, subagents) are unioned, so a project never accrues more than one hour per wall-clock hour. Prints hours per project per day over the window (–since, default the last 7 days, to –until, default now), one block per project that has a transcript in the window, or the one –project named (zero hours when it has none). Report only — nothing is filed, priced or billed; forward-only by decision on #3135, a historical number is one –since run over the transcripts that survive. With –fleet (#4422) the same hours and list-price COGS per machine and in total, for one –project or every project, read from the fleet snapshots each machine publishes (summary.labor, from this meter and the token ledger priced by token-report.js) — a machine is fresh, stale (its newest snapshot older than 24 h) or never (none), its figures add across machines, and the total is labelled partial whenever a machine is stale, never or carries no labor read; nothing is read live. With –by job (#4423) every project’s hours are grouped under the client job its manifest’s _meta.billing names ({job, billable}; BoB’s own projects declare overhead, not billable — #3134), and a project with no _meta.billing is listed under unbilled (unmapped) with the manifest and the key to add, never silently dropped and never silently billed.

the meter has one invocation shape and its rules are the content — docs/reference/work-attribution.md documents it; the how-to arrives with the pricing and export slices of #3135

bob labor report [--project <name|path>] [--since <iso>] [--until <iso>] [--gap <minutes>] [--projects-dir <dir>] [--by project|job] [--json] | bob labor report --fleet [--project <name>] [--json]
Flag Meaning
--project <name|path> one project only — its name (what project-name.js resolves a checkout to), a transcript-directory slug, or a checkout path; reported with zero hours when no transcript falls in the window
--since <iso> the start of the window (a date is its local midnight); default the local midnight six days before –until
--until <iso> the end of the window; default now
--gap <minutes> G for this run, over billing.json and the default; the document names the source as flag
--projects-dir <dir> read transcripts from this directory instead of ~/.claude/projects — an archived transcript tree for a one-off historical run
--by project|job project (default): one block per project; job: one block per client job from each project’s manifest _meta.billing {job, billable} (operator repo, provisions/<project>.json), then unbilled (unmapped) listing every project in the window with no billing block and the key to add; a malformed block counts as unmapped. Not with –fleet (exit 2).
--fleet hours and COGS per machine and in total from the fleet snapshots in $BOB_FLEET_SNAPSHOTS (else <BOB_HOME>/fleet/snapshots), each machine fresh / stale / never, the total partial when any is stale, never or unread; –since, –until, –gap and –projects-dir do not apply (exit 2)
--json one bob-labor/1 document on stdout: generated_at, projects_dir, window {since, until}, gap_minutes, gap_source {source: billing.json | default | flag, path}, project (the selector, or null), rules, counts {transcript_dirs, projects, sessions}, projects [{project, transcript_dirs, hours, sessions [{id, file, events, subagents, spans, hours}], spans [{start, end, hours, sessions}], days [{date, hours, spans, sessions}]}], error; with –fleet one bob-labor-fleet/1 document: generated_at, snapshots_dir, stale_after_seconds, project, machines [{id, role, status, generated_at, age_seconds, readable, reason, window, hours_30d, usd_30d, qualified, unrecorded}], projects [{project, by_machine, hours_30d, usd_30d, qualified, unrecorded, partial, partial_reasons}], counts, partial, partial_reasons; with –by job also by: job, jobs [{job, billable, hours, projects [{project, hours, billable, manifest}]}] and unmapped {hours, projects [{project, hours, manifest, reason, fix}]}
Exit Meaning
0 reported — a project with no transcript in the window is reported with zero hours
2 usage: a bad flag or date, a –gap that is not a positive number, or an unparsable config/billing.json (named; the gap is never silently defaulted over it); a meter flag beside –fleet; a –by that is not project or job

Engine: node scripts/labor/labor.js report · Issue: #4420 · Since: unreleased · Read next: bob labor

Every transcript on this machine has one priced record in the token ledger (#4421, cap #3135): each session transcript under ~/.claude/projects/<slug>/ written since the window opened (–since, default 30 days) is classified against the ledger’s session records by session id — recorded, unrecorded (no record and at least one priced API response: a session killed with its tmux window, a crash, a sleep, or one from before the SessionEnd hook existed), settling (no record but written inside –settle minutes, default 60: the session may be live or its hook still measuring — listed, never recorded) or empty (nothing to price). Without –apply, one line per unrecorded transcript (project, session id, last event, response count) and a summary; –apply appends one type: session record per unrecorded transcript — kind interactive, source reconcile, measured by token-snapshot.js the way every other writer measures (per-response counting #4204, provenance #1806), stamped at the transcript’s last event — and a second –apply appends nothing. One record per session id in both directions: the reconcile refuses a session any record names, and the SessionEnd hook refuses a session the reconcile recorded, naming it. The fleet snapshot and bob tick run it with –apply; bob status –scope project and bob doctor print the count.

the pass runs unattended inside the fleet snapshot and bob tick, and by hand only as the fix bob status and bob doctor name — docs/reference/token-monitoring.md documents it

bob labor reconcile [--apply] [--project <name>] [--since <iso>] [--settle <minutes>] [--projects-dir <dir>] [--json]
Flag Meaning
--apply append the records; without it, report what would be written
--project <name> one project only — its checkout name or its transcript-directory slug
--since <iso> the start of the window, by transcript write time (a date is its local midnight); default 30 days ago — a one-off over surviving history is one wide –since run
--settle <minutes> a transcript written more recently than this is settling and is listed, not recorded (default 60; 0 records everything)
--projects-dir <dir> read transcripts from this directory instead of ~/.claude/projects
--json one bob-labor-reconcile/1 document on stdout: apply, ledger, projects_dir, window, settle_minutes, project, counts {transcripts, recorded, unrecorded, settling, empty, written, failed}, by_project {name: the same counts}, unrecorded [{session_id, project, dir, cwd, first_event, last_event, responses, model, mtime}], settling [the same, with settles_at], written [{session_id, project, timestamp, message_count, total_tokens, model}], failed [{session_id, reason}], ok, error
Exit Meaning
0 no unrecorded transcript is left in the window
1 one or more unrecorded transcripts (report only), or –apply could not price one
2 usage: a bad flag, date or settle value

Engine: node scripts/labor/labor.js reconcile · Issue: #4421 · Since: unreleased · Read next: bob labor

Which rituals are overdue, due or upcoming per project — the declared _meta.rituals schedule or liveness-scaled defaults, last run derived from closed ritual-run issues (#2230, #2231); a guide walkthrough is listed for each guide whose requirement still has the acceptance criterion that asked for it unticked (#3809).

bob ritual due [--project <p> | --all] [--json] [--repo owner/name] [--now YYYY-MM-DD] [--window P14D] [--runs FILE] [--snapshots DIR]
Flag Meaning
--project <p> one project, by _meta.project or manifest file name
--all every active project manifest
--window <duration> how far ahead counts as due (default P14D)
--runs <file> last-run dates instead of the forge read
--json one bob-rituals-due/1 document
Exit Meaning
0 nothing overdue
1 at least one ritual overdue
2 usage or config error

Engine: node scripts/rituals/ritual.js due · Issue: #2230 · Since: v1.274.0 · Read next: Hold a ritual

Start the attended session of a ritual: resume its open run issue or open one, refuse a kit the machine role forbids (#2228), apply the ritual kit to the project checkout as a provision overlay, then print the evidence packet summary, the checklist the run embeds (#2241) and the previous run findings (#2234).

bob ritual run <ritual> [--project <p>] [--drill <name> | --drill-kind <kind>] [--machine <id>] [--guide <name|file>] [--repo owner/name] [--no-kit] [--dry-run] [--json]
Flag Meaning
--ritual <name> the ritual, instead of the positional name
--project <p> the project (default: the one whose _meta.path holds the current directory)
--drill <name> a BoB-level drill — restore, lost-laptop or farm-compromise — held on its home (bigbrain); its kind and runbook come from registry/rituals.json (#2240)
--drill-kind <kind> a project’s own drill: restore, failover, credential-rotation or incident-response (required for drill without –drill)
--machine <id> the machines.json id a drill rehearses losing or rebuilding — required by lost-laptop, whose run body embeds that machine’s inventory-generated revocation list
--guide <name|file> guide-walkthrough only (#3809): the guide to walk — one the vocabulary lists, by name or by file, or any other .md file; the body carries the three-item walkthrough checklist
--repo owner/name the repo holding the runs (default: the checkout github.com origin)
--no-kit resume or open the run without applying the kit overlay
--dry-run open nothing and apply nothing — report the run it would resume or open
--json one bob-ritual-run/1 document: verdict, issue, url, opened, kit, checkout, machine, overlay, packet, previous {date, issue, findings}, error
Exit Meaning
0 started, resumed, or –dry-run
2 usage or config error — unknown ritual or project, no checkout here without –no-kit
3 refused — this machine role forbids the ritual kit
4 not started — the forge could not be read, refused the create or spooled it
5 the run is open but its kit overlay could not be applied

Engine: node scripts/rituals/ritual.js run · Issue: #2234 · Since: v1.274.0 · Read next: Hold a ritual

File one ritual-run issue with the standard body (marker, scope, kit, the declared checklist embedded as tickable items at its version (#2241), evidence placeholder, findings checklist, delta against the previous run) after refusing a duplicate open run of the same ritual (#2231).

bob ritual open <ritual> [--project <p>] [--drill <name> | --drill-kind <kind>] [--machine <id>] [--guide <name|file>] [--replaces <todo>]... [--repo owner/name] [--held-on YYYY-MM-DD] [--dry-run] [--json]
Flag Meaning
--ritual <name> the ritual, instead of the positional name
--project <p> the project (default: the one holding the current directory)
--drill <name> a BoB-level drill — restore, lost-laptop or farm-compromise — filed on its home (bigbrain); the body carries the runbook’s timed checklist and an Outcome table (#2240)
--drill-kind <kind> a project’s own drill kind — required for drill without –drill, refused on any other ritual
--machine <id> the machines.json id the drill rehearses; required by lost-laptop, whose body embeds the machine’s revocation list from secrets-inventory.json
--guide <name|file> guide-walkthrough only (#3809): the guide to walk — one the vocabulary lists, by name or by file, or any other .md file; the body carries the three-item walkthrough checklist
--replaces <todo> guide-walkthrough only, repeatable (#3809): a to-do that asked the operator to follow the guide — once the run exists it gets a comment linking the run and is closed as not planned, without completed
--held-on YYYY-MM-DD the held_on stamped in the marker (default today, UTC)
--dry-run print the title, labels and body; file nothing
--json one bob-ritual-open/1 document
Exit Meaning
0 filed, queued, –dry-run, or every –replaces to-do converted onto the run
2 usage or config error
3 a run of this ritual is already open
4 nothing filed — the forge could not be read or refused the create; or a –replaces to-do could not be closed

Engine: node scripts/rituals/ritual.js open · Issue: #2231 · Since: v1.274.0 · Read next: Hold a ritual

Gather a run evidence packet report-only and post (or replace) it as one comment on the run issue; –due prepares every farm-eligible ritual due soon, what bob tick runs (#2233).

bob ritual prepare <run-issue> [--project <p>] [--repo owner/name] [--budget-seconds N] [--dry-run] [--json] | bob ritual prepare --due [--project <p> | --all] [--within P2D] [--budget-seconds N] [--dry-run] [--json]
Flag Meaning
--due prepare every farm-eligible ritual overdue or due within –within instead of one run issue
--within <duration> (–due) the due window (default P2D)
--budget-seconds <N> bound the whole gathering pass
--dry-run gather and print (one run) or list the targets (–due); post nothing
--json one bob-ritual-prepare/1 (or bob-ritual-prepare-due/1) document
Exit Meaning
0 posted, updated, queued, or –dry-run (–due: every target prepared)
1 (–due) at least one target not prepared
2 usage or config error
3 nothing to prepare — the run is closed or declares no collectors
4 nothing posted — the forge could not be read or refused the write

Engine: node scripts/rituals/ritual.js prepare · Issue: #2233 · Since: v1.274.0 · Read next: Hold a ritual

Close a held ritual run with durable outputs: every finding links a bug, req, task, security or todo issue or says no-action (an empty run needs –no-findings, recorded), lessons and decisions are linked /journal issues never labels on the run (#2062), a checklist run records its version and the items not assessed and is refused with nothing ticked (#2241), and the closed body carries the delta against the previous run (#2234).

bob ritual close <run-issue> [--project <p>] [--repo owner/name] [--finding N]... [--no-action "<why>"]... [--journal N]... [--no-findings] [--held-on YYYY-MM-DD] [--dry-run] [--json]
Flag Meaning
--finding <N> a finding issue to add to the checklist (repeatable)
--no-action <why> a finding that needs nothing, with its reason (repeatable)
--journal <N> a /journal lesson or decision issue to link under Journal (repeatable)
--no-findings close a run with an empty checklist, recording that it found nothing
--held-on YYYY-MM-DD the day the ritual was held (default: the run marker)
--dry-run run every check and print the closed body; write nothing
--json one bob-ritual-close/1 document: verdict, findings, journal, no_findings, delta {previous, resolved, recurring, new}, problems, body, error
Exit Meaning
0 closed, queued, or –dry-run
2 usage or config error — not a ritual-run issue, a project mismatch, a bad issue number
3 refused (each problem named; the run stays open) or already closed
4 the forge could not be read or refused the write
5 closed, but the kit overlay stamped with the run could not be restored

Engine: node scripts/rituals/ritual.js close · Issue: #2234 · Since: v1.274.0 · Read next: Hold a ritual

Write a portfolio-review decision into a project manifest: _meta.portfolio invest / maintain / park / archive, the dormant default cadence for a parked or archived project (and active: false for archive), only _meta rewritten in the file’s own style, projects.json regenerated when active changes; an archive is carried out on GitHub too — the repo is archived, never deleted, and un-archived when the project is revived (#3609) — report-only without –apply (#2235).

bob ritual decide <project> <invest|maintain|park|archive> [--apply] [--repo owner/name] [--keep-repo] [--json]
Flag Meaning
--apply write the manifest (and projects.json when active changes) and archive or un-archive the GitHub repo; without it, report what would change
--repo owner/name the GitHub repo to archive, when the project has no checkout on this machine and its manifest names no remote
--keep-repo record the decision and leave GitHub alone (a repo someone else owns)
--json one bob-ritual-decide/1 document
Exit Meaning
0 applied, unchanged, or a report without –apply
2 usage or config error
4 the manifest was written but projects.json could not be regenerated
5 the manifest was written but the GitHub repo was not archived

Engine: node scripts/rituals/ritual.js decide · Issue: #2235 · Since: v1.274.0 · Read next: Hold a ritual

The portfolio sweep (#3609): inventory every directory under ~/projects and ~/Sites on every fleet machine — this one directly, the others over Tailscale SSH, nested repos included, a machine that cannot be reached named as not inventoried — into the operator repo’s portfolio.json; decide records one outcome per row (invest / maintain / park / archive / scrap / not-a-project); status lists the rows still undecided; apply carries the decisions into the manifests — bob ready for a directory with no manifest, the manifest path corrected to the decided row, bob ritual decide — report-only without –apply; scrap prints the deletion list per machine, takes one approval of that exact list, and deletes only what is approved and holds nothing that exists only there; audit renders the dated audit page into the operator repo; record writes the decisions into the portfolio-review run issue.

bob ritual sweep <inventory [--write] [--machines id,id] | decide <row> <outcome> [--with <row>]... [--note "<why>"] [--discard] | status | apply [--apply] [--only <row>] | scrap [--approve <digest>] [--apply] | audit [--write] | record <run-issue> [--journal <N>] [--apply]> [--json]
Flag Meaning
--write inventory: save the list as the operator repo’s portfolio.json, keeping every decision already recorded; audit: save the dated audit there
--machines id,id inventory: scan only these machines; the rest are listed as not inventoried
--with row decide: another row decided as part of the same decision (a backup beside its original); repeatable
--note "<why>" decide: one line recorded with the decision
--discard decide <row> scrap: accept the loss of what exists only in that directory; the scrap list then says what is lost
--only row apply: carry out this one decision
--approve digest scrap: record the approval of the exact list the dry run printed
--apply apply: write the manifests and archive repos; scrap: delete what this machine removes from the approved list; record: write the run issue; without it, report
--journal N record: the /journal decision issue linked on every status change
--json one bob-portfolio/1 document, or the subcommand’s (-decide/1, -status/1, -apply/1, -scrap/1, -audit/1, -record/1)
Exit Meaning
0 inventory complete, decision recorded, every row decided, every decision carried out, or the scrap list printed, approved or removed
1 status: at least one row is undecided; apply: a decision is blocked or failed; scrap –apply: a path could not be removed
2 usage or config error, a scrap list that is not approved or changed since its approval
3 inventory: at least one machine was not inventoried
4 record: the forge could not be read or refused the write

Engine: node scripts/rituals/sweep.js · Issue: #3609 · Since: v1.279.0 · Read next: Hold a ritual

Since: the release a command first shipped in

Section titled “Since: the release a command first shipped in”

This site is built from master, which is usually ahead of the release installed on your machine. Since tells you whether a command on this page is in your release. It names the first release that included the command, linked to that release’s page. bob doctor prints the release you run on its version line. If that release is the same as or later than a command’s Since, you have the command.

  • A release tag such as v1.274.0: the first release that included the command.
  • unreleased: the command is on master, but no release includes it yet. The page never guesses the next version number.
  • unknown: this build could not read the release history. A callout at the top of the page gives the reason, for example a shallow clone or a repository with no release tags.

How it is derived. Nobody writes these values by hand, and they are never stored in scripts/bob/commands.json. scripts/bob/since.js (#2622) reads the history of the routing table, oldest commit first, and finds the first commit that declared each command, by its noun and verb. It then picks the lowest release tag whose history contains that commit. Release tags are the ones matching version.tag_pattern in docs-site.json (default v[0-9]*), the same setting the site’s build stamp uses. Moving the table file, or changing a command’s summary, engine or flags, does not change its Since. A command that is removed and added back keeps the release of its first appearance. A command whose route is renamed gets a new Since, because it is now a new route. Run node scripts/bob/since.js resolve --root . to print every value as JSON (bob-since/1).

Why the committed copy can lag. A new release changes some values from unreleased to a tag. The drift check in tests/test-bob-dispatch.sh therefore compares this page with the Since values masked out. The docs build renders the page again, so the published site always shows current values.

Some jobs can be run either from a shell with bob, or inside a Claude session with a slash command. This table lists those pairs. Everything else a session can run is in the catalogs the site build generates: slash commands, skills and agents. On GitHub, where those pages don’t exist, use the Glossary instead. To find the phrasing that triggers each one, see the Natural-Language Guide.

In a shell In a Claude session Difference
bob warp start /warp-drive bob warp start launches the run in its own tmux session from any shell; /warp-drive runs it in the session you are in.
bob warp stop /stop-warp-drive Same abort, from a shell or from the session.
bob plan build /flightplan /flightplan can interview for scope; bob plan build never asks.
bob groom /groom bob groom is the headless pass (dry run unless –apply); /groom is interactive.
bob dev up /dev-up Same engine.
bob fork /cdfork Same engine.
bob swarm /swarm Same loop.
bob decompose /capability /capability writes the parent and, at Level 2+, hands its child requirements to bob decompose, which runs the gated decomposition.
bob provision /provision Same engine; the slash command adds guidance.
bob promotion setup /setup-promotion Same scaffold.
bob deploy /deploy Same dispatcher and ceiling gate; /deploy acts on the session’s project.
bob release /release Same release engine.
bob status /status Different jobs: bob status is a health verdict; /status is a project catch-up and next-work report (/what-next –report).

The old command names (cdi, cdprov, warp and the rest) still work until 2026-09-21. Each bin/<was> is now a shim generated from this table by scripts/bob/gen-shims.sh (#2060): it prints the bob spelling once per shell (BOB_SHIM_QUIET=1 silences it) and then runs the bob command, passing arguments, stdio and exit status through unchanged. The old engines moved from bin/ to scripts/cli/ unchanged (#2059); a verb becomes an argument prefix, so bob warp status runs scripts/cli/warp status. #2091 moves the remaining callers to the new names before the shims are removed.

Was Now Engine
bob-mirror bob mirror scripts/cli/bob-mirror
bob-ready bob ready scripts/ready/ready.js
bob-reap bob reap scripts/cli/bob-reap
bob-release bob release scripts/cli/bob-release
cdb bob dash status scripts/cli/cdb
cdfork bob fork scripts/cli/cdfork
cdfork-pair bob pair scripts/cli/cdfork-pair
cdg bob dash generate scripts/cli/cdg
cdi bob init scripts/cli/cdi
cdl bob link scripts/cli/cdl
cdp bob promote scripts/cli/cdp
cdprov bob provision scripts/cli/cdprov
cds bob dash serve scripts/cli/cds
dev-health bob dev health scripts/cli/dev-health
dev-up bob dev up scripts/cli/dev-up
forge-health bob forge health scripts/cli/forge-health
forge-queue bob forge queue scripts/cli/forge-queue
setup-promotion bob promotion setup scripts/cli/setup-promotion
swarm bob swarm scripts/cli/swarm
warp bob warp status · bob warp log · bob warp config · bob warp viz · bob warp stop · bob warp reap · bob warp session · bob warp finalize scripts/cli/warp
  • bin/bob — the router itself
  • bin/bob-shell.zsh — sourceable shell integration (the claude wrapper, #1195), not an invocable entrypoint
  • bin/cdprov-interview — an alias shim for bob provision --interview (#2060; the same engine, scripts/orchestrator/interview.sh, through the gated provision path); provision is verb-less, so it cannot also carry a verb
  • bin/gh — the forge-health PATH shim (#1748) — a transparent gh, not a command of its own