Team Mode provides multi-worker coordination with bounded batch execution, task lifecycle tracking, and synthesized results. The leader agent decomposes a goal into discrete worker tasks, executes them with concurrency control, and merges outputs into a unified summary.
ν λͺ¨λλ λ€μ€ μ컀 μ‘°μ μ μ 곡ν©λλ€. μ νλ λ°°μΉ μ€ν, νμ€ν¬ μλͺ μ£ΌκΈ° μΆμ , μ’ ν© κ²°κ³Όλ₯Ό μ§μν©λλ€. 리λ μμ΄μ νΈκ° λͺ©νλ₯Ό κ°λ³ μ컀 νμ€ν¬λ‘ λΆν΄νκ³ , λμμ± μ μ΄λ‘ μ€νν ν μΆλ ₯μ ν΅ν© μμ½μΌλ‘ λ³ν©ν©λλ€.
Supports two execution backends: native subprocesses for fast headless operation, or tmux panes for human-readable, observable worker output. Workers receive strict guardrails that prevent recursive orchestration and scope creep.
λ κ°μ§ μ€ν λ°±μλλ₯Ό μ§μν©λλ€: λΉ λ₯Έ ν€λλ¦¬μ€ λμμ μν λ€μ΄ν°λΈ μλΈνλ‘μΈμ€, λλ μ¬λμ΄ μ½μ μ μλ κ΄μ°° κ°λ₯ν μ컀 μΆλ ₯μ μν tmux νμΈ. μ컀λ μ¬κ·μ μ€μΌμ€νΈλ μ΄μ κ³Ό λ²μ νμ₯μ λ°©μ§νλ μ격ν κ°λλ μΌμ λ°μ΅λλ€.
Workers are instructed not to spawn subagents, delegate to other agents, or run orchestration commands (/team, /ultrawork, etc.). They report changed files, verification performed, and remaining blockers before finishing.
μ컀λ μλΈμμ΄μ νΈ μμ±, λ€λ₯Έ μμ΄μ νΈμ μμ, μ€μΌμ€νΈλ μ΄μ
λͺ
λ Ή(/team, /ultrawork λ±) μ€νμ κΈμ§λ°μ΅λλ€. μλ£ μ λ³κ²½λ νμΌ, μνλ κ²μ¦, λ¨μ λΈλ‘컀λ₯Ό λ³΄κ³ ν©λλ€.
Team Mode is opt-in. Set the environment variable before starting pi:
ν λͺ¨λλ μ΅νΈμΈμ λλ€. piλ₯Ό μμνκΈ° μ μ νκ²½ λ³μλ₯Ό μ€μ νμΈμ:
When enabled, the team tool is registered in the root session only. Inside workers, PI_TEAM_WORKER=1 is automatically set to suppress recursive orchestration β workers cannot register the team or subagent tools.
νμ±νλλ©΄ team λκ΅¬κ° λ£¨νΈ μΈμ
μλ§ λ±λ‘λ©λλ€. μ컀 λ΄λΆμμλ μ¬κ·μ μ€μΌμ€νΈλ μ΄μ
μ μ΅μ νκΈ° μν΄ PI_TEAM_WORKER=1μ΄ μλμΌλ‘ μ€μ λ©λλ€ β μ컀λ team λλ subagent λꡬλ₯Ό λ±λ‘ν μ μμ΅λλ€.
The /team slash command accepts a goal and optional key-value parameters:
/team μ¬λμ λͺ
λ Ήμ λͺ©νμ μ νμ ν€-κ° λ§€κ°λ³μλ₯Ό λ°μ΅λλ€:
Parameters:
λ§€κ°λ³μ:
| Parameter | Typeνμ | DefaultκΈ°λ³Έκ° | Descriptionμ€λͺ |
|---|---|---|---|
goal |
stringλ¬Έμμ΄ | β | Task decomposition goalνμ€ν¬ λΆν΄ λͺ©ν |
agent |
stringλ¬Έμμ΄ | worker |
Agent name for workersμ컀μ μμ΄μ νΈ μ΄λ¦ |
backend |
auto / native / tmux |
auto |
Execution backendμ€ν λ°±μλ |
worker-count |
number (1β12)μ«μ (1β12) | β | Number of parallel workersλ³λ ¬ μ컀 μ |
worktree-policy |
off / on / auto |
off |
Git worktree isolationGit μν¬νΈλ¦¬ 격리 |
resume |
string (runId)λ¬Έμμ΄ (runId) | β | Resume an existing runκΈ°μ‘΄ μ€ν μ¬κ° |
resume-mode |
mark-interrupted / retry-stale |
mark-interrupted |
How to handle stale tasksμ€λλ νμ€ν¬ μ²λ¦¬ λ°©μ |
max-output |
numberμ«μ | β | Max output chars per workerμμ»€λΉ μ΅λ μΆλ ₯ λ¬Έμ μ |
Team Mode supports two execution backends. The auto mode prefers tmux when available and falls back to native.
ν λͺ¨λλ λ κ°μ§ μ€ν λ°±μλλ₯Ό μ§μν©λλ€. auto λͺ¨λλ tmuxλ₯Ό μ¬μ©ν μ μμΌλ©΄ μ νΈνκ³ , μμΌλ©΄ λ€μ΄ν°λΈλ‘ ν΄λ°±ν©λλ€.
| Backend | Descriptionμ€λͺ | Use Caseμ¬μ© μ¬λ‘ |
|---|---|---|
auto |
Tries native, falls back to tmuxλ€μ΄ν°λΈλ₯Ό μλνκ³ tmuxλ‘ ν΄λ°± | DefaultκΈ°λ³Έκ° |
native |
Subprocess workersμλΈνλ‘μΈμ€ μ컀 | Fast, headlessλΉ λ₯Έ ν€λλ¦¬μ€ |
tmux |
Human-readable tmux panesμ¬λμ΄ μ½μ μ μλ tmux νμΈ | Debugging, observableλλ²κΉ , κ΄μ°° κ°λ₯ |
When backend=native is forced, tmux detection is skipped entirely. When backend=tmux is forced and tmux is unavailable, pane creation fails immediately.
backend=nativeκ° κ°μ λλ©΄ tmux κ°μ§λ₯Ό μμ ν 건λλλλ€. backend=tmuxκ° κ°μ λμλλ° tmuxλ₯Ό μ¬μ©ν μ μμΌλ©΄ νμΈ μμ±μ΄ μ¦μ μ€ν¨ν©λλ€.
Tmux panes are created either in the current tmux window (if pi is already inside a tmux client) or in a new detached session. Pane metadata (session, window, pane ID, attach command, log paths) is stored on each task's terminal record.
tmux νμΈμ νμ¬ tmux μλ(piκ° μ΄λ―Έ tmux ν΄λΌμ΄μΈνΈ λ΄λΆμ μλ κ²½μ°) λλ μλ‘μ΄ λνμΉλ μΈμ μ μμ±λ©λλ€. νμΈ λ©νλ°μ΄ν°(μΈμ , μλ, νμΈ ID, μ°κ²° λͺ λ Ή, λ‘κ·Έ κ²½λ‘)λ κ° νμ€ν¬μ ν°λ―Έλ λ μ½λμ μ μ₯λ©λλ€.
Team Mode tracks three levels of status:
ν λͺ¨λλ μΈ μμ€μ μνλ₯Ό μΆμ ν©λλ€:
Tasks are created during goal decomposition, transition to pending when eligible, and execute through in_progress to a terminal state. The blocked state is reserved for dependency-based scheduling (future).
νμ€ν¬λ λͺ©ν λΆν΄ μ€ μμ±λκ³ , μ€ν κ°λ₯ν΄μ§λ©΄ pendingμΌλ‘ μ νλλ©°, in_progressλ₯Ό κ±°μ³ μ’
λ£ μνλ‘ μ΄λν©λλ€. blocked μνλ μμ‘΄μ± κΈ°λ° μ€μΌμ€λ§μ©μΌλ‘ μμ½λμ΄ μμ΅λλ€(ν₯ν).
The overall run status reflects aggregate worker progress. cancelled and interrupted are triggered by abort signals or Ctrl+C.
μ 체 μ€ν μνλ μ컀 μ§ν μν©μ μ§κ³νμ¬ λ°μν©λλ€. cancelledκ³Ό interruptedλ μ€λ¨ μκ·Έλμ΄λ Ctrl+Cμ μν΄ νΈλ¦¬κ±°λ©λλ€.
Commands (follow-up messages) use an optimistic concurrency FSM with a statusVersion counter. Terminal statuses can transition back to queued for retry. Retries are capped at 3 attempts β exceeding this marks the command blocked.
λͺ
λ Ή(νμ λ©μμ§)μ statusVersion μΉ΄μ΄ν°κ° μλ λκ΄μ λμμ± FSMμ μ¬μ©ν©λλ€. μ’
λ£ μνλ μ¬μλλ₯Ό μν΄ queuedλ‘ λ€μ μ νν μ μμ΅λλ€. μ¬μλλ μ΅λ 3νλ‘ μ νλλ©°, μ΄κ³Όνλ©΄ λͺ
λ Ήμ΄ blockedλ‘ νμλ©λλ€.
Every team run persists its state to a durable JSON file. This enables resume, debugging, and audit of past runs.
λͺ¨λ ν μ€νμ μνλ₯Ό λ΄κ΅¬μ± μλ JSON νμΌμ μ μ₯ν©λλ€. μ΄λ₯Ό ν΅ν΄ μ¬κ°, λλ²κΉ , κ³Όκ±° μ€ν κ°μ¬κ° κ°λ₯ν©λλ€.
Tmux logs are stored alongside the state file when using the tmux backend:
tmux λ°±μλ μ¬μ© μ tmux λ‘κ·Έκ° μν νμΌκ³Ό ν¨κ» μ μ₯λ©λλ€:
Writes are atomic β the record is written to a temp file first, then renamed.
μ°κΈ°λ μμμ μ λλ€ β λ μ½λλ₯Ό λ¨Όμ μμ νμΌμ μ΄ ν μ΄λ¦μ λ³κ²½ν©λλ€.
Interrupted or incomplete runs can be resumed by referencing their runId. Two strategies handle stale tasks:
μ€λ¨λκ±°λ μλ£λμ§ μμ μ€νμ runIdλ₯Ό μ°Έμ‘°νμ¬ μ¬κ°ν μ μμ΅λλ€. λ κ°μ§ μ λ΅μΌλ‘ μ€λλ νμ€ν¬λ₯Ό μ²λ¦¬ν©λλ€:
Marks stale in_progress tasks as interrupted. Stale commands are marked stale. Use this when you want to inspect what was running and decide manually.
μ€λλ in_progress νμ€ν¬λ₯Ό interruptedλ‘ νμν©λλ€. μ€λλ λͺ
λ Ήμ staleλ‘ νμλ©λλ€. μ€ν μ€μ΄λ μμ
μ κ²μ¬νκ³ μλμΌλ‘ κ²°μ νλ €λ©΄ μ΄ μ΅μ
μ μ¬μ©νμΈμ.
Resets stale in_progress tasks to pending for re-execution. Stale commands are retried (attempt incremented, reset to queued). Commands exceeding 3 attempts are marked blocked.
μ€λλ in_progress νμ€ν¬λ₯Ό pendingμΌλ‘ μ¬μ€μ νμ¬ μ¬μ€νν©λλ€. μ€λλ λͺ
λ Ήμ μ¬μλλ©λλ€(μλ νμ μ¦κ°, queuedλ‘ μ¬μ€μ ). 3νλ₯Ό μ΄κ³Όν λͺ
λ Ήμ blockedλ‘ νμλ©λλ€.
Send targeted messages to a specific worker or task in an existing run. The command creates a durable inbox entry, re-executes the worker with the new context, and records the result.
κΈ°μ‘΄ μ€νμ νΉμ μ컀λ νμ€ν¬μ λμ λ©μμ§λ₯Ό 보λ λλ€. λͺ λ Ήμ λ΄κ΅¬μ± μλ μΈλ°μ€ νλͺ©μ μμ±νκ³ , μ 컨ν μ€νΈλ‘ μ컀λ₯Ό μ¬μ€ννλ©°, κ²°κ³Όλ₯Ό κΈ°λ‘ν©λλ€.
The target can be a worker identifier (worker-1) or a task identifier (task-1).
λμμ μ컀 μλ³μ(worker-1) λλ νμ€ν¬ μλ³μ(task-1)κ° λ μ μμ΅λλ€.
Git worktree isolation can be controlled via the worktree-policy parameter:
Git μν¬νΈλ¦¬ 격리λ worktree-policy λ§€κ°λ³μλ‘ μ μ΄ν μ μμ΅λλ€:
| Policy | Behaviorλμ |
|---|---|
off |
No worktree isolation. Workers share the working tree.μν¬νΈλ¦¬ 격리 μμ. μμ»€κ° μμ νΈλ¦¬λ₯Ό 곡μ ν©λλ€. |
on |
Always use git worktrees for worker isolation.νμ git μν¬νΈλ¦¬λ₯Ό μ¬μ©νμ¬ μ컀λ₯Ό 격리ν©λλ€. |
auto |
Use worktrees if available (delegates to the legacy worktree boolean). Resolves to !!worktree.μ¬μ© κ°λ₯νλ©΄ μν¬νΈλ¦¬ μ¬μ©(λ κ±°μ worktree λΆλ¦¬μΈμ μμ). !!worktreeλ‘ ν΄μλ©λλ€. |
The resolved boolean is passed to runAgent() as the worktree option.
ν΄μλ λΆλ¦¬μΈμ worktree μ΅μ
μΌλ‘ runAgent()μ μ λ¬λ©λλ€.
| Env Varνκ²½ λ³μ | DefaultκΈ°λ³Έκ° | Descriptionμ€λͺ |
|---|---|---|
PI_ENABLE_TEAM_MODE |
(unset)(λ―Έμ€μ ) | Set to 1 to enable team mode1λ‘ μ€μ νμ¬ ν λͺ¨λ νμ±ν |
PI_TEAM_WORKER |
(unset)(λ―Έμ€μ ) | Auto-set inside workers to suppress recursive orchestrationμ컀 λ΄λΆμμ μλ μ€μ λμ΄ μ¬κ·μ μ€μΌμ€νΈλ μ΄μ μ΅μ |
PI_TEAM_RUN_STATE_ROOT |
cwd/.pi/agent/runs |
Override state file storage locationμν νμΌ μ μ₯ μμΉ μ¬μ μ |
The team tool is only registered when PI_ENABLE_TEAM_MODE=1 AND the session is a root session (not itself a team worker). Workers receive PI_TEAM_WORKER=1 and PI_SUBAGENT_MAX_DEPTH=1 in their environment.
team λꡬλ PI_ENABLE_TEAM_MODE=1μ΄κ³ μΈμ
μ΄ λ£¨νΈ μΈμ
(μμ μ΄ ν μμ»€κ° μλ)μΌ λλ§ λ±λ‘λ©λλ€. μ컀λ νκ²½μ PI_TEAM_WORKER=1κ³Ό PI_SUBAGENT_MAX_DEPTH=1μ λ°μ΅λλ€.
When the tool's AbortSignal fires, all pending and in_progress tasks are marked interrupted, registered tmux resources are cleaned up, and the run status is set to interrupted. The abort races against normal worker completion via Promise.race().
λꡬμ AbortSignalμ΄ λ°λνλ©΄ λͺ¨λ pending λ° in_progress νμ€ν¬κ° interruptedλ‘ νμλκ³ , λ±λ‘λ tmux 리μμ€κ° μ 리λλ©°, μ€ν μνκ° interruptedλ‘ μ€μ λ©λλ€. μ€λ¨μ Promise.race()λ₯Ό ν΅ν΄ μ μ μ컀 μλ£μ κ²½μν©λλ€.
Double Ctrl+C during pi interactive shutdown emits session_shutdown during runtimeHost.dispose rather than calling session.abort(). The extension registers a session_shutdown handler that calls cleanupActiveTeamTmuxResources(), ensuring all active tmux sessions and panes are cleaned up even when the abort signal path is bypassed.
pi μΈν°λν°λΈ μ’
λ£ μ€ μ΄μ€ Ctrl+Cλ session.abort()λ₯Ό νΈμΆνμ§ μκ³ runtimeHost.dispose μ€ session_shutdownμ λ°μμν΅λλ€. μ΅μ€ν
μ
μ cleanupActiveTeamTmuxResources()λ₯Ό νΈμΆνλ session_shutdown νΈλ€λ¬λ₯Ό λ±λ‘νμ¬, μ€λ¨ μκ·Έλ κ²½λ‘κ° μ°νλμ΄λ λͺ¨λ νμ± tmux μΈμ
κ³Ό νμΈμ΄ μ 리λλλ‘ ν©λλ€.
If pane creation partially fails (e.g., only 2 of 4 panes are created before an error), the already-created panes are cleaned up via cleanupTeamTmuxResources() to prevent orphaned tmux sessions.
νμΈ μμ±μ΄ λΆλΆμ μΌλ‘ μ€ν¨νλ©΄(μ: μ€λ₯ μ 4κ° μ€ 2κ°λ§ μμ±), κ³ λ¦½λ tmux μΈμ
μ λ°©μ§νκΈ° μν΄ μ΄λ―Έ μμ±λ νμΈμ΄ cleanupTeamTmuxResources()λ₯Ό ν΅ν΄ μ 리λ©λλ€.
An in-memory Set<TeamTmuxCleanupRegistration> tracks all active tmux resources across concurrent team runs. Registrations are added when tmux panes are created and removed on normal completion. The registry enables cross-run cleanup during session shutdown.
λ©λͺ¨λ¦¬ λ΄ Set<TeamTmuxCleanupRegistration>μ΄ λμ ν μ€ν μ 체μ λͺ¨λ νμ± tmux 리μμ€λ₯Ό μΆμ ν©λλ€. λ±λ‘μ tmux νμΈ μμ± μ μΆκ°λκ³ μ μ μλ£ μ μ κ±°λ©λλ€. λ μ§μ€νΈλ¦¬λ μΈμ
μ’
λ£ μ€ κ΅μ°¨ μ€ν μ 리λ₯Ό κ°λ₯νκ² ν©λλ€.
On success, tmux resources are cleaned immediately. On failure, tmux panes/sessions are intentionally left alive for debugging. Use cleanupActiveTeamTmuxResources() or attach to the session manually to inspect.
μ±κ³΅ μ tmux 리μμ€λ μ¦μ μ 리λ©λλ€. μ€ν¨ μ tmux νμΈ/μΈμ
μ λλ²κΉ
μ μν΄ μλμ μΌλ‘ μ΄λ €λ‘λλ€. cleanupActiveTeamTmuxResources()λ₯Ό μ¬μ©νκ±°λ μλμΌλ‘ μΈμ
μ μ°κ²°νμ¬ κ²μ¬νμΈμ.