Agent Teams is an experimental coordination capability that turns one coding session into a small working team: the session's agent becomes the Lead, creates named teammates for delegated work, exchanges durable messages with them, and tracks shared tasks on a common board. Roster, mailbox, and task state are replayed from the Lead's session log, so they survive crashes, reloads, and interruptions. The whole feature lives in the experimental package group: it is excluded from official releases and npm publishing, carries no stability promise, and is disabled by default — no shipped bundle wires it in.
| Package | Role | ctx key |
|---|---|---|
packages/experimental/agent-team | Service definition: durable roster, mailbox, and task board backed by the Lead Session log | ctx.agentTeams |
packages/experimental/tool-agent-team | Ten model tools for creating, messaging, and coordinating teammates | registers scoped tools on ctx.tools |
packages/experimental/agent-team-profile | Explicit source-checkout profile layer over dsh-base | — |
packages/experimental/agent-team-web-profile | Explicit source-checkout Web layer for the Host Team profile | — |
packages/experimental/client-ui-agent-team | Team roster, task board, and teammate navigation for Web | — |
Everything here is a source-checkout prototype, not part of any official release payload. The placement and release-exclusion rationale is recorded in .agents/notes/implemented/architecture/2026-08-18-experimental-agent-teams-packages.md; the docs/subsystems/agent-team.md subsystem reference owns the durable types and the service API.
The team domain
Every ordinary runtime root is the implicit Lead of a Team whose TeamId equals its SessionId — there is no creation event, and durable state begins with the first member, message, or task record. The Lead creates named teammates with a unique lowercase name such as reviewer; a teammate starts fresh (no Lead history) or as a fork that inherits the Lead's completed turns. Names are permanent: even a teammate whose creation failed keeps its name, and no name is ever reused.
The roster shows every member with its role (lead or teammate) and current status — running, idle, inactive (exists but not loaded), provisioning, or failed. Only the Lead can create teammates or interrupt them.
Durable events
Team events are appended to the exact live Lead Session and flushed before the operation reports success or wakes waiters. There are exactly four mutable event types, all log-only — they never enter the conversation surface, so derived model history is untouched by coordination records:
type MutableTeamEventType =
| 'team/member' // every teammate lifecycle change
| 'team/task' // every compare-and-set task mutation
| 'team/message/queued' // a message durably stored in the Lead log
| 'team/message/delivered' // a target receipt acknowledgedSession event seq and time own ordering and timing; Team snapshots do not duplicate them. An invariant companion (packages/experimental/agent-team/src/invariant.ts) replays each candidate event against its committed prefix and rejects invalid transitions before append.
State is replayed, never stored separately
The Lead Session log is the single source of truth. foldTeam() replays one root Session into the roster, task board, and queued-minus-delivered mailbox that every Team operation reads. It selects records by TeamId, so events inherited by an ordinary fork retain the ancestor id and never enter the new root's state. This is why the feature is durable across crashes and reloads:
team/member, team/task, team/message/* (appended + flushed to Lead Session log)
│
└── foldTeam(root Session) ──► roster ──► task board ──► queued-minus-delivered mailbox
(every read is a replay)Without durable session storage the events have nowhere to land, so the team features need durable session storage to activate. The smallest working setup is durable storage plus both Team packages:
# smallest team setup — durable storage plus both Team packages
- name: '@deepseek-ai/dsh-session-persistence-jsonl'
- name: '@deepseek-ai/dsh-experimental-agent-team'
- name: '@deepseek-ai/dsh-experimental-tool-agent-team'The service: TeamService
TeamService (ctx.agentTeams, packages/experimental/agent-team/src/index.ts) is the Host-side domain service. Every method takes the exact live calling Agent as an authority credential; only the Lead spawns, reassigns, or interrupts:
membership(agent: Agent): TeamMembership
listMembers(agent: Agent): TeamMemberView[]
spawnTeammate(caller: Agent, request: SpawnTeammateRequest): Promise<SpawnTeammateResult>
sendMessage(caller: Agent, request: SendTeamMessageRequest): Promise<SendTeamMessageResult>
createTask(caller: Agent, request: CreateTeamTaskRequest): Promise<TeamTaskView>
getTask(caller: Agent, id: TeamTaskId): TeamTaskView
listTasks(caller: Agent): TeamTaskView[]
updateTask(caller: Agent, request: UpdateTeamTaskRequest): Promise<TeamTaskView>
waitForChange(caller: Agent, timeoutMs: number, signal: AbortSignal): Promise<TeamWaitResult>
interrupt(caller: Agent, targetName: string): { previousStatus: 'running' | 'idle' | 'inactive' }Durable mailbox
A sent message is first appended to the Lead Session as team/message/queued and flushed before delivery is attempted, so a queued result is already safely stored and must not be resent. Two delivery modes cover two intents: a quiet message (send_message) delivers information without starting an idle teammate, while a follow-up (followup_task) makes the message the recipient's next turn. The target message begins with Team message <id> from <name>: and keeps the same id and sender in TeamMessageSource. A receipt is acknowledged with team/message/delivered only after the target Session durably holds the message identity in its pending inbox or recorded history. Delivery folds both live and persisted target inbox/history state before retrying, so a crash between inbox acceptance and model claim does not duplicate the message — retry plus target-Session de-duplication, not cross-process exactly-once delivery.
Shared task board
Tasks are complete versioned snapshots (TeamTaskSnapshot) with a numeric task-<n> id, a revision that increments per mutation, optional blockedBy edges (named, non-deleted, acyclic), and advisory writeScopes — normalized workspace-relative path prefixes, never locks:
interface TeamTaskSnapshot {
readonly id: TeamTaskId
readonly revision: number
readonly subject: string
readonly description: string
readonly status: TeamTaskStatus // pending | in_progress | completed | deleted
readonly ownerId?: SessionId
readonly blockedBy: TeamTaskId[]
readonly writeScopes: string[]
}Every mutation is compare-and-set: it carries expectedRevision, and a stale caller receives TEAM_TASK_STALE_REVISION instead of overwriting a newer value. A task is claimable only when everything it depends on is complete. File-hint overlap between two in-progress tasks produces warnings, never blocking. Deleted tasks remain tombstones for replay and id stability but disappear from the active list.
The tools: ten Team operations
@deepseek-ai/dsh-experimental-tool-agent-team registers the complete Team tool set in each live Team member's exact Agent scope (packages/experimental/tool-agent-team/src/index.ts), plus a team:policy system-prompt section ordered at the TEAM_POLICY slot (order 600 in packages/core/system-prompt/src/index.ts):
| Tool | Operation |
|---|---|
spawn_teammate | Lead-only: create one named, durable teammate (fresh or fork context) |
send_message | Quiet durable message to another member, without starting an idle member |
followup_task | Durable follow-up task that starts the target's turn when needed |
list_agents | List the Lead and every durable teammate with current runtime status |
wait_agent | Wait for the next teammate status, mailbox, or task change (10s–1h) |
interrupt_agent | Lead-only: interrupt one teammate's turn, preserving its pending inbox |
team_task_create | Create one unowned pending task on the shared board |
team_task_list | List shared tasks with status/owner/readiness filters and cursors |
team_task_get | Read the complete latest value of one task |
team_task_update | Compare-and-set a task action using the latest revision |
The TEAM_POLICY section (order 600) tells the model how to behave on a team: shared working directory, advisory write scopes, FS_STALE_VERSION rebasing, quiet vs. follow-up messaging, and the rule that the Lead must wait for required teammates before giving the final answer.
Known limitations
These are current package constraints, stated honestly — not a comparison with other coordination mechanisms:
- One process and one shared checkout — members share
cwdand observe edits immediately; there is no worktree, remote member, merge, or filesystem lock. - Advisory write scopes — Bash, formatters, code generators, and direct external writers can bypass filesystem version checks; Leads must coordinate ownership and review the final diff.
- Flat immutable roster — only the Lead creates direct teammates; there is no nested Team, rename, deletion, or name reuse.
- No automatic task-ownership release — idle, interruption, process exit, and failed work do not release a task owner.
- Mailbox is not cross-process exactly-once — concurrent harness processes over one Team are unsupported; the guarantee is process-local retry plus target-Session de-duplication.
- Needs durable session storage to activate — the team events must land in a persisted Lead Session log, and the feature is not wired into any shipped bundle.
Packages
| Package |
|---|
@deepseek-ai/dsh-experimental-agent-team |
@deepseek-ai/dsh-experimental-tool-agent-team |
@deepseek-ai/dsh-experimental-agent-team-profile |
@deepseek-ai/dsh-experimental-agent-team-web-profile |
@deepseek-ai/dsh-experimental-client-ui-agent-team |
Further reading
packages/experimental/README.md— the experimental group map and release exclusionpackages/experimental/agent-team/README.md— operation, authorization, recovery, and limit behaviorpackages/experimental/tool-agent-team/README.md— the model tool surfacedocs/subsystems/agent-team.md— durable Team types and thectx.agentTeamsservice APIpackages/experimental/agent-team/src/types.ts—TeamMemberSnapshot,TeamMessageSnapshot,TeamTaskSnapshot