The bnerd team CLI¶
The bnerd team command group is the headless entry point for agent teams. It runs in pure line-based I/O — no Bubbletea, no terminal control codes — so it works in pipes, CI, SSH without a PTY, and as the target of another AI's MCP call.
Commands¶
bnerd team list¶
List all team recipes known to the CLI (from your mission repo and fallback locations).
bnerd team list
# pr-review Run a multi-role review of a pull request
# cloud-app Build/change the cloud product across its surfaces
# incident-response Triage and respond to an active incident
Flag:
| Flag | Default | Description |
|---|---|---|
--mission-repo <path> | auto-discovered | Override the mission repo path |
bnerd team describe <slug>¶
Show the full definition of a team recipe: its lead role, safety mode, members (always-on vs on-demand), and workspace.
bnerd team describe pr-review
# pr-review — Run a multi-role review of a pull request
# lead: product-orchestrator
# safety: read-only
# members:
# - code-reviewer (always-on)
# - security-reviewer (always-on)
bnerd team run <slug> [prompt]¶
Spawn the named team and drive it headlessly. The initial prompt positions the team-lead; it can also be provided via --prompt.
Confirmations and clarifying questions surface inline on stderr:
[lead] spawning code-reviewer, security-reviewer
[code-reviewer] task #1: review PR #142 — code correctness
─── CONFIRM ────────────────────────────────────────────────
code-reviewer wants to run: gh pr view 142
context: reading PR body before reviewing
Approve? [y/N/explain]: ▮
─── ASK ────────────────────────────────────────────────────
code-reviewer: Should I check the migration for reversibility?
Answer (or "skip"): ▮
After the initial task the CLI accepts further operator input on stdin — type a message and press Enter to inject it into the team-lead's mailbox. This keeps the session interactive while teammates run in the background.
Flags:
| Flag | Default | Description |
|---|---|---|
--prompt <text> | (empty) | Initial prompt for the team lead (alternative to positional arg) |
--safety <mode> | read-only | Safety floor: read-only, non-destructive, or full. Can only tighten the recipe's declared floor, never loosen it. |
--auto-approve <policy> | never | Confirmation policy: never (ask every time), safe (auto-approve read-only tools only), all (auto-approve everything — only meaningful with --safety=read-only). |
--auto-skip-questions | off | Answer every ask_question prompt with "skip" instead of blocking on stdin. Required for unattended / CI runs. |
--json-events | off | Emit a JSONL event stream on stdout (see Event stream below). Enables CI / pipe / another-AI consumption. Turns off interactive stdin input. |
--mission-repo <path> | auto-discovered | Override the mission repo path |
Security note for unattended runs
--auto-approve=all with --safety=read-only does not restrict outbound web-tool URLs. A prompt-injection in fetched content could exfiltrate model-context data via web_fetch GET URLs. For unattended (cron/CI) runs, also pass --auto-skip-questions — otherwise ask_question blocks on stdin and hangs the job.
Storyboard A — interactive headless (default)¶
Teammates stream their activity to stdout, confirmations and questions pause on stderr, and you answer inline. Same level of control as bnerd pa today — just multi-threaded.
Storyboard B — pre-authorised autonomy¶
bnerd team run inbox-triage "review yesterday's tickets" \
--safety=read-only --auto-approve=safe --json-events
{"event":"spawned","teammate":"ops-investigator"}
{"event":"task_created","id":1,"subject":"summarise #7703 progress"}
{"event":"tool_call","by":"ops-investigator","tool":"openproject_read"}
{"event":"task_complete","id":1,"by":"ops-investigator"}
{"event":"team_done","report":"…"}
The safety floor is read-only, so auto-approving everything risks nothing. The final report is the last event; pipe it to jq or another process.
bnerd team status <team-id>¶
Print a non-blocking snapshot of a persisted team's state: coordinator status, teammate statuses, open tasks, and pending confirmations.
bnerd team status run-cloud-app
# coordinator: running
# teammates:
# - product-orchestrator routing task #3
# - go-cli-dev idle (waiting for task)
# - rails-api-dev claimed task #2: add POST /networks to hq
# tasks:
# #1 completed add POST /networks — rails-api-dev
# #2 claimed add networks CLI subcommand — go-cli-dev
# #3 pending document POST /networks — docs-engineer [blocked by #1, #2]
bnerd team resume <team-id>¶
Restore a team from disk after a crash or kill. The coordinator rebuilds the task graph, rehydrates each teammate's chat history, and re-starts the idle/self-claim loop from where it left off. Teammates with dangling tool calls (interrupted mid-execution) receive a synthetic "interrupted — retrying" result and pick up from the next step.
bnerd team cleanup <team-id>¶
Shut down a running team, drain any pending approvals (auto-declined), and archive the team state directory.
Event stream¶
When --json-events is set, every team event is emitted as a JSON object on its own line (JSONL). Events are separated from the human-readable log; the log goes to stderr while events go to stdout so they can be piped cleanly.
Key event types:
| Event | Fields | Description |
|---|---|---|
spawned | teammate, role | A teammate came online |
task_created | id, subject, by | A task was added to the shared list |
task_claimed | id, by | A teammate claimed a task |
task_complete | id, by, summary | A task was marked done |
gate_satisfied | task_id, gate, by, at_ref, decision | A review gate was satisfied |
confirm_requested | id, from, tool, args, context | A tool confirmation is needed |
question_requested | id, from, question | A teammate has a question |
approval_requested | task_id, from, summary | A human-gate task needs approval |
tip_mismatch | task_id, gates | Gates were satisfied at different commits; task held |
team_paused | reason, by | Team entered pause state |
team_done | report | Team finished; report is the final synthesis |