Skip to content

Agent Teams

Agent teams let you run a set of role-based AI teammates as coordinated in-process workers — each with its own chat session, tool access, and task assignment — driven by a shared task list and a message mailbox. The team definition lives in your mission repo; the bnerd CLI is the runtime.

Roadmap status

Agent teams landed in bnerd CLI as part of roadmap item B7 (phase 1). The TUI's live team panel, task board, and focus mode (see Agent Teams in the TUI) are complete; the future SRE-network / distributed-pod phase is on the roadmap but not shipped yet.

Two execution flows

bnerd's AI surfaces support two distinct ways to work with multiple agents:

Normal chat with subagents

The default chat (:chat / :code / bnerd pa) lets the AI spin up short-lived, read-only subagents (sub_agent, explore_agent, kube_agent) to handle isolated sub-tasks and return a compact summary. These are ephemeral — they run, report back, and terminate. No shared task list, no mailbox, no persistence.

Use this when you need the AI to delegate a quick lookup or exploration step within a single conversation.

Agent teams — persistent, coordinated teammates

An agent team is a set of long-lived teammates: each is a full chat session with its own role, tool registry, and history, connected through a shared task list and a message mailbox. Every team has a coordinator that routes tasks, responds to teammate messages, gates phase transitions, and ends the run once the goal is met — teammates self-claim unblocked tasks, satisfy review gates, and idle until new work arrives. Two things can play that coordinator role:

  • A scripted coordinator driver — an AI session holding the team's coordination toolset, spawned alongside the roster rather than as one of its members. This is what bnerd team run uses (see The bnerd team CLI → Coordinator driver).
  • Your own conversation — say "work with a team on X" in bnerd x's chat or bnerd web, or use the :team <slug> shorthand in the TUI, and the conversation's agent itself gets the coordinator's toolset bound in and drives the team without leaving the chat window. See AI Assistant → Working with a team and Agent Teams in the TUI.

Use this when a task is large enough to be split across roles — e.g. adding a new API endpoint across the hq API, CLI, and docs simultaneously, or running a structured PR review with both a code-reviewer and a security-reviewer checking the same commit.

Normal chat + subagents Agent teams
Teammate lifetime One task, then terminated Long-lived; idle between tasks
Coordination Lead's own chat Shared task list + mailbox — a scripted driver session, or the conversation itself
Task history Lost after subagent exits Persisted to .bnerd/teams/<id>/
State after a crash Lost Persisted to disk and marked interrupted (tasks/mailbox/teammate histories flushed, lease released); a TUI-launched team can be resumed by reopening its conversation (--ai-continue) — see Resuming an interrupted team. A web- or headless-launched team is marked interrupted the same way but has no resume offer.
Safety Lead's session floor Per-role tool registry + team SafetyMode floor
Entry point :chat, :code, bnerd pa bnerd team run, "work with a team" in chat/web, TUI's :team <slug> shorthand

Getting started

  1. Make sure your mission repo's orchestrator/teams/ contains a team recipe (see Team recipes).
  2. Run a team headlessly:

    bnerd team run pr-review "review PR #142 in cloud/app/hq"
    
  3. Or use the :team <slug> shorthand in the TUI, which asks the conversation's agent to start it:

    bnerd x
    :team pr-review
    
  4. Or just ask for it, in your own words, from the ordinary conversation (bnerd x or bnerd web):

    work with a team on reviewing PR #142 using the pr-review recipe
    

    Either way the team runs inside your current conversation — no separate view opens — with a live status panel, a full task board (Ctrl+T in the TUI), and focus mode for stepping into a teammate's own thread. See AI Assistant → Working with a team and Agent Teams in the TUI.

See The bnerd team CLI for the full command reference, and Safety model for how tools are scoped per role.

Delegated coordinator

When your own conversation is the coordinator, it can hand day-to-day coordination off to a teammate instead of doing it itself — an opt-in move, not something a team does on its own.

What it is. A delegated coordinator is an ordinary teammate that additionally holds the driver toolset (team_spawn_teammate, team_task_create/team_task_update, team_stop_teammate, team_replace_teammate, team_pause/team_resume, team_status, team_send_message, task list/get, and team_finish) scoped to its own name. From that point on, attention events — a teammate finishing a task, failing, or asking something — route to the delegate's inbox instead of being injected into your conversation.

When to use it. It's a context-pressure valve for a long autonomous phase: instead of your conversation's own context filling up with every "task #4 claimed", "task #4 done" milestone while the team grinds through a big roster, a delegate absorbs that traffic and only surfaces what still needs you (approvals, questions — see below).

How to invoke it. Ask the agent to delegate coordination — e.g. "hand coordination of this team to the reviewer" — and it calls team_delegate with a brief (the goal handoff delivered as the delegate's first inbox message), an optional name, and an optional role. role defaults to the recipe's lead: hint (the same role slug bnerd team run uses for its scripted driver's persona) when omitted; if the recipe declares no lead: hint either, team_delegate fails and asks for an explicit role.

What changes — and what doesn't. The conversation stays your interface: it keeps the full driver toolset after delegating (it never loses team_stop_teammate, team_finish, and the rest), so you can still ask it "what's the status" or "stop the reviewer" at any time. What changes is who reacts — a delegated coordinator's own attention stream, task claims and completions, go to the delegate, not to your conversation, so the conversation's context stops growing with routine team chatter. A delegate can never chain-delegate — team_delegate isn't in a teammate's own toolset, only in the conversation's (or the scripted headless driver's).

The delegate can still report to you. A delegate that sends a message to lead is reporting upward, to the conversation — that message is not diverted into its own inbox, and it lands in your conversation the way a teammate's report did before delegation. That is how a delegated coordinator hands you a status summary or a closing report without you having to ask. Mail from every other teammate addressed to lead still goes to the delegate, which is the point of the handoff.

The conversation can still end up coordinating alongside the delegate

Because the conversation keeps its driver toolset, the TUI's quiescence nudge (the periodic "the team looks quiet, decide the next step" prod that keeps a stalled team moving) still targets the conversation even while delegated — it has no delegate-aware routing yet. If it fires, the conversation may genuinely start coordinating again alongside the delegate (bounded to once per distinct task-board state). This is the current, intentional fallback: it guarantees a quiet delegated team is never left with nobody to wake it. A follow-up to route the nudge to the delegate's inbox instead is tracked on the roadmap.

If the delegate falls far enough behind, its status block says so

The attention stream reaches a delegate through a bounded inbox (64 slots). A roster completing tasks faster than the delegate drains them — it is inside a long turn, the board is busy — can overflow it, and those events are dropped rather than blocking the team. When that happens the delegate's next status block carries a line like 3 attention events dropped since last status — re-read the board. team_status re-derives the full board, so nothing is lost — but the delegate has to know to ask.

The count is cleared by the delegate's own team_status call and nothing else, so it always names the backlog since the delegate last looked. Your conversation's status block shows the same number without consuming it: a render for you must never swallow a warning meant for the delegate.

Approvals still reach you. Delegation changes nothing about who resolves a pending confirm, question, or task-completion approval — the delegate's toolset carries no approval-resolution tool, exactly like the conversation's own driver toolset never has (anti-laundering, see Safety Model). Those still surface to you inline, the same as before delegation.

Stopping the delegate returns coordination. team_stop_teammate (or team_replace_teammate) on the delegate hands coordination back to your conversation — there's no separate "undelegate" verb. A delegate cannot stop or replace itself (that would deadlock on its own shutdown grace); it asks you to do it instead. It can call team_finish to end the whole team, excluding itself from the shutdown loop it triggers. If a delegate dies or panics without being stopped, coordination also returns to the conversation automatically — a team is never silently left leaderless by a crash.

Delegation survives interrupt/resume. If the team is interrupted while delegated, resuming it (reopening the TUI conversation with --ai-continue) rebuilds the delegate with its driver toolset, mailbox alias, and prior history intact, and routes the resume brief to its inbox (not the conversation's) since it's the delegate that has to re-plan the reopened task board. If the delegate's persisted role no longer resolves in the mission catalog, the team resumes leaderless — coordination sits with the conversation again, honestly, rather than pretending a member that couldn't be rebuilt is still driving.