Skip to content

Warp Drive from the Command Line

Everything a warp-drive run does from inside a Claude Code session can be started and steered from a plain terminal — iTerm2 on a laptop, an SSH shell on farm-01, a systemd timer. This page is the one coherent explanation of that lifecycle: groom → plan → start → observe → stop → report. It is authored with bob warp start (#2049) and refreshed by the last requirement of the capability (#2025); the parts that have not landed yet say so, by issue.

Every command below is a row in scripts/bob/commands.json, and bob <noun> <verb> --help prints its flags and exit codes without acting — on every bob warp verb, including stop, wherever --help sits in the argv.

Terminal window
bob groom --area warp-drive # DRY-RUN: prints what the pass would change
bob groom --area warp-drive --apply # Level 3: apply it

bob groom runs the /groom pass headless (claude -p over the inlined command text, #2051). Without --apply it is an explicit dry run; --apply needs automation Level 3. Scope it with --area <slug>, --issues N,N or --all.

Terminal window
bob plan build --from approved --area warp-drive --name "warp CLI" # prints the plan number
bob plan items 2311 # the ordered items

bob plan build derives a flight plan once, with no interview, and writes (or refreshes) its flight-plan issue (#2050). --from farm restricts it to unattended-eligible work (farm-tick.md).

Terminal window
bob warp start --flightplan 2311 --rdb

bob warp start (#2049) launches the run in a tmux session you can attach to:

  1. Preflight. It runs bob preflight first — bob doctor plus bob ready --dry-run as one verdict. A failure exits 1 with the verdict printed and nothing started. On the BoB source checkout, a failure that is only this machine being behind source is fixed first: when the checkout is the clean main branch and no Claude Code session is live, it runs scripts/deploy.sh and bob doctor, then the preflight again. The JSON records it as host_converged. --no-converge-host skips it (#2472).
  2. Dashboard. It ensures the project’s monitor is running — the same path as bob warp viz --no-open: reuse a fresh server or start one on this machine’s resolved bind (a machine that declares "dashboard": {"bind": "tailnet"} in the operator repo’s machines.json, like farm-01, serves on its Tailscale address). A dashboard that fails to start is reported and the run goes on; --no-viz skips the step (#2636).
  3. Session. It creates the detached tmux session warp-<stem>[-<scope>] (the stem is the project; in a linked git worktree it is <project>-<worktree>, so a worktree run keeps its project’s name — #4041) (-fp-N, -issue-N, -area-<slug>, or --session <name>) in the project root, and refuses with exit 3 when that session already exists.
  4. Launch. It sends claude -a<level> [-rdb] "/warp-drive <scope flags>" into the session’s one window. --level defaults to _automation.active_level, else 3; --rdb turns on the remote decision bridge.
  5. Attach line. It prints the session name, the one attach command (bob warp attach <project>, attach.command in warp-start/1), the tmux -CC attach -t <session> line and the viz URL (viz.url). --attach opens an iTerm2 control-mode window on an interactive Mac. On any other terminal it runs bob warp attach there, so the terminal follows the run (#3163).

--dry-run runs the preflight without filing anything and prints the plan; --json emits one warp-start/1 document.

It is not bob warp session start. That verb binds an integration-branch stream and launches nothing.

The same engine, scripts/warp-drive/launch.sh, is what bob fork uses per worktree window and what segment-spawn.sh uses per segment handoff — one launcher, so a run started any of these ways looks the same to everything below.

Terminal window
bob warp status --watch --log # phase, issue, chunk, metrics; redraws in place
bob warp log # the phase-transition history
bob warp viz --tailnet # the live session graph, served on the tailnet
bob viz --tailnet # every project on every machine as tiles, each linking to its graph
bob control --tailnet # BoB Control: the same pages behind one navigation (Now, Projects, Fleet, Costs)
bob plan status 2311 # plan progress: runnable / gated / done
bob warp attach bigbrain # this terminal joins the run and follows it
Terminal window
bob warp attach # the project you are in
bob warp attach bigbrain # a project by its name, from any directory
bob warp attach ~/projects/bigbrain-drain # or by path (a worktree, say)

A long run is a chain of tmux sessions: segment 1 in warp-<stem>[-<scope>], then one warp-seg-<stem>-<N> per segment. bob warp attach (#3163) attaches to the one that hosts the run now. When the run hands off to a new segment, the terminal moves to it. You never type a segment number.

Where you run it What it does
iTerm2, also over SSH tmux -CC attach (control mode). Each segment gets its own -CC attach, so it opens as its own window.
Any other terminal tmux attach.
Inside tmux Switches this tmux client to the run. It never nests an attach.

While bob warp attach is following a run, it is the only thing that attaches to it. A segment handoff opens no iTerm2 window of its own, because this terminal already moves to the new segment. With no follower running, each new segment opens its own window as before (#3942).

--cc and --plain choose the mode yourself. The follow stops when you detach (the run goes on, and the same command re-attaches) or when the run ends. bob warp attach --print prints the session and its tmux line without attaching. Exit 3 means there is no live run to attach to.

bob warp status|log|viz read the project’s warp-drive state file, so they work the same against a run started with bob warp start, /warp-drive typed in a session, or a segment handoff. From another machine, bob warp viz --tailnet prints a URL reachable over Tailscale. After the server starts, bob warp status keeps printing that URL on its Viz: row (viz in --json), and bob doctor lists it too (#2639).

Terminal window
bob warp stop # graceful: transitions to aborted
bob warp stop --hard # emergency: deletes the state file, no cleanup

A graceful stop moves the run to the aborted phase; the session inside the tmux window then files the abort report (/stop-warp-drive does the whole cleanup from inside Claude Code). --hard wipes the state file and tears down the run’s warp-seg-* tmux session, leaving uncommitted work in the tree. A run that ends, completed or aborted, cleans up after itself (#3163). It kills its own warp-seg-* sessions, then runs the bob warp reap sweep, which also removes finished segment sessions other runs left behind. The sweep never touches a live run, an attached session or the session the run itself is in. The transition’s response names what it removed as seg_reap, and WARP_RUN_END_REAP=0 turns the sweep off. Run bob warp reap by hand only for what is left: an attached session (--yes), or the last segment’s own window once you have closed it (dry run by default).

The run-end sweep only touches warp-seg-* sessions. A finished claude /warp-drive REPL in a warp-<project>-fp-<N> session, or an old interactive Claude session in any other tmux session, is found by running bob warp reap by hand (#3302):

Terminal window
bob warp reap # dry run: every Claude pane graded stale or live
bob warp reap --idle 60 # stale after 60 idle minutes instead of 240
bob warp reap --force # stop the stale ones: Escape, /exit, wait, kill the pane
bob warp reap --force --idle-shells # also kill tmux sessions holding only an idle shell

A Claude pane is stale once its window has been idle longer than _workflow.reap_idle_minutes (240 by default; --idle overrides it). A stale pane in an attached session, or one whose project has an active warp-drive run, is listed under “needs –yes” and left alone without it. Sessions that hold only an idle shell are listed as their own class and killed only with --idle-shells. A Claude process outside tmux is listed with its PID, age and tty, and never stopped.

Before any kill — a reaped warp-seg-* pane, a stopped Claude pane, an idle shell session, the run-end teardown and the segment handoff’s kill of a leaked session — the pane’s whole scrollback (tmux capture-pane -p -S -) is saved to <project>/.claude/scrollback/<session>-<pane>-<UTC time>.log (#3552). That output is the evidence a harness-defect report needs when a run died oddly. Each save is an action line (saved scrollback <path>); a pane that cannot be saved — no project above its cwd, or a log that cannot be written — is named as scrollback not saved for %N: <why>, and the kill goes ahead anyway. The logs are a declared reap surface (scrollback, ttl_days: 7), so the residue reaper deletes them after a week and the managed ignore block keeps them out of git.

The dashboard servers behind bob warp viz and bob viz keep running after the run ends. bob doctor lists every one on this machine in its dashboards section: project, port, bind (localhost or tailnet), PID, age and the /warp link, closing with the /bob fleet link (#2639). It flags a server that started before the current deploy, or one bound somewhere other than where the project last asked, and prints the command that stops it (#2563):

6952/warp
bob doctor # INFO dashboards: 2 running, 1 flagged
# Fleet: http://farm-01.<tailnet>.ts.net:6952/bob
bob dash serve --stop bigbrain # every dashboard server for one project, any port or bind
bob dash serve --stop --all # every BoB dashboard server on this machine

Stopping is idempotent. The next bob warp viz starts a fresh server.

A run ends by filing a session summary — a GitHub issue labelled session-report,session-summary,warp-drive — with the chunk reports it filed along the way (chunk-report). From a shell:

Terminal window
gh issue list --label session-report --limit 5
bob plan status 2311
bob notify "warp run on bigbrain finished" --level info

bob notify sends a Telegram message over the bridge from any shell, and prints the message instead when no bridge is configured (#2048).

Terminal window
bob tick --dry-run # every step read-only; the digest is the only artifact
bob tick # one live cycle
bob tick --pause # later ticks exit 3 as `paused` until --resume (two failed ticks do this themselves, #2055)

bob tick (#2054) is steps 1–6 as one command with one exit code, for a timer. Under a lock on $BOB_HOME/.bob-tick.lock it runs bob groom --all --apply, bob plan build --from farm, one bob warp start --flightplan N --level 3 --rdb and waits for its tmux session. The wait is bounded by _workflow.tick_wall_clock_minutes. It then reconciles the plan, publishes a fleet snapshot, cuts a nightly and runs bob release promote --auto on BOB_SOURCE, and runs bob update --channel nightly, which a live session refuses only when the nightly would rewrite the settings.json hooks (#2746). It ends with a tick-digest/1 digest at $BOB_HOME/fleet/ticks/<date>.json. What each step may take and how the night shift stops is farm-tick.md.

tests/test-unattended-path.sh (#2058) is this page as a test. It builds a scratch git repo at Level 3 and puts a fake claude and a fake gh on the path, then drives the real bin/bob and engines through steps 3–5 and §7:

  1. bob warp start --issue 1 — the fake claude walks the state machine to coding.
  2. bob warp status — shows the run as active, with its phase, issue and level.
  3. bob tick --dry-run — writes the digest and files no issue, PR, tag or commit.
  4. bob warp stop — the run aborts, resolves the abort and exits.

It runs under make test on macOS and Linux, and prints a SKIP: reason when tmux is missing. When this page and that test disagree, the test is right.