When to recruit
Sorting work into do, quiet, and crew: no model, a model without a pane, or a model with one.
A pane plus a model is the most expensive thing a captain can spend, and the easiest to spend on work that needs neither. Every task sorts into three buckets: no model at all, a model without a pane, or a model and a pane.
The decision rule#
No model needed? -> captain do
A model, and you can write the whole
instruction now, and one answer ends it? -> captain quiet
A model, and you will learn the next
instruction from what it does? -> captain crewThe discriminator between the last two is steering. Not risk, not size, and not whether the work writes files. If the captain already knows everything it would say to an agent, a pane buys nothing: there is no next instruction to type into it. If the captain will only know what to ask after seeing the agent's first move, nothing but a pane will do.
| Path | Cost | Examples |
|---|---|---|
captain do / captain inspect | One subprocess, zero tokens | A commit, a push, a declared Makefile target, finding which files changed |
captain quiet | One headless turn, a three-line prompt | A question about the code, a short review, a drafted commit message, one bounded edit |
captain crew | Pane, instruction block, assignment, wait, report | Design, debugging, anything you will steer as it goes |
Deterministic work: captain do#
captain do performs work with no crew and no model at all. It is the answer whenever the outcome is already determined by its inputs, so a commit or a declared build target never costs a pane.
captain do commit --message "Fix the off-by-one" src/parser.py
captain do push
captain do branch docs-site
captain do switch main
captain do fetch
captain do pull
captain do run test| Command | Arguments | Does |
|---|---|---|
do commit | --message MESSAGE (required), [path ...] | Stages the named paths and commits them. Omit the paths to commit what is already staged. |
do push | none | Pushes the current branch, setting upstream on the first push. |
do branch | name | Creates and switches to a new branch. |
do switch | name | Switches to a branch that already exists. |
do fetch | none | Fetches from the remote, touching no file in the worktree. |
do pull | none | Fast-forwards the current branch. It never merges, rebases, or conflicts. |
do run | target | Runs one target the project declares in its Makefile. |
do run accepts only a declared target from a fixed vocabulary: build, check, clean, fmt, format, gate, help, install, lint, test, typecheck, vet. It is not a shell: a target the project does not declare is refused rather than guessed at.
Reads without a model: captain inspect#
captain inspect answers read-only questions with no model and no Herdr lookup. Paths are literal and project-bounded. Reads go here; writes and anything needing the real environment go to do.
captain inspect files src
captain inspect read README.md
captain inspect search "literal text" src
captain inspect state repo graph.json
captain inspect git diff --staged
captain inspect git branches
captain inspect git grep --text "literal text"| Command | Arguments | Does |
|---|---|---|
inspect files | [path] | Enumerates files under a path. |
inspect read | path | Reads one regular UTF-8 text file. |
inspect search | text [path] | Searches for literal, case-sensitive text. Not a regex. |
inspect state | session|project|repo [path] | Reads a literal path within one stored scope. Crew are limited to repo. |
inspect git | status|log|current-branch|root|diff|branches|ls-files|grep [--staged] [--text TEXT] | Fixed Git queries. --staged diffs the index instead of the worktree, and grep takes its literal, case-sensitive pattern from --text. |
- Results are JSON, bounded to 64 KiB, 200 results, 10,000 entries, 8 MiB searched, and five seconds. Hitting a limit produces a truncation marker or an explicit error, never a quietly short answer.
- No shell, no arbitrary flags, no external helpers. The Git operations above are the whole set.
What inspect refuses#
Git requires a trusted system installation and an ordinary stable local checkout. Linked worktrees, partial clones, alternates, and unsupported config are refused. Git must be root-owned at /usr/bin/git on Linux, or the Command Line Tools installation on macOS — the macOS /usr/bin/git launcher is not used.
Reads accept regular UTF-8 text files. Enumeration skips symlinks and .git, and a direct symlink read fails. Filesystem deadlines are cooperative. Native sandbox permissions still apply on top of all of this — see ownership and guardrails.
One model turn without a pane: captain quiet#
A pane buys two things: somewhere to approve a native permission prompt, and somewhere to steer a running turn. Work that needs neither should pay for neither. captain quiet spends one headless model turn with no pane, no assignment, and no wait: the result is printed and recorded, and that ends it. Quiet turns covers it in full.
captain quiet --task "Does anything else call parse_header?"
captain quiet --task "Draft a commit message" --diff staged
captain quiet --task "Review this against AGENTS.md" --diff worktree
captain quiet --task "Fix the typo in the heading" --write src/content/docs/cli.tsx
captain quiet --task "Name a branch for a docs rewrite" --model cheap| Flag | Does |
|---|---|
--task TEXT | The whole instruction. Required, and the only required flag. |
--diff worktree|staged | Appends that diff to the task. A headless turn has no shell, so Git is the one thing it cannot read itself. |
--write PATH | A file the turn may edit, repeatable. Without it the turn is read-only. |
--model MODEL | A tier or model name. Falls back to [crew] model, cheap by default. |
--timeout SECONDS | Seconds to allow. 900 by default. |
The turn reads the checkout itself, so paste nothing you can name instead. A read-only turn is also handed this session's own directory, letting it triage the event log, mail, and assignment records. A turn given --write is not: an unwatched editing turn can never reach that state, and it leaves its edits unstaged.
Stopping a crew without losing it#
When a crew is working the wrong problem, interrupt stops its current turn while keeping its pane, conversation, and assignment. It is the middle ground between a tell that queues behind the current turn and a dismiss that throws the pane away.
captain interrupt Jack
captain interrupt Jack --reason "wrong file, reassigning"--reason is recorded in session memory, so why a turn was cut short survives into the next wait and the session's history.