@vadimcomanescu/pi-teams
v1.0.7
Published
Pi team orchestration extension for named teammates, shared task boards, and coordinated execution
Maintainers
Readme
pi-teams
Pi team orchestration extension for named teammates, shared task boards, and coordinated execution.
Forked from pi-subagents, then reshaped around a team-first workflow: lead sessions create one active team, spawn named teammates, coordinate through a shared task board, inspect everything through one /team surface, and synthesize results from automatic teammate notifications.
What pi-teams is for
- named teammates inside one lead-managed team
- shared mutable task boards, not private lead bookkeeping
- teammate continuation, both while running and after completion when a saved session exists
- notification-first coordination, with inspection tools as secondary support
- advanced execution paths still available through the low-level
teamtool
Installation
pi install npm:@vadimcomanescu/pi-teamsTo remove:
npx @vadimcomanescu/pi-teams --removeMaintainer release workflow
Releases are now guard-railed so npm publish cannot happen without first pushing git commits and a matching tag.
npm run release:publishWhat this does, in order:
- Fails if the working tree is dirty.
- Fails unless you are on
main. - Fails if
HEADis behindorigin/main. - Validates
package.jsonversion and matchingCHANGELOG.mdentry. - Pushes
HEADtoorigin/main. - Creates and pushes tag
v<package-version>. - Runs
npm publish.
Direct npm publish is blocked by prepublishOnly unless PI_TEAMS_RELEASE_SCRIPT=1 is explicitly set.
Team-first workflow
Lead sessions use the coordinator prompt by default. Start with the first-class team and task tools. Use the low-level team execution tool only when you intentionally want lower-level control.
Primary lead tools
| Tool | Purpose |
|------|--------|
| team_create | Create one active team for the current lead session |
| spawn_teammate | Launch a named teammate inside that team |
| check_teammate | Inspect teammate status and last summary |
| team_shutdown | Stop the active team |
| team_delete | Physically delete the current lead team once non-lead teammates are no longer active |
| task_create / task_list / task_read / task_update | Manage the shared task board |
Advanced execution tools
| Tool | Purpose |
|------|--------|
| team | Low-level execution for single, chain, and parallel runs |
| send_message | Follow up with a running teammate, or resume an idle teammate that still has a session |
| task_stop | Stop a running teammate or low-level execution |
After
team_create, follow-up team and task tools can omitteam_name. They resolve against the current team automatically.
team_shutdownstops teammates, marks the team shutdown, and releases owned open work back to the shared board.team_deleteis the final physical cleanup step. It fails while non-lead teammates are still active, can succeed without prior shutdown when nobody is active, and is a successful no-op when there is no current team.
check_teammateexposes lifecycle fields for coordinator decisions:mode,status,activity,is_active,state, and follow-up/resume details includingaddressable,can_resume,can_queue_follow_up, andcontinuation. Running teammates can becomeidlebetween turns. Idle teammates with a saved session can be resumed. Shutdown and orphaned teams are non-addressable.Plain-text
send_messagefollow-ups require a non-emptysummary.Graceful shutdown uses
send_messagestructured payloads. The lead sendsmessage: { type: "shutdown_request" }, then the teammate replies withto: "lead"andmessage: { type: "shutdown_response", request_id, approve, reason? }.Team messaging is durable across running and resumable teammates. The lead runtime polls teammate message state roughly once per second to route follow-ups and process shutdown responses.
task_updateis shared board state. Leads can edit any task. Teammates can claim and complete their own tasks. Leads can also set task dependencies withdepends_on(array of task IDs). Dependent tasks remain blocked until prerequisites are completed, and teammates cannot edit dependencies or delete tasks they do not own.
User says
Create a team with 3 teammates to review this repo:
- architecture on GPT-5.3 Codex
- testing on Codex
- docs on the default model
Create tasks for each area, wait for them to finish, then synthesize the results.Lead calls
team_create({
team_name: "repo-review",
description: "Review pi-teams for architecture, tests, and docs",
default_model: "openai/gpt-5.3-codex"
})
spawn_teammate({
name: "architecture",
prompt: "Review repository architecture and identify structural risks.",
cwd: "/home/vadim/Code/pi-teams",
model: "openai/gpt-5.3-codex"
})
spawn_teammate({
name: "testing",
prompt: "Review tests, missing coverage, and regression risks.",
cwd: "/home/vadim/Code/pi-teams",
model: "openai/gpt-5.3-codex"
})
spawn_teammate({
name: "docs",
prompt: "Review docs drift, README accuracy, and user contract clarity.",
cwd: "/home/vadim/Code/pi-teams",
// Uses default_model fallback
})
task_create({
subject: "Architecture review",
description: "Assess boundaries, naming, and rollout risks."
})
task_create({
subject: "Testing review",
description: "Find missing tests, weak assertions, and integration gaps."
})
task_create({
subject: "Docs review",
description: "Check README/help/install output against the real tool surface."
})
// Wait for teammate notifications. Completions arrive automatically as
// <task-notification> XML blocks. Use check_teammate only if something looks
// stuck, or if you want an explicit status snapshot before synthesizing.Operator command
/team
/team repo-review
/team --detail architecture
/team --detail architecture --full-prompt
/stop-all/team is the single operator surface for team inspection. The roster shows teammate count, compact state badges, and the latest meaningful activity. Use --detail <name> for teammate detail (mode, model, cwd, owned tasks, latest activity, availability, and the latest prompt or summary), and add --full-prompt to expand long text.
The lead TUI also shows a live teammate spinner widget (Team live) for the currently relevant teammates. It shows current task, current tool, and recent output in real time, and it is not a separate async/history surface.
Mode sync is available through structured messaging, for example:
send_message({ to: "docs", message: { type: "mode_set_request", mode: "plan" } })
(valid modes: default, plan, execute). Mode changes persist and are reflected in both /team and check_teammate.
Use default_model on team_create for the team-wide fallback. Override model per teammate only when one role needs something different.
Model resolution order is:
spawn_teammate({ model })- the team's
default_model - the spawned agent's own default model
Skill inheritance for teammates:
- If the lead session was started with
--skillsand/or--no-skills, teammate workers inherit those parent skill flags by default. - If an explicit agent/team skill override is provided for a worker run, that override takes precedence.
If you want predictable provider usage, set default_model explicitly to a provider and model you already have access to.
If you want pure tool visibility instead of slash commands, use:
task_list()
check_teammate({ agent_name: "architecture" })
check_teammate({ agent_name: "testing" })
check_teammate({ agent_name: "docs" })Prompt-template delegation (advanced)
If you use pi-prompt-template-model, you can wrap team delegation in a slash command:
---
description: Take a screenshot
model: claude-sonnet-4-20250514
team: browser-screenshoter
cwd: /tmp/screenshots
---
Use url in the prompt to take screenshot: $@Then /take-screenshot https://example.com switches to Sonnet, delegates to the browser-screenshoter agent with /tmp/screenshots as the working directory, and restores your model when done. Runtime overrides like --cwd=<path> and --team=<name> work too.
pi-prompt-template-model is entirely optional, pi-teams works standalone through the first-class team tools and advanced worker slash commands below.
Agents
Agents are markdown files with YAML frontmatter that define specialized worker configurations.
Agent file locations:
| Scope | Path | Priority |
|-------|------|----------|
| Builtin | ~/.pi/agent/extensions/pi-teams/agents/ | Lowest |
| User | ~/.pi/agent/agents/{name}.md | Medium |
| Project | .pi/agents/{name}.md (searches up directory tree) | Highest |
Use agentScope parameter to control discovery: "user", "project", or "both" (default; project takes priority).
Builtin agents: The extension ships with ready-to-use agents — scout, planner, worker, reviewer, context-builder, researcher, and delegate. They load at lowest priority so any user or project agent with the same name overrides them. Builtin agents appear with a [builtin] badge in listings and cannot be modified through management actions (create a same-named user agent to override instead).
Note: The
researcheragent usesweb_search,fetch_content, andget_search_contenttools which require the pi-web-access extension. Install it withpi install npm:pi-web-access.
Agent frontmatter:
---
name: scout
description: Fast codebase recon
tools: read, grep, find, ls, bash, mcp:chrome-devtools # mcp: requires pi-mcp-adapter
extensions: # absent=all, empty=none, csv=allowlist
model: claude-haiku-4-5
thinking: high # off, minimal, low, medium, high, xhigh
skill: safe-bash, chrome-devtools # comma-separated skills to inject
output: context.md # writes to {chain_dir}/context.md
defaultReads: context.md # comma-separated files to read
defaultProgress: true # maintain progress.md
interactive: true # (parsed but not enforced in v1)
---
Your system prompt goes here (the markdown body after frontmatter).The thinking field sets a default extended thinking level for the agent. At runtime it's appended as a :level suffix to the model string (e.g., claude-sonnet-4-5:high). If the model already has a thinking suffix (from a chain-clarify override), the agent's default is not double-applied.
Extension sandboxing
Use extensions in frontmatter to control which extensions a worker can access:
# Field absent: all extensions load (default behavior)
# Empty field: no extensions
extensions:
# Allowlist specific extensions
extensions: /abs/path/to/ext-a.ts, /abs/path/to/ext-b.tsSemantics:
extensionsabsent → all extensions loadextensions:empty →--no-extensionsextensions: a,b→--no-extensions --extension a --extension b
When extensions is present, it takes precedence over extension paths implied by tools entries.
MCP Tools (optional)
If you have the pi-mcp-adapter extension installed, workers can use MCP server tools directly. Without that extension, everything below is ignored, MCP integration is entirely optional.
Add mcp: prefixed entries to the tools field in agent frontmatter:
# All tools from a server
tools: read, bash, mcp:chrome-devtools
# Specific tools from a server
tools: read, bash, mcp:github/search_repositories, mcp:github/get_file_contents| Syntax | Effect |
|--------|--------|
| mcp:server-name | All tools from that MCP server |
| mcp:server-name/tool_name | One specific tool |
The mcp: items are additive — they don't affect which builtins the agent gets. tools: mcp:chrome-devtools (with no regular tools listed) gives the agent all default builtins plus chrome-devtools tools. To restrict builtins, list them explicitly: tools: read, bash, mcp:chrome-devtools.
Workers only get direct MCP tools when mcp: items are explicitly listed. Even if your mcp.json has directTools: true globally, a worker without mcp: in its frontmatter won't get any direct tools, keeping it lean. The mcp proxy tool is still available for discovery if needed.
First-run caveat: The MCP adapter caches tool metadata at startup. The first time you connect to a new MCP server, that cache is empty, so tools are only available through the generic
mcpproxy. After that first session, restart pi and direct tools become available.
Resolution priority: step override > agent frontmatter > disabled
Quick Commands
| Command | Description |
|---------|-------------|
| /run <agent> <task> | Run a single agent with a task |
| /chain agent1 "task1" -> agent2 "task2" | Run agents in sequence with per-step tasks |
| /parallel agent1 "task1" -> agent2 "task2" | Run agents in parallel with per-step tasks |
| /agents | Open the Agents Manager overlay |
All commands validate agent names locally and tab-complete them, then route through the tool framework for full live progress rendering. Results are sent to the conversation for the LLM to discuss.
Per-Step Tasks
Use -> to separate steps and give each step its own task with quotes or --:
/chain scout "scan the codebase" -> planner "create implementation plan"
/parallel scanner "find security issues" -> reviewer "check code style"Both double and single quotes work. The -- delimiter also works: /chain scout -- scan code -> planner -- analyze auth.
Steps without a task inherit behavior from the execution mode: chain steps get {previous} (output from the prior step), parallel steps get the first available task as a fallback.
/chain scout "analyze auth" -> planner -> implementer
# scout: "analyze auth", planner: gets scout's output, implementer: gets planner's outputShared task (no ->): Space-separated agents with a single -- task:
/chain scout planner -- analyze the auth system
/parallel scout reviewer -- check for security issuesInline Per-Step Config
Append [key=value,...] to any agent name to override its defaults:
/chain scout[output=context.md] "scan code" -> planner[reads=context.md] "analyze auth"
/run scout[model=anthropic/claude-sonnet-4] summarize this codebase
/parallel scanner[output=scan.md] "find issues" -> reviewer[output=review.md] "check style"| Key | Example | Description |
|-----|---------|-------------|
| output | output=context.md | Write results to file (relative to chain dir for /chain//parallel; for /run, absolute paths are used as-is and relative paths resolve against cwd) |
| reads | reads=a.md+b.md | Read files before executing (+ separates multiple) |
| model | model=anthropic/claude-sonnet-4 | Override model for this step |
| skills | skills=planning+review | Override skills (+ separates multiple) |
| progress | progress | Enable progress tracking |
Set output=false, reads=false, or skills=false to explicitly disable.
Execution Mode
All slash commands run in foreground. This keeps the UI stable, with one live team surface.
Forked Context Execution
Add --fork at the end of /run, /chain, or /parallel to run with context: "fork":
/run reviewer "review this diff" --fork
/chain scout "analyze this branch" -> planner "plan next steps" --fork
/parallel scout "audit frontend" -> reviewer "audit backend" --forkUse --fork when you want child runs to start from a branched session based on the parent leaf.
Agents Manager
Press Ctrl+Shift+M or type /agents to open the Agents Manager overlay — a TUI for browsing, viewing, editing, creating, and launching agents and chains.
Screens:
| Screen | Description | |--------|-------------| | List | Browse all agents and chains with search/filter, scope badges, chain badges | | Detail | View resolved prompt, frontmatter fields, recent run history | | Edit | Edit fields with specialized pickers (model, thinking, skills, prompt editor) | | Chain Detail | View chain steps with flow visualization and dependency map | | Parallel Builder | Build parallel execution slots, add same agent multiple times, per-slot task overrides | | Task Input | Enter task and launch with optional skip-clarify toggle | | New Agent | Create from templates (Blank, Scout, Planner, Implementer, Code Reviewer, Blank Chain) |
List screen keybindings:
↑↓— navigate agents/chainsEnter— view detail- Type any character — search/filter
Tab— toggle selection (agents only)Ctrl+N— new agent from templateCtrl+K— clone current itemCtrl+DorDel— delete current itemCtrl+R— run selected (1 agent: launch, 2+: sequential chain)Ctrl+P— open parallel builder (from selection or cursor agent)Esc— clear query, then selection, then close overlay
Parallel builder keybindings:
↑↓— navigate slotsCtrl+A— add agent (opens search picker)DelorCtrl+D— remove slotEnter— edit per-slot task overrideCtrl+R— continue to task input (requires 2+ slots)Esc— back to list
Task input keybindings:
Enter— launch (or quick run if skip-clarify is on)Tab— toggle skip-clarify (defaults to on for all manager launches)Esc— back
Multi-select workflow: Select agents with Tab, then press Ctrl+R for a sequential chain or Ctrl+P to open the parallel builder. The parallel builder lets you add the same agent multiple times, set per-slot task overrides, and launch N agents in parallel. Slots without a custom task use the shared task entered on the next screen.
Chain Files
Chains are .chain.md files stored alongside agent files. They define reusable multi-step pipelines.
Chain file locations:
| Scope | Path |
|-------|------|
| User | ~/.pi/agent/agents/{name}.chain.md |
| Project | .pi/agents/{name}.chain.md |
Format:
---
name: scout-planner
description: Gather context then plan implementation
---
## scout
output: context.md
Analyze the codebase for {task}
## planner
reads: context.md
model: anthropic/claude-sonnet-4-5:high
progress: true
Create an implementation plan based on {previous}Each ## agent-name section defines a step. Config lines (output, reads, model, skills, progress) go immediately after the header. A blank line separates config from the task text. Chains support the same three-state semantics as tool params: omitted (inherit from agent), value (override), false (disable).
Chains can be created from the Agents Manager template picker ("Blank Chain"), or saved from the chain-clarify TUI during execution.
Features (beyond base)
- Slash Commands:
/run,/chain,/parallelwith tab-completion and live progress - Agents Manager Overlay: Browse, view, edit, create, delete, and launch agents/chains from a TUI (
Ctrl+Shift+M) - Management Actions: LLM can list, inspect, create, update, and delete agent/chain definitions via
actionfield - Chain Files: Reusable
.chain.mdfiles with per-step config, saveable from the clarify TUI - Multi-select & Parallel: Select agents in the overlay, launch as chain or parallel
- Run History: Per-agent JSONL recording of task, exit code, duration; shown on detail screen
- Thinking Level: First-class
thinkingfrontmatter field with picker UI and runtime suffix application - Agent Templates: Create agents from presets (Scout, Planner, Implementer, Code Reviewer, Blank Chain)
- Skill Injection: Agents declare skills in frontmatter; skills get injected into system prompts
- Parallel-in-Chain: Fan-out/fan-in patterns with
{ parallel: [...] }steps within chains - Chain Clarification TUI: Interactive preview/edit of chain templates and behaviors before execution
- Agent Frontmatter Extensions: Agents declare default chain behavior (
output,defaultReads,defaultProgress,skill) - Chain Artifacts: Shared directory at
<tmpdir>/pi-chain-runs/{runId}/for inter-step files - Solo Agent Output: Agents with
outputwrite to temp dir and return path to caller - Live Progress Display: Real-time visibility during sync execution showing current tool, recent output, tokens, and duration
- Output Truncation: Configurable byte/line limits via
maxOutput - Debug Artifacts: Input/output/JSONL/metadata files per task
- Session Logs: JSONL session files with paths shown in output
- Session-scoped Notifications: Team completions notify the originating session
Modes
| Mode | Notes |
|------|-------|
| Single | { agent, task } - agents with output write to temp dir |
| Chain | { chain: [{agent, task}...] } with {task}, {previous}, {chain_dir} variables |
| Parallel | { tasks: [{agent, task}...] } |
Execution context defaults to context: "fresh", which starts each child run from a clean session. Set context: "fork" to start each child from a real branched session created from the parent's current leaf.
Clarify TUI for single/parallel:
Single and parallel modes also support the clarify TUI for previewing/editing parameters before execution. Unlike chains, they default to no TUI - use clarify: true to enable:
// Single agent with clarify TUI
{ agent: "scout", task: "Analyze the codebase", clarify: true }
// Parallel tasks with clarify TUI
{ tasks: [{agent: "scout", task: "Analyze frontend"}, ...], clarify: true }Clarification TUI keybindings:
Navigation mode:
Enter- RunEsc- Cancel↑↓- Navigate between steps/tasks (parallel, chain)e- Edit task/template (all modes)m- Select model (all modes)t- Select thinking level (all modes)s- Select skills (all modes)w- Edit writes/output file (single, chain only)r- Edit reads list (chain only)p- Toggle progress tracking (chain only)S- Save current overrides to agent's frontmatter file (all modes)W- Save chain configuration to a.chain.mdfile (chain only)
Model selector mode:
↑↓- Navigate model listEnter- Select modelEsc- Cancel (keep current model)- Type to filter (fuzzy search by model name or provider)
Thinking level selector mode:
↑↓- Navigate level listEnter- Select levelEsc- Cancel (keep current level)
Skill selector mode:
↑↓- Navigate skill listSpace- Toggle skill selectionEnter- Confirm selectionEsc- Cancel (keep current skills)- Type to filter (fuzzy search by name or description)
Edit mode (full-screen editor with word wrapping):
Esc- Save changes and exitCtrl+C- Discard changes and exit←→- Move cursor left/rightAlt+←→- Move cursor by word↑↓- Move cursor up/down by display line (auto-scrolls)Page Up/DownorShift+↑↓- Move cursor by viewport (12 lines)Home/End- Start/end of current display lineCtrl+Home/End- Start/end of textAlt+Backspace- Delete word backward- Paste supported (multi-line in multi-line editors)
Skills
Skills are specialized instructions loaded from SKILL.md files and injected into the agent's system prompt.
Skill locations (project-first precedence):
- Project:
.pi/skills/{name}/SKILL.md - Project packages:
.pi/npm/node_modules/*viapackage.json -> pi.skills - Project settings:
.pi/settings.json -> skills - User:
~/.pi/agent/skills/{name}/SKILL.md - User packages:
~/.pi/agent/npm/node_modules/*viapackage.json -> pi.skills - User settings:
~/.pi/agent/settings.json -> skills
Usage:
// Agent with skills from frontmatter
{ agent: "scout", task: "..." } // uses agent's default skills
// Override skills at runtime
{ agent: "scout", task: "...", skill: "tmux, safe-bash" }
// Disable all skills (including agent defaults)
{ agent: "scout", task: "...", skill: false }
// Chain with chain-level skills (additive to agent skills)
{ chain: [...], skill: "code-review" }
// Chain step with skill override
{ chain: [
{ agent: "scout", skill: "safe-bash" }, // only safe-bash
{ agent: "worker", skill: false } // no skills at all
]}Skill injection format:
<skill name="safe-bash">
[skill content from SKILL.md, frontmatter stripped]
</skill>Missing skills: If a skill cannot be found, execution continues with a warning shown in the result summary.
Usage
These are the parameters the LLM agent passes when it calls the team tool, not something you type directly. The agent decides to use these based on your conversation. For user-facing commands, see Quick Commands above.
team tool parameters:
// Single agent
{ agent: "worker", task: "refactor auth" }
{ agent: "scout", task: "find todos", maxOutput: { lines: 1000 } }
{ agent: "scout", task: "investigate", output: false } // disable file output
// Single agent from parent-session fork (real branched session at current leaf)
{ agent: "worker", task: "continue this thread", context: "fork" }
// Parallel
{ tasks: [{ agent: "scout", task: "a" }, { agent: "scout", task: "b" }] }
// Parallel with forked context (each task gets its own isolated fork)
{ tasks: [{ agent: "scout", task: "audit frontend" }, { agent: "reviewer", task: "audit backend" }], context: "fork" }
// Chain with TUI clarification (default)
{ chain: [
{ agent: "scout", task: "Gather context for auth refactor" },
{ agent: "planner" }, // task defaults to {previous}
{ agent: "worker" }, // uses agent defaults for reads/progress
{ agent: "reviewer" }
]}
// Chain with forked context (each step gets its own isolated fork of the same parent leaf)
{ chain: [
{ agent: "scout", task: "Analyze current branch decisions" },
{ agent: "planner", task: "Plan from {previous}" }
], context: "fork" }
// Chain without TUI
{ chain: [...], clarify: false }
// Chain with behavior overrides
{ chain: [
{ agent: "scout", task: "find issues", output: false }, // text-only, no file
{ agent: "worker", progress: false } // disable progress tracking
]}
// Chain with parallel step (fan-out/fan-in)
{ chain: [
{ agent: "scout", task: "Gather context for the codebase" },
{ parallel: [
{ agent: "worker", task: "Implement auth based on {previous}" },
{ agent: "worker", task: "Implement API based on {previous}" }
]},
{ agent: "reviewer", task: "Review all changes from {previous}" }
]}
// Parallel step with options
{ chain: [
{ agent: "scout", task: "Find all modules" },
{ parallel: [
{ agent: "worker", task: "Refactor module A" },
{ agent: "worker", task: "Refactor module B" },
{ agent: "worker", task: "Refactor module C" }
], concurrency: 2, failFast: true } // limit concurrency, stop on first failure
]}
// Chain with parallel step
{ chain: [
{ agent: "scout", task: "Gather context" },
{ parallel: [
{ agent: "worker", task: "Implement feature A based on {previous}" },
{ agent: "worker", task: "Implement feature B based on {previous}" }
]},
{ agent: "reviewer", task: "Review all changes from {previous}" }
], clarify: false }Management Actions
Agent definitions are not loaded into LLM context by default. Management actions let the LLM discover, inspect, create, and modify agent and chain definitions at runtime through the team tool, with no manual file editing or restart required. Newly created agents are immediately usable in the same session. Set action and omit execution payloads (task, chain, tasks).
// Discover all agents and chains (management defaults to both scopes)
{ action: "list" }
{ action: "list", agentScope: "project" }
// Inspect one agent or chain (searches both scopes)
{ action: "get", agent: "scout" }
{ action: "get", chainName: "review-pipeline" }
// Create agent
{ action: "create", config: {
name: "Code Scout",
description: "Scans codebases for patterns and issues",
scope: "user",
systemPrompt: "You are a code scout...",
model: "anthropic/claude-sonnet-4",
tools: "read, bash, mcp:github/search_repositories",
extensions: "", // empty = no extensions
skills: "parallel-scout",
thinking: "high",
output: "context.md",
reads: "shared-context.md",
progress: true
}}
// Create chain (presence of steps creates .chain.md)
{ action: "create", config: {
name: "review-pipeline",
description: "Scout then review",
scope: "project",
steps: [
{ agent: "scout", task: "Scan {task}", output: "context.md" },
{ agent: "reviewer", task: "Review {previous}", reads: ["context.md"] }
]
}}
// Update agent fields (merge semantics)
{ action: "update", agent: "scout", config: { model: "openai/gpt-4o" } }
{ action: "update", agent: "scout", config: { output: false, skills: "" } } // clear optional fields
{ action: "update", chainName: "review-pipeline", config: {
steps: [
{ agent: "scout", task: "Scan {task}", output: "context.md" },
{ agent: "reviewer", task: "Improved review of {previous}", reads: ["context.md"] }
]
}}
// Delete definitions
{ action: "delete", agent: "scout" }
{ action: "delete", chainName: "review-pipeline" }Notes:
createusesconfig.scope("user"or"project"), notagentScope.update/deleteuseagentScopeonly for scope disambiguation when the same name exists in both scopes.- Agent config mapping:
reads -> defaultReads,progress -> defaultProgress,extensionscontrols extension sandboxing, andtoolssupportsmcp:entries that map to direct MCP tools. - To clear any optional field, set it to
falseor""(e.g.,{ model: false }or{ skills: "" }). Both work for all string-typed fields.
Parameters
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| agent | string | - | Agent name (single mode) or target for management get/update/delete |
| task | string | - | Task string (single mode) |
| action | string | - | Management action: list, get, create, update, delete |
| chainName | string | - | Chain name for management get/update/delete |
| config | object | - | Agent or chain config for management create/update |
| output | string \| false | agent default | Override output file for single agent (absolute path as-is, relative path resolved against cwd) |
| skill | string \| string[] \| false | agent default | Override skills (comma-separated string, array, or false to disable) |
| model | string | agent default | Override model for single agent |
| tasks | {agent, task, cwd?, skill?}[] | - | Parallel tasks (sync only) |
| chain | ChainItem[] | - | Sequential steps with behavior overrides (see below) |
| context | "fresh" \| "fork" | fresh | Execution context mode. fork uses a real branched session from the parent's current leaf for each child run |
| chainDir | string | <tmpdir>/pi-chain-runs/ | Persistent directory for chain artifacts (default auto-cleaned after 24h) |
| clarify | boolean | true (chains) | Show TUI to preview/edit chain; implies sync mode |
| agentScope | "user" \| "project" \| "both" | both | Agent discovery scope (project wins on name collisions) |
| cwd | string | - | Override working directory |
| maxOutput | {bytes?, lines?} | 200KB, 5000 lines | Truncation limits for final output |
| artifacts | boolean | true | Write debug artifacts |
| includeProgress | boolean | false | Include full progress in result |
| share | boolean | false | Upload session to GitHub Gist (see Session Sharing) |
| sessionDir | string | - | Override session log directory (takes precedence over defaultSessionDir and parent-session-derived path) |
context: "fork" fails fast when the parent session is not persisted, the current leaf is missing, or a branched child session cannot be created. It never silently downgrades to fresh.
ChainItem can be either a sequential step or a parallel step:
Sequential step fields:
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| agent | string | required | Agent name |
| task | string | {task} or {previous} | Task template (required for first step) |
| cwd | string | - | Override working directory |
| output | string \| false | agent default | Override output filename or disable |
| reads | string[] \| false | agent default | Override files to read from chain dir |
| progress | boolean | agent default | Override progress.md tracking |
| skill | string \| string[] \| false | agent default | Override skills or disable all |
| model | string | agent default | Override model for this step |
Parallel step fields:
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| parallel | ParallelTask[] | required | Array of tasks to run concurrently |
| concurrency | number | 4 | Max concurrent tasks |
| failFast | boolean | false | Stop remaining tasks on first failure |
ParallelTask fields: (same as sequential step)
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| agent | string | required | Agent name |
| task | string | {previous} | Task template |
| cwd | string | - | Override working directory |
| output | string \| false | agent default | Override output (namespaced to parallel-N/M-agent/) |
| reads | string[] \| false | agent default | Override files to read |
| progress | boolean | agent default | Override progress tracking |
| skill | string \| string[] \| false | agent default | Override skills or disable all |
| model | string | agent default | Override model for this task |
Chain Variables
Templates support three variables:
| Variable | Description |
|----------|-------------|
| {task} | Original task from first step (use in subsequent steps) |
| {previous} | Output from prior step (or aggregated outputs from parallel step) |
| {chain_dir} | Path to chain artifacts directory |
Parallel output aggregation: When a parallel step completes, all outputs are concatenated with clear separators:
=== Parallel Task 1 (worker) ===
[output from first task]
=== Parallel Task 2 (worker) ===
[output from second task]This aggregated output becomes {previous} for the next step.
Extension Configuration
pi-teams reads optional JSON config from ~/.pi/agent/extensions/pi-teams/config.json.
defaultSessionDir
defaultSessionDir sets the fallback directory used for session logs. Eg:
{
"defaultSessionDir": "~/.pi/agent/sessions/team/"
}Session root resolution follows this precedence:
params.sessionDirfrom theteamtool callconfig.defaultSessionDir- Derived from parent session (stored alongside parent session file)
Sessions are always enabled, every worker run gets a session directory for tracking.
orphanCleanupMaxAgeHours
orphanCleanupMaxAgeHours controls startup cleanup for stale orphaned team directories. Teams in orphaned state older than this threshold are removed on lead-session startup/switch/branch. Active teams are never removed.
{
"orphanCleanupMaxAgeHours": 72
}Chain Directory
Each chain run creates <tmpdir>/pi-chain-runs/{runId}/ containing:
context.md- Scout/context-builder outputplan.md- Planner outputprogress.md- Worker/reviewer shared progressparallel-{stepIndex}/- Subdirectories for parallel step outputs0-{agent}/output.md- First parallel task output1-{agent}/output.md- Second parallel task output
- Additional files as written by agents
Directories older than 24 hours are cleaned up on extension startup.
Artifacts
Location: {sessionDir}/team-artifacts/ or <tmpdir>/pi-team-artifacts/
Files per task:
{runId}_{agent}_input.md- Task prompt{runId}_{agent}_output.md- Full output (untruncated){runId}_{agent}.jsonl- Event stream (sync only){runId}_{agent}_meta.json- Timing, usage, exit code
Session Logs
Session files (JSONL) are stored under a per-run session directory. Directory selection follows the same precedence as session root resolution: explicit sessionDir > config.defaultSessionDir > parent-session-derived path. The session file path is shown in output.
When context: "fork" is used, each child run starts with --session <branched-session-file> produced from the parent's current leaf. This is a real session fork, not injected summary text.
Session Sharing
When share: true is passed, the extension will:
- Export the full session (all tool calls, file contents, outputs) to an HTML file
- Upload it to a GitHub Gist using your
ghCLI credentials - Return a shareable URL (
https://shittycodingagent.ai/session/?<gistId>)
This is disabled by default. Session data may contain sensitive information like source code, file paths, environment variables, or credentials that appear in tool outputs.
To enable sharing for a specific run:
{ agent: "scout", task: "...", share: true }Requirements:
- GitHub CLI (
gh) must be installed and authenticated (gh auth login) - Gists are created as "secret" (unlisted but accessible to anyone with the URL)
Live progress (sync mode)
During sync execution, the collapsed view shows real-time progress for single, chain, and parallel modes.
Chains:
- Header:
... chain 1/2 | 8 tools, 1.4k tok, 38s - Chain visualization with status:
✓scout → ●planner(✓=done, ●=running, ○=pending, ✗=failed) - Current tool:
> read: packages/tui/src/... - Recent output lines (last 2-3 lines)
Parallel:
- Header:
... parallel 2/4 | 12 tools, 2.1k tok, 15s - Per-task step cards showing status icon, agent name, model, tool count, and duration
- Current tool and recent output for each running task
Press Ctrl+O to expand the full streaming view with complete output per step.
Note: Chain visualization (the
✓scout → ●plannerline) is only shown for sequential chains. Chains with parallel steps show per-step cards instead.
Nested worker recursion guard
Workers can themselves call the team tool, which risks unbounded recursive spawning (slow, expensive, hard to observe). A depth guard prevents this.
By default nesting is limited to 2 levels: main session → worker → nested worker. Any deeper team calls are blocked and return an error with guidance to the calling agent.
Override the limit with PI_TEAM_MAX_DEPTH set before starting pi:
export PI_TEAM_MAX_DEPTH=3 # allow one more level (use with caution)
export PI_TEAM_MAX_DEPTH=1 # only allow direct workers, no nesting
export PI_TEAM_MAX_DEPTH=0 # disable worker delegation entirelyPI_TEAM_DEPTH is an internal variable propagated automatically to child processes -- don't set it manually.
Events
Lifecycle events:
team:startedteam:complete
notify.ts consumes team:complete as the canonical completion channel.
Files
├── index.ts # Main extension, tool registration, overlay dispatch
├── agents.ts # Agent + chain discovery, frontmatter parsing
├── skills.ts # Skill resolution, caching, and discovery
├── settings.ts # Chain behavior resolution, templates, chain dir
├── chain-clarify.ts # TUI for chain/single/parallel clarification
├── chain-execution.ts # Chain orchestration (sequential + parallel)
├── chain-serializer.ts # Parse/serialize .chain.md files
├── execution.ts # Core runSync, applyThinkingSuffix
├── render.ts # TUI rendering (widget, tool result display)
├── artifacts.ts # Artifact management
├── formatters.ts # Output formatting utilities
├── schemas.ts # TypeBox parameter schemas
├── utils.ts # Shared utility functions
├── types.ts # Shared types and constants
├── parallel-utils.ts # Parallel execution utilities
├── pi-spawn.ts # Cross-platform pi CLI spawning
├── single-output.ts # Solo agent output file handling
├── notify.ts # Completion notifications
├── completion-dedupe.ts # Completion deduplication for notifications
├── file-coalescer.ts # Debounced file write coalescing
├── jsonl-writer.ts # JSONL event stream writer
├── agent-manager.ts # Overlay orchestrator, screen routing, CRUD
├── agent-manager-list.ts # List screen (search, multi-select, progressive footer)
├── agent-manager-detail.ts # Detail screen (resolved prompt, runs, fields)
├── agent-manager-edit.ts # Edit screen (pickers, prompt editor)
├── agent-manager-parallel.ts # Parallel builder screen (slot management, agent picker)
├── agent-manager-chain-detail.ts # Chain detail screen (flow visualization)
├── agent-management.ts # Management action handlers (list, get, create, update, delete)
├── agent-serializer.ts # Serialize agents to markdown frontmatter
├── agent-scope.ts # Agent scope resolution utilities
├── agent-selection.ts # Agent selection state management
├── agent-templates.ts # Agent/chain creation templates
├── render-helpers.ts # Shared pad/row/header/footer helpers
├── run-history.ts # Per-agent run recording (JSONL)
└── text-editor.ts # Shared text editor (word nav, paste)