Skip to content

Build master @ bc50cd5bunreleased — 31 commits past v1.282.0Last reviewed Last changed Grade fresh (aging >90d, stale >180d)Source / History

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.

Start here: the everyday commands ​

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.

text
$ 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.

Quick index ​

Daily driver ​

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

CommandWhat it does
bob doctorAssert 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 statusThe 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 asksEvery 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 briefOne 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 tourWhat 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 uBob 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 notifySend 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 vizOpen 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 controlOpen 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 … →

Set up a project ​

Bring a repo under BoB and keep its tooling converged.

CommandWhat it does
bob initInitialize 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 readyThe 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 preflightThe warp-drive preflight gate: doctor + ready --dry-run as one verdict. →
bob provisionProvision a project from its manifest — status / diff / check / refresh / prune / init / interview / detect / add / remove / decline / reconcile / overlay / untrack / ignore-paths … →
bob linkLink a global item (command, agent, hook) into the current project's .claude/, link every missing one, or list what is available. →
bob promotePromote a local .claude/ item (command, agent, hook, skill) to the global source and replace the local file with a symlink back. →
bob promotion setupScaffold a project's dev → test → prod promotion ladder — detect → dev.json → wrangler → provision handoff → todo → verify; dry run by default, --apply writes (#931). →
bob deployDeploy 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 setupRender 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 statusHow 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 runTake 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 restoreLoad 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 … →

Plan and run warp-drive ​

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

CommandWhat it does
bob groomRun 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 decomposeDecompose 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 doRun 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 buildDerive 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 remainingRunnable plan items in run order — flightplan.js remaining <N>, argv passed through unchanged. →
bob plan statusPlan 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 itemsThe plan's ordered items, todo rows marked — flightplan.js items <N>, argv passed through unchanged. →
bob warp startLaunch 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 attachAttach 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 statusShow the active warp-drive phase, issue, chunk and metrics; --watch redraws in place, --log appends the phase history. →
bob warp logThe warp-drive phase-transition history for this project. →
bob warp configShow the resolved workflow configuration (_workflow keys, kickoff options) for this project. →
bob warp vizOpen 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 stopAbort the active warp-drive session — graceful (transitions to aborted) or --hard (deletes the state file, no cleanup). →
bob warp reapGC 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 sessionThe 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 finalizeShip the integration branch to main — one PR at Level 2, rebase + merge at Level 3 (#268). →
bob forkFan 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 pairThe 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 swarmRun the full agent-swarm loop as one command — decompose → approve → capped dispatch via bob fork → gate → integrate → summary (#582). →

Dev environment and dashboards ​

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

CommandWhat it does
bob dev upBring 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 healthQuick health check of the dev environment — the shortcut for dev up --check. →
bob reapReap regenerable working-tree residue per the project's reap.json — dry run by default, --apply deletes; keep-list and liveness guards (#1664). →
bob dash statusThe tooling dashboard: global items and every registered project's symlink status, port band, warp-drive harness defects, and last bob ready verdict. →
bob dash generateGenerate a project's static dashboard (bugs, releases, changes, incidents, journal, cross-refs) into .dash/ from the current directory. →
bob dash serveStart the dashboard server for the current project on its ledger-assigned port, or list / stop running dashboards and show port allocations. →
bob serveConverge 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 … →

Release, update and the farm ​

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

CommandWhat it does
bob releaseThe 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 updateConverge 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 tickOne 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 maintainConsolidate 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 proposePropose 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 runRun 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 gateThe 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 mirrorReconcile and publish to each repo's declared second git host (mirrors.json): resolve / reconcile / publish / verify / status — dry run without --apply (#1747). →
bob forge healthForge availability classified from real gh call outcomes — operational / degraded / unreachable / unknown; the exit code is the answer (#1748). →
bob forge queueThe 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 publishPublish 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 … →

Operator and secrets ​

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.

CommandWhat it does
bob operator showPrint 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 initScaffold 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 migrateMove 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 checkVerify 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 checkGrade 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 attachList 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 statusWhat 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 mintCreate 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 rolesEvery 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 runRun 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 failoversThe 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 verifyCheck 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 mintCreate 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 … →

Work attribution ​

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

CommandWhat it does
bob labor reportAgent 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 reconcileEvery 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 … →

Rituals ​

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

CommandWhat it does
bob ritual dueWhich 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 runStart 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 openFile 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 prepareGather 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 closeClose 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 decideWrite 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 sweepThe 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 in full ​

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.

Daily driver ​

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; 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).

text
bob doctor [--json] [--project <dir>] [--section <surfaces|symlinks|toolchain|settings_hooks>[,...]]
FlagMeaning
--jsonmachine-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
ExitMeaning
0converged
1drift — the output names the remediation
2error

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

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: 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.

text
bob status [--json] [--live] | bob status --scope host|project|fleet [--json] [scope flags]
FlagMeaning
--scope <host|project|fleet>what to grade; omit it for the front door (every scope, one next: command)
--livefront door only: re-grade the project (ready --dry-run) and pull the fleet live instead of reading recorded verdicts
--jsonmachine-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-previewproject only: add rebob --report as an informational section
--no-livefleet 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)
ExitMeaning
0ok
1drift — host drift, NOT READY, or an unreachable/stale fleet machine
2error or usage error

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

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, 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.

text
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]
FlagMeaning
--jsonone 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
--allalso list the asks waiting behind the budget, under the ones inside it
--reconcilemake 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})
--applywith --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
ExitMeaning
0listed — a project that could not be read is named as a gap
1transition: the event is not one the ask's phase allows, or draft: the ask already exists — nothing changed
2usage error, no readable projects.json, or (transition, status) no such ask
3no project could be read — every forge read failed; transition admitted: refused by the admission gate, the phase did not move
4transition: 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

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 — 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.

text
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>]
FlagMeaning
--area <area:label>|allone 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>|allone 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)
--reconciletick 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)
--applywith --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-timerrender 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-timerdisable the briefing timer and remove both units (#2246)
--timer-statusthe 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-runwith --install-timer / --uninstall-timer: report what would be written and run; write and run nothing
--jsonthe briefing/1 document on stdout (schemas/briefing.schema.json); the human rendering otherwise
--writestore 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)
--sendstore 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)
--scheduleda 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|skipwhat 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)
--offlineread 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)
ExitMeaning
0built — every source read in full; with --send: delivered (or quiet and skipped)
2usage error
3built — 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)
4with --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

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 — 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.

text
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]
FlagMeaning
--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)
--allalso list the in-use items (by default only unknown and parked are listed; the counts always cover all three)
--fleetgrade 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-backfilldo 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
--applicabilitygrade 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-inferwith --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)
--jsonone 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
ExitMeaning
0tour rendered, or the choice recorded
2usage 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 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 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.

text
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]
FlagMeaning
--no-inferstatus, 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-overlayexam: 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)
--applydispose: write the record to registry/dispositions.json (without it: report only)
--jsonone 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)
ExitMeaning
0status rendered · exam supports certified · dispose record valid (written with --apply)
1status: 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
2usage error, an unknown or ambiguous item, an item with no eval suite (exam), or an unreadable record
3exam: 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

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, POSTs /notify, and prints the message instead when no bridge is configured — never lost, never a silent drop.

text
bob notify <message> [--level info|warn|block] [--project <name>] [--session-id <id>] [--cwd <dir>] [--json]
FlagMeaning
--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)
--jsonone bob-notify/1 document on stdout (the secret is never in it)
ExitMeaning
0delivered (2xx)
2usage error
3bridge not configured — message printed to stdout instead
4transport error — curl failed or the bridge answered non-2xx

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

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); each tile links to its bob warp viz card, and --tailnet serves it on this machine's Tailscale address (#2070).

text
bob viz [--tailnet] [--page briefings] [--json] | --install-service | --uninstall-service [--dry-run]
FlagMeaning
--tailnetserve 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 briefingsopen /briefings instead — the latest briefing and its history on the same server (#2244)
--jsonone 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-serviceinstall 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-servicestop and remove the dashboard service; idempotent
--dry-runwith --install-service / --uninstall-service: report what would be written and run, change nothing
ExitMeaning
0served
1no project here and no BoB source checkout, or the server failed to start; or a systemctl / launchctl step of --install-service failed
2usage 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

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 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.

text
bob control [--tailnet] [--json] | bob control runs [--json]
FlagMeaning
--tailnetserve on the Tailscale address, as bob viz --tailnet does
--jsonone 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}}]
ExitMeaning
0served; runs: printed (an empty log is zero runs)
1no project here and no BoB source checkout, or the server failed to start; runs: the log could not be read
2usage error (an unknown flag)

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

Set up a project ​

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 provision --init --auto).

text
bob init [-y|--yes] [--auto-provision] [--force] [project-dir]
FlagMeaning
-y, --yesnon-interactive: accept every default
--auto-provisionwhen no manifest exists, run bob provision --init --auto without prompting (#1161)
--forceinit even if warp-drive is active; also overrides the non-project marker check (#707) — $HOME and BOB_HOME are always refused
ExitMeaning
0initialized (or already converged)
1refused 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

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, 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.

text
bob ready [project-dir | owner/repo | --all] [--new] [--start] [--vision <file|->] [--dry-run] [--json] [--name <project-name>]
FlagMeaning
--allgrade every project projects.json declares that is checked out on this machine — one table, each verdict persisted (#2068)
--dry-runreport what each step would do; mutate nothing
--jsonmachine-readable verdict (schema project-ready/1; project-ready-all/1 with --all)
--name <project-name>override the project name used for the provisions manifest
--newcreate the forge repo for a directory that already has files (a missing or empty directory gets one without it) (#3158)
--startonce 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)
ExitMeaning
0READY
1NOT READY — each blocker names its fix; with --all, any present project NOT READY
2usage error

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

bob preflight ​

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).

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

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

bob provision ​

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.

text
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]
FlagMeaning
--statusthe current provisioning state (exit 3 on drift)
--contextwith --status: the description tokens a session here loads — global set, project manifest, manifest + each kit — per item type; --json = bob-context-cost/1 (#2229)
--diffdry run — what would change, with a why: line per recommended item (#1879); --json = the explain.js document
--checkIaC compliance check: drift and undeclared items
--refreshre-provision from the manifest (the default action)
--initgenerate the manifest from stack detection; --auto = detect → write → refresh with no prompts (#506)
--interviewthe orchestrator interview (#163) — the same engine bin/cdprov-interview wraps
--pruneremove dangling BoB symlinks (#304)
--untrackuntrack 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-pathsprint the path set the managed ignore block covers here (bob-ignore-paths/1 with --json) — read-only; what untrack selects against (#2536)
ExitMeaning
0converged, applied, or dry run printed
1failure — a refused write, a broken link, or an engine error
2usage error
3drift (--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.

text
bob link <type> <name> | --all | --list [type]
FlagMeaning
--alllink every missing global item
--list [type]list the available global items, optionally one type
ExitMeaning
0linked or listed
1usage 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

bob promote ​

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

text
bob promote <file>
ExitMeaning
0promoted and linked back
1usage 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

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).

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

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

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 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).

text
bob deploy [--env test|prod] [--dry-run] [--project <dir>] [--adapter <name>] [--skip-tests] [--skip-build] [--skip-backup] [--force] [--list]
FlagMeaning
--env <test|prod>target environment (default prod)
--dry-runrun 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-testsskip the contract's check step
--skip-buildskip the contract's build step
--skip-backupmigrate without the pre-migrate backup — the explicit override, printed as a warning (#3087)
--forcebypass the promotion-ceiling gate — a deliberate human override
--listlist the available adapters and exit
ExitMeaning
0deployed, or the dry run printed
1a contract step failed, or a usage error
3refused — 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

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 <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.

text
bob backup setup [--project <dir>] [--env <env>] [--apply] [--json]
FlagMeaning
--project <dir>project root (default: the current directory)
--env <env>the environment whose backup block to render (default prod)
--applywrite the Worker, create the bucket and set the lifecycle rules; without it, print the plan
--jsonone bob-backup-setup/1 document: files, bucket and rules with their action, changed, next steps
ExitMeaning
0planned, or applied and converged
1a wrangler step failed under --apply
2usage
3the 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

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 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).

text
bob backup status [--project <dir>] [--json]
FlagMeaning
--project <dir>project root (default: the current directory)
--jsonone bob-backup-status/1 document: verdict and, per env, newest, age_seconds, expected_by, drill, fresh, reason
ExitMeaning
0every declared backup is fresh
1a backup is stale — older than the schedule allows, absent or unreadable
2usage
3no 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

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 latest/<db>.json pointer names a dump taken after the trigger. The primitive the deploy path's backup-before-migrate calls.

text
bob backup run [--project <dir>] [--env <env>] [--timeout <min>] [--json]
FlagMeaning
--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)
--jsonone bob-backup-run/1 document: ok, worker, instance, sidecar, waited_seconds, error
ExitMeaning
0the new dump landed
1the trigger failed, or no new dump within --timeout
2usage
3no 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

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 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.

text
bob backup restore [--project <dir>] [--env <env>] [--from <key>] [--i-understand-this-overwrites-prod] [--json]
FlagMeaning
--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-prodwith --env prod above automation Level 1: allow the prod restore, still only after the typed confirmation
--jsonone bob-backup-restore/1 document: from, target, dropped, counts, rto_seconds, drill, error
ExitMeaning
0restored and every row count matches the sidecar
1a step failed, or a row count differs
2usage
3no backup declared, or the declaration, wrangler config or restore target is missing or invalid (named on stderr)
4refused 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

Plan and run warp-drive ​

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 (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.

text
bob groom [--area <slug> | --issues N,N | --all] [--apply] [--timeout <min>] [--route <name>[:<model>]] [--cwd <dir>] [--json]
FlagMeaning
--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
--allevery open cluster (bare /groom) — the default
--applyLevel 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)
--jsonone bob-groom/1 document on stdout: scope, mode, level, timed_out, claude_exit, result {groomed, approved, blocked, todos, deferred}, output, verdict, exit
ExitMeaning
0groomed
1the groom reported blockers (blocked>0), or produced no GROOM-RESULT summary line
2usage or config error — bad flag, two scopes, no groom.md, the Level 3 switch failed
3claude unavailable (not on PATH) or it failed to run
4killed at --timeout

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

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 → 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).

text
bob decompose <N> | status | transition <event> [--data JSON | --file F] | stop   [--cwd <dir>] [--json]
FlagMeaning
--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)
--jsonone 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
ExitMeaning
0started, advanced, or status printed
1invalid transition from the current phase, or a run already active
2usage error, or no decompose run in this checkout
3refused 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

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 · 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).

text
bob do "<question>" [--artifact <type>] [--budget <N>m|<N>t|<N>k] | status | transition <event> [--data JSON] | stop   [--cwd <dir>] [--json]
FlagMeaning
--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>kthe 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:
--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)
--jsonone 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
ExitMeaning
0started, advanced (discarded included), stopped, or status printed
1invalid transition from the current phase, or a run already active
2usage error, or no do run in this checkout
3refused 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

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. Without --allow-unapproved un-approved work is never seated (the engine names each dropped issue).

text
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]
FlagMeaning
--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-afterclear the plan's declared predecessor(s) → flightplan.js --no-after
--allow-unapprovedseat issues lacking approved (off by default)
--allow-overlapwith --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)
--jsonthe engine's JSON document: plan, scope, items, dropped, unapproved …
ExitMeaning
0plan created or refreshed
1the engine rejected an argument (e.g. a non-git-safe --branch)
2usage error — unknown flag, two scope sources, bad --from — or a gh/repo error from the engine
3refused: 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

bob plan remaining ​

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

text
bob plan remaining <N> [--json] [--all]
FlagMeaning
--jsonan ARRAY of runnable items (the warp-drive consumer contract)
--allwiden --json to
ExitMeaning
0printed
1usage — missing/invalid <N>, or a broken depends_on declaration
2gh/repo error

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

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 unchanged.

text
bob plan status <N> [--json]
FlagMeaning
--jsonmachine-readable status document
ExitMeaning
0printed
1usage — missing/invalid <N>
2gh/repo error

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

bob plan items ​

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

text
bob plan items <N> [--json]
FlagMeaning
--jsonmachine-readable item list
ExitMeaning
0printed
1usage — missing/invalid <N>
2gh/repo error

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

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 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.

text
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]
FlagMeaning
--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)
--rdbpass -rdb so the run uses the remote-decision bridge (Telegram)
--session <name>tmux session name instead of the derived warp-<stem>[-<scope>]
--attachsurface 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-runrun the preflight (files nothing) and print the plan; no session created
--no-preflightskip bob preflight (never the default)
--no-converge-hostdo 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-vizdo 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)
--jsonone warp-start/1 document on stdout
ExitMeaning
0started (or dry-run plan printed)
1preflight failed — the verdict is printed, nothing started
2usage error
3refused — that tmux session already exists
4tmux unavailable or session creation failed
5refused — 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

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. When the run hands off to a new segment this terminal moves to it; it stops when you detach or the run ends (#3163).

text
bob warp attach [project] [--cc | --plain] [--print] [--command] [--json] [--session <name>] [--wait <s>] [--poll <s>]
FlagMeaning
--cctmux -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)
--plaintmux attach — the default on any other terminal
--printprint the run's current tmux session and its tmux attach line; attach nothing
--commandprint 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)
--jsonone 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)
ExitMeaning
0followed the run to its end, detached, or printed
1no project found
2usage error
3no live run to attach to, or no tmux session hosts it
4tmux 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

bob warp status ​

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

text
bob warp status [--watch|--live|-w] [--interval <s>] [--log] [--json]
FlagMeaning
--watch, --live, -wlive view — redraw in place
--interval <s>refresh interval in seconds (default 5)
--logappend the phase-history log below the session info
--jsonone-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
ExitMeaning
0rendered
1no 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

bob warp log ​

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

text
bob warp log
ExitMeaning
0rendered
1no 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

bob warp config ​

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

text
bob warp config
ExitMeaning
0rendered
1no project root

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

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 (#2636).

text
bob warp viz [--tailnet] [--no-open] [--json]
FlagMeaning
--tailnetserve 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-openensure the server and print the URL without opening a browser (what bob warp start runs, #2636)
--jsonone 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)
ExitMeaning
0served
1no 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

bob warp stop ​

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).

text
bob warp stop [--hard|--reset]
FlagMeaning
--hard, --resetemergency reset — delete the state file with no cleanup
ExitMeaning
0aborted or reset
1no 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

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 executes, --yes also reaps attached or warp-running sessions, --idle-shells also kills idle shell-only sessions; Claude outside tmux is reported only.

text
bob warp reap [--force] [--yes] [--idle <minutes>] [--idle-shells] [--json]
FlagMeaning
--forceexecute 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
--yeswith --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-shellswith --force, also kill idle shell-only tmux sessions
--jsonmachine-readable plan: warp-seg classes plus claude, idle_shells, outside and the actions taken
ExitMeaning
0reported or reaped
1a kill failed

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

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 branch config.

text
bob warp session <start <branch> [--area <slug>|--flightplan <N>] | end | status>
FlagMeaning
--area <slug>(start) bind the session branch to one workstream
--flightplan <N>(start) bind the session branch to a flight plan
ExitMeaning
0ok
1usage 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

bob warp finalize ​

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

text
bob warp finalize [--dry-run]
FlagMeaning
--dry-runprint what would be shipped without pushing or merging
ExitMeaning
0shipped or previewed
1no 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

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 | pair.

text
bob fork <fork <branch>... | fork --from-issues [N] | fork --from-flightplan <N> | status [--json] | drop <branch>|--all [--force] | watch [--once] [--json] | pair ...>
FlagMeaning
--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
ExitMeaning
0ok
1a fork, drop or status step failed
2usage error, or git / tmux missing

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

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).

text
bob pair --contract <path> --backend <repo> --frontend <repo> --branch <name>
FlagMeaning
--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)
ExitMeaning
0both worktrees spawned
1a worktree or tmux step failed
2usage error, or git / tmux missing

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

bob swarm ​

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

text
bob swarm <run [--approval <path>] [--cap <n>] [--cwd <dir>] [--dry-run] [--finalize] | plan --plan <file> [--cap <n>] | summary [--plan <file>] [--results-dir <dir>]>
FlagMeaning
--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
ExitMeaning
0ok
1a gate, dispatch or integrate step failed
2unknown subcommand

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

Dev environment and dashboards ​

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.

text
bob dev up [--verbose | --check | --regen | --regen-seed | --no-auto-seed] [project-dir]
FlagMeaning
--verbosefull lifecycle with detailed output (the default)
--checkquick health check only
--regenregenerate dev.json from the stack recipe (overwrites)
--regen-seeddelete auto-generated seed files (010+) and regenerate
--no-auto-seedskip automatic seed generation
ExitMeaning
0every step completed
1dev.json not found or invalid
2server failed to start or the health check failed
3migration failed
4seed failed

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

bob dev health ​

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

text
bob dev health [project-dir]
ExitMeaning
0healthy, or n-a — the project has no dev environment to bring up (#853)
1dev.json not found or invalid
2server 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

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).

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.

text
bob reap [project-root] [--apply] [--sync-ignore] [--owner <tool>[,<tool>]] [--manifest <path>] [--json]
FlagMeaning
--applyactually delete (default: dry-run report)
--sync-ignorewrite 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)
--jsonmachine-readable report
ExitMeaning
0clean
1a deletion failed
2config / 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

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.

text
bob dash status [--projects-only | --global-only | --matrix | --ports | --check <project>]
FlagMeaning
--projects-onlyonly the per-project symlink status
--global-onlyonly the global tooling inventory
--matrixthe project × item provisioning matrix
--portsthe per-project dev-port bands
--check <project>grade one project and exit non-zero on a broken link
ExitMeaning
0rendered
1usage 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

bob dash generate ​

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

text
bob dash generate [project-dir]
ExitMeaning
0generated
1build failed

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

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.

text
bob dash serve [--tailnet | --list | --stop <name> | --stop --all | --ports]
FlagMeaning
--tailnetbind this machine's Tailscale address instead of localhost (#1736); refuses to start when Tailscale is down
--listevery 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
--portseach project's port band
ExitMeaning
0started, listed, or stopped
1server 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

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 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).

text
bob serve [--apply] [--machine <id>] [--json]
FlagMeaning
--applyconverge: 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)
--jsonone 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
ExitMeaning
0converged, applied, or no serve block declared
1drift remains (a route, or a dashboard unit not running), or an apply step failed (named, with its fix)
2usage or config error, including a declaration or argument naming funnel
3Tailscale 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

Release, update and the farm ​

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 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).

text
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]
FlagMeaning
--channel <stable|nightly>stable (default): bump + CHANGELOG + vX.Y.Z tag + Release · nightly: lightweight nightly-YYYY-MM-DD tag
--autopromote 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-docsstable / 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-runrun 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
ExitMeaning
0released, tagged, or nothing to do
2usage error
3refused — a gate names why
4held — 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)
5partial — 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

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 dirty tree or a live Claude Code session.

text
bob update [--channel stable|nightly] [--to <tag>] [--dry-run] [--json]
FlagMeaning
--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-runprint the tag it would move to; fetches, writes nothing
--jsonmachine-readable result (schema bob-update/1)
ExitMeaning
0updated and bob doctor converged
1updated; bob doctor reports drift
2usage error, or no source checkout to update
3refused — dirty tree, off the main branch, cannot fetch, unknown / no tag, not fast-forwardable, or deploy failed (the reason is named)
4live-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

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 (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.

text
bob tick [--dry-run] [--cwd <dir>] [--json] | bob tick --pause | --resume | bob tick --install-timer [--machine <id>] [--dry-run] [--json] | --uninstall-timer
FlagMeaning
--dry-runevery 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
--jsonthe tick-digest/1 document on stdout (human lines to stderr)
--pausewrite $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)
--resumeremove the pause file and reset the failed-tick count
--install-timerrender 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-timerdisable 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)
ExitMeaning
0tick complete or dry-run complete
1run blocked — a pipeline step failed (named in the digest)
2usage error
3another 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)
4budget — 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

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 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.

text
bob wiki maintain [--project DIR] [--source DIR] [--dry-run] [--max-records N] [--max-chars N] [--since YYYY-MM-DD] [--json]
FlagMeaning
--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-runcollect 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)
--jsonone wiki-maintain/1 document
ExitMeaning
0done — a PR opened, a no-op, or a dry run
1the run failed: the agent, the wiki lint, the push or the PR — nothing is consumed
2usage or config error (no BOB_SOURCE checkout, no wiki store)

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

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 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.

text
bob wiki propose (<item> | --auto) [--source DIR] [--dry-run] [--model M] [--max-cost-usd USD] [--runs N] [--json]
FlagMeaning
--autopropose 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-runpick 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
--jsonone skill-propose/1 document
ExitMeaning
0done — a PR opened (a draft when the gate rejected), a no-op or a dry run
1the 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
2usage 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

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 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.

text
bob eval run <item> [--model M] [--runs N] [--max-cost-usd USD] [--out FILE] [--root DIR] [--keep] [--json]
FlagMeaning
--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)
--keepkeep the temp dir (the assembled plugin, the platform's result and its HTML report) and name it in the output
--jsonprint the skill-eval/1 document
ExitMeaning
0the eval completed — any verdict, a run the ceiling cut short included (partial: true)
2usage: an unknown item, an item with no suite, a bad flag or no cost ceiling
3it 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

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 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.

text
bob eval gate <item> <result.json> [--model M] [--record --pr <#N|owner/repo#N> --pages <slug,slug>] [--date YYYY-MM-DD] [--root DIR] [--json]
FlagMeaning
--model <M>the model whose best is compared (default: the result's model)
--recordwrite 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)
--jsonone skill-eval-gate/1 document
ExitMeaning
0accept — strictly above the recorded best
1reject — equal, lower, or a partial run
2usage: 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

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).

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.

text
bob mirror <resolve|reconcile|publish|verify|status> [project|--all] [--apply] [--local] [--ref <branch>] [--path <dir>] [--json] [--no-probe]
FlagMeaning
--allevery project with an enabled mirror
--applyactually 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
--jsonmachine-readable output
--no-probe(status) declared state only, no network probe
ExitMeaning
0ok
1operational failure — unreachable, push rejected, or a stale mirror
2declaration 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

bob forge health ​

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

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

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

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 (#1750); an edit with an empty body is never queued or replayed, and drop sets one entry aside (#3186).

text
bob forge queue [status|list|show <id>|resolve <id>|drop <id>|replay [--apply]|clear] [--json]
FlagMeaning
--apply(replay) deliver the spooled mutations instead of previewing
--jsonmachine-readable output
ExitMeaning
0nothing 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

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 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.

text
bob site publish <bundle-dir> [--apply] [--deploy] [--force-live] [--json]
FlagMeaning
--applycopy, commit, push and deploy; without it the plan and the gate probes are printed and nothing is written
--deploywith --apply, redeploy even when nothing changed
--force-livedeploy 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
--jsonone site-publish/1 document — section, producer, files added / updated / unchanged / orphaned, gate probes, deploy account, commit, deploy
ExitMeaning
0reported, published or unchanged
2usage, an invalid bundle, or a bundle file outside its section
3no site declared, an invalid site, a refusal (undeclared section, ungated, exposed host, account) or a git failure
4the 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

Operator and secrets ​

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 against schemas/operator.schema.json (#2267, decision #2266).

text
bob operator show [--json]
FlagMeaning
--jsonone bob-operator/1 document — resolution rungs, root, validity, the profile when valid
ExitMeaning
0resolved and valid
2invalid profile — missing, unparseable or failing the schema; or usage
3no 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

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 it, and write the $BOB_HOME/.bob-operator pointer only with --link (#2267).

text
bob operator init <dir> [--id <slug>] [--label <name>] [--forge-host <host>] [--forge-owner <owner>] [--upstream <owner/repo>] [--link] [--force] [--into-existing] [--json]
FlagMeaning
--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)
--linkalso write $BOB_HOME/.bob-operator pointing at <dir> — the only way init touches BOB_HOME
--forcerewrite the scaffold files in a directory that already holds operator.json
--into-existingscaffold 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)
--jsonone bob-operator-init/1 document
ExitMeaning
0scaffolded
1refused — <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
2usage

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

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, 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).

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

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

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, 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.

text
bob secrets check [--json]
FlagMeaning
--jsonone bob-secrets/1 document — the operator, counts, one row per declared secret (name, kind, ref, state, source, fix); never a value
ExitMeaning
0every required secret is present (an unrequired gap is reported, never graded)
1a required secret is missing, insecure or unknown
2invalid operator profile, or usage
3no 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

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 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.

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

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

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) to attach to it (#2291). One SSH call through the fleet transport; the sessions are enumerated by seg-windows.js on the target.

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

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

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 left this period — read with the working key from the environment or the keychain. The key value is never printed.

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

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

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 (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.

text
bob route mint --machine <id> [--route <name>] [--apply] [--replace] [--json]
FlagMeaning
--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)
--applycreate and store the key; without it, report what would be created
--replacewith --apply: delete the existing key of that name first, for a machine that no longer holds its value
--jsonone bob-route/1 document — machine, key name, limit_usd, verdict, stored_at; never a value
ExitMeaning
0minted, already present, or a dry run
1the route's API failed, or the key could not be stored
2usage, an unknown machine, a machine with no declared limit, or not this machine
3no 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

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, 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.

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

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

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 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.

text
bob route run --role <role> [--cwd DIR] [--result FILE] [--fresh-session-id] -- <command> [args…]
FlagMeaning
--role <role>the role to run on (bob route roles lists them)
--cwd DIRthe project to run in (default the current directory)
--result FILEwrite a bob-failover/1 document: the candidate the command ran on, and every attempt
--fresh-session-idgive each restart of a command that passes --session-id <id> a new id, recorded on its attempt in --result
ExitMeaning
0the command succeeded
2usage, an unknown role, or routing.json does not load
3every 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

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 — read from $BOB_HOME/route-failover.jsonl, which bob route run appends to.

text
bob route failovers [--limit N] [--json]
FlagMeaning
--limit Nhow many records to show (default 20)
--jsonone bob-failover/1 document — the log path and the records
ExitMeaning
0the records were printed, or none were recorded

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

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 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.

text
bob cloudflare verify [--cwd <dir>] [--account <key>] [--write] [--json]
FlagMeaning
--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
--writealso create and delete a KV namespace in the account, and read every other declared account to show it is refused
--jsonone bob-cloudflare/1 document — account, account_id, token, status; never a value
ExitMeaning
0the working token is active in the account
1the Cloudflare API failed
2usage, or an unknown account
3no 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

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 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.

text
bob cloudflare mint --machine <id> [--account <key>] [--apply] [--replace] [--json]
FlagMeaning
--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)
--applycreate and store the token; without it, report what would be created
--replacewith --apply: delete the existing token of that name first, for a machine that no longer holds its value
--jsonone bob-cloudflare/1 document — machine, account_id, token, groups, excluded, verdict, stored_at; never a value
ExitMeaning
0minted, already present, or a dry run
1the Cloudflare API failed, or the token could not be stored
2usage, an unknown machine or account, or not this machine
3the root token is missing or rejected, or a token exists whose value this machine does not hold
4Cloudflare 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

Work attribution ​

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 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

text
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]
FlagMeaning
--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|jobproject (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).
--fleethours 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)
--jsonone 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}]}
ExitMeaning
0reported — a project with no transcript in the window is reported with zero hours
2usage: 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

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 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

text
bob labor reconcile [--apply] [--project <name>] [--since <iso>] [--settle <minutes>] [--projects-dir <dir>] [--json]
FlagMeaning
--applyappend 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
--jsonone 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
ExitMeaning
0no unrecorded transcript is left in the window
1one or more unrecorded transcripts (report only), or --apply could not price one
2usage: a bad flag, date or settle value

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

Rituals ​

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, #2231); a guide walkthrough is listed for each guide whose requirement still has the acceptance criterion that asked for it unticked (#3809).

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

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

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 provision overlay, then print the evidence packet summary, the checklist the run embeds (#2241) and the previous run findings (#2234).

text
bob ritual run <ritual> [--project <p>] [--drill <name> | --drill-kind <kind>] [--machine <id>] [--guide <name|file>] [--repo owner/name] [--no-kit] [--dry-run] [--json]
FlagMeaning
--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/namethe repo holding the runs (default: the checkout github.com origin)
--no-kitresume or open the run without applying the kit overlay
--dry-runopen nothing and apply nothing — report the run it would resume or open
--jsonone bob-ritual-run/1 document: verdict, issue, url, opened, kit, checkout, machine, overlay, packet, previous {date, issue, findings}, error
ExitMeaning
0started, resumed, or --dry-run
2usage or config error — unknown ritual or project, no checkout here without --no-kit
3refused — this machine role forbids the ritual kit
4not started — the forge could not be read, refused the create or spooled it
5the 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

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 checklist, delta against the previous run) after refusing a duplicate open run of the same ritual (#2231).

text
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]
FlagMeaning
--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-DDthe held_on stamped in the marker (default today, UTC)
--dry-runprint the title, labels and body; file nothing
--jsonone bob-ritual-open/1 document
ExitMeaning
0filed, queued, --dry-run, or every --replaces to-do converted onto the run
2usage or config error
3a run of this ritual is already open
4nothing 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

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).

text
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]
FlagMeaning
--dueprepare 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-rungather and print (one run) or list the targets (--due); post nothing
--jsonone bob-ritual-prepare/1 (or bob-ritual-prepare-due/1) document
ExitMeaning
0posted, updated, queued, or --dry-run (--due: every target prepared)
1(--due) at least one target not prepared
2usage or config error
3nothing to prepare — the run is closed or declares no collectors
4nothing 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

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 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).

text
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]
FlagMeaning
--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-findingsclose a run with an empty checklist, recording that it found nothing
--held-on YYYY-MM-DDthe day the ritual was held (default: the run marker)
--dry-runrun every check and print the closed body; write nothing
--jsonone bob-ritual-close/1 document: verdict, findings, journal, no_findings, delta {previous, resolved, recurring, new}, problems, body, error
ExitMeaning
0closed, queued, or --dry-run
2usage or config error — not a ritual-run issue, a project mismatch, a bad issue number
3refused (each problem named; the run stays open) or already closed
4the forge could not be read or refused the write
5closed, 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

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 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).

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

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 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.

text
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]
FlagMeaning
--writeinventory: save the list as the operator repo's portfolio.json, keeping every decision already recorded; audit: save the dated audit there
--machines id,idinventory: scan only these machines; the rest are listed as not inventoried
--with rowdecide: another row decided as part of the same decision (a backup beside its original); repeatable
--note "<why>"decide: one line recorded with the decision
--discarddecide <row> scrap: accept the loss of what exists only in that directory; the scrap list then says what is lost
--only rowapply: carry out this one decision
--approve digestscrap: record the approval of the exact list the dry run printed
--applyapply: 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 Nrecord: the /journal decision issue linked on every status change
--jsonone bob-portfolio/1 document, or the subcommand's (-decide/1, -status/1, -apply/1, -scrap/1, -audit/1, -record/1)
ExitMeaning
0inventory complete, decision recorded, every row decided, every decision carried out, or the scrap list printed, approved or removed
1status: at least one row is undecided; apply: a decision is blocked or failed; scrap --apply: a path could not be removed
2usage or config error, a scrap list that is not approved or changed since its approval
3inventory: at least one machine was not inventoried
4record: 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 ​

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.

Slash commands and skills ​

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 shellIn a Claude sessionDifference
bob warp start/warp-drivebob 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-driveSame abort, from a shell or from the session.
bob plan build/flightplan/flightplan can interview for scope; bob plan build never asks.
bob groom/groombob groom is the headless pass (dry run unless --apply); /groom is interactive.
bob dev up/dev-upSame engine.
bob fork/cdforkSame engine.
bob swarm/swarmSame 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/provisionSame engine; the slash command adds guidance.
bob promotion setup/setup-promotionSame scaffold.
bob deploy/deploySame dispatcher and ceiling gate; /deploy acts on the session's project.
bob release/releaseSame release engine.
bob status/statusDifferent jobs: bob status is a health verdict; /status is a project catch-up and next-work report (/what-next --report).

Old name → bob command ​

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.

WasNowEngine
bob-mirrorbob mirrorscripts/cli/bob-mirror
bob-readybob readyscripts/ready/ready.js
bob-reapbob reapscripts/cli/bob-reap
bob-releasebob releasescripts/cli/bob-release
cdbbob dash statusscripts/cli/cdb
cdforkbob forkscripts/cli/cdfork
cdfork-pairbob pairscripts/cli/cdfork-pair
cdgbob dash generatescripts/cli/cdg
cdibob initscripts/cli/cdi
cdlbob linkscripts/cli/cdl
cdpbob promotescripts/cli/cdp
cdprovbob provisionscripts/cli/cdprov
cdsbob dash servescripts/cli/cds
dev-healthbob dev healthscripts/cli/dev-health
dev-upbob dev upscripts/cli/dev-up
forge-healthbob forge healthscripts/cli/forge-health
forge-queuebob forge queuescripts/cli/forge-queue
setup-promotionbob promotion setupscripts/cli/setup-promotion
swarmbob swarmscripts/cli/swarm
warpbob warp status · bob warp log · bob warp config · bob warp viz · bob warp stop · bob warp reap · bob warp session · bob warp finalizescripts/cli/warp

Not mapped ​

  • 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