@restranger/repi-subagents0.0.1-ca9b82c
Declarative subagents with Markdown definitions, Fleet UI, and isolated child sessions for pi-coding-agent
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
@restranger/repi-subagents
Declarative subagents for Pi. An agent is a Markdown file with YAML frontmatter plus a system prompt; the plugin discovers it, runs it in an isolated child Pi session, and returns its final answer to the parent.
Ships with 6 built-in default agents adapted from Claude Code's built-ins (general-purpose,
Explore, Plan, verification, statusline-setup, claude-code-guide) for Pi's conventions
(AGENTS.md, .pi/, ctx.ui), plus user and
project Markdown declarations and JSON overrides.
pi install npm:@restranger/repi-subagents
# or from this repository
pi --extension ./packages/subagents/src/index.ts
Built-in default agents
The plugin includes six built-in subagents, adapted from Claude Code to Pi:
| Agent | Purpose | Tools | Model |
|---|---|---|---|
general-purpose |
Complex, multi-step tasks and research. | * (all) |
inherit |
Explore |
Fast read-only codebase exploration. | read, bash, grep, find, ls |
haiku (fallback: inherit) |
Plan |
Software architect for implementation planning. | read, bash, grep, find, ls |
inherit |
verification |
Adversarial verification specialist to break changes. | default (read, bash, ...) |
inherit |
statusline-setup |
Write a Pi extension for a custom footer / status segment. | read, write, edit |
inherit |
claude-code-guide |
Answer questions about Claude Code, the Agent SDK, and the API. | bash, read, web_search, fetch_content |
haiku (fallback: inherit) |
Any built-in agent can be overridden by placing an .md file with the same name in your user or
project agent directory, or customized / disabled ("enabled": false) in subagents.json.
Agent file
---
name: scout
description: Fast codebase reconnaissance. Use for "where is X?" and "how does Y work?".
tools: read, grep, find, ls
model: inherit
fallback_models:
- backup/model
- inherit
thinking: low
max_turns: 12
background: false
prompt_mode: append
color: cyan
---
You are a read-only codebase scout. Search the repository, quote exact files and line
numbers, and return a concise report. Do not modify files.
The file name is the fallback agent name when name: is absent. description: is required: it is
the only thing the parent model sees before choosing an agent. This repository includes a
ready-to-use read-only example at .pi/agents/scout.md.
Frontmatter
| Field | Meaning |
|---|---|
name |
Agent id. Letters, digits, ., _, -; max 64 chars. Falls back to the file name. |
description |
Required. Short selection hint shown in the tool description. |
tools |
read, grep, find / [read, grep] / none / *. Omitted means the built-in set read, bash, edit, write, grep, find, ls. |
disallowedTools |
Removed after the allowlist is built. |
model |
inherit (default) or a model id; exact provider/model first, then a unique fuzzy match. |
fallback_models |
List of models to try in order if the primary model fails (resolution error, provider error, rate limits, quota, 4xx/5xx). Supports inherit. Aliases: fallbackModels, fallbacks, fallback_model. |
thinking |
off, minimal, low, medium, high, xhigh. Unknown values fall back to the parent. |
max_turns |
Positive integer; 0/absent = unlimited, values below 2 are raised to 2. |
background |
Default for the tool's background flag. |
prompt_mode |
append (default) appends the body to Pi's prompt; replace uses it as the whole system prompt. |
color |
Optional UI hint; stored for later presentation work. |
Aliases accepted for compatibility: allowed-tools, disallowed-tools, maxTurns,
run_in_background, systemPromptMode, effort (as thinking).
Unsupported fields such as hooks, mcpServers, skills, memory, isolation,
permission and permissionMode are ignored with a warning. They are not silently reinterpreted.
Discovery
Scanned recursively, lowest priority first; a later directory overrides the same name:
$PI_CODING_AGENT_DIR/agents/**/*.md, or~/.config/pi/agent/agents/**/*.mdand~/.pi/agent/agents/**/*.md$XDG_CONFIG_HOME/repi/agents/**/*.md(default~/.config/repi/agents)<project>/.pi/agents/**/*.md<project>/.repi/agents/**/*.md(highest)
Project directories are skipped when Pi reports the workspace as untrusted. Hidden directories,
node_modules, .git and *.chain.md files are ignored. /subagents reload rescans without
restarting Pi.
JSON overrides
Markdown remains the declaration format, but frontmatter values can be overridden without editing the file. Overrides live in:
$XDG_CONFIG_HOME/repi/subagents.json(default~/.config/repi/subagents.json)<project>/.repi/subagents.json(highest priority; skipped when the workspace is untrusted)
Both files are optional. Within JSON, project values win over user values. JSON is applied after Markdown discovery, so it overrides the already-resolved Markdown definition. The JSON file cannot create an agent that has no Markdown declaration.
{
"version": 1,
"agents": {
"scout": {
"description": "Project-specific reconnaissance agent",
"tools": ["read", "grep", "find", "ls"],
"disallowedTools": ["bash"],
"model": "antigravity/gemini-3.8-flash",
"fallbackModels": ["anthropic/claude-3-5-sonnet", "inherit"],
"thinking": "high",
"maxTurns": 40,
"background": true,
"promptMode": "append",
"color": "cyan",
"systemPrompt": "You are a read-only scout for this repository."
},
"Explore": {
"enabled": false
}
}
}
Agent names are case-insensitive. Supported fields are description, tools,
disallowedTools, model, fallbackModels, thinking, maxTurns, background, promptMode, color,
enabled and systemPrompt. Frontmatter-style aliases (max_turns, prompt_mode,
disallowed_tools, run_in_background, systemPromptMode, effort, allowed-tools, prompt,
system_prompt, fallback_models, fallbacks, fallback_model) and their hyphenated variants are accepted as well.
Special values:
nullremoves that field from a lower-priority JSON layer and falls back to the Markdown value."model": "inherit"/"thinking": "inherit"clears a model or thinking level declared in Markdown."maxTurns": 0removes a Markdown turn limit."tools": "inherit"resets the allowlist to the default built-in tools;"none"/[]means no tools;"*"means every parent tool."enabled": falsehides the agent. A higher-priority layer can re-enable it.systemPromptreplaces the Markdown body;promptModethen decides append vs replace.
Malformed JSON, unknown fields, unknown agent names and invalid values are reported by
/subagents list and subagent_list. Invalid values leave the Markdown value in place. The list
also shows which override files were read. Re-read both files with /subagents reload.
Tools
| Tool | Purpose |
|---|---|
subagent |
Run { agent, task, description?, background?, model?, fallbackModels?, maxTurns? }. prompt is accepted as a Claude-style alias for task. Foreground waits; background returns a run id. |
subagent_status |
One run by id, or every run in the session. |
subagent_wait |
Wait for ids (default: all active runs) with timeoutMs (default 120000). |
subagent_abort |
Abort a queued or running run. |
subagent_list |
Agents, discovery directories, override config files, diagnostics and runs. |
/subagents prints the same catalogue; /subagents reload rescans the files; /subagents fleet opens
the live dashboard described below; /subagents stop stops all active subagents (or /subagents stop <id> stops a specific run).
Tab completes /subagents to fleet|list|reload|stop, and Tab after fleet or stop lists
the run ids of the current session — generated ids cannot be typed from memory, so this is the way
to address one run without opening the dashboard. fleet also accepts a run id to open straight on
that run.
Children never receive subagent* tools, so a child cannot spawn grandchildren and make
wait/abort ownership ambiguous.
What the model sees before it calls the tool
Delegation quality depends on three surfaces, and each one has exactly one owner:
<rules>— thesubagenttool declarespromptGuidelines, so Pi renders six bullets in the ordinary system-prompt rules block, next to thebash/read/editrules: delegate broad multi-file exploration, keep one-off lookups inline, fan out independent questions in one turn, write self-contained briefs (the child sees neither the conversation norAGENTS.md), never delegate understanding, and collect background results before reporting. They are attached to the tool definition, so they disappear when the tool is inactive and never appear in children (which excludesubagent*).promptSnippetadds the tool to Pi'sAvailable toolslist.<repi_subagents>— the catalogue injected frombefore_agent_start: name, description and tool allowlist for every agent discovered on disk (user directories, project.pi/agentsand.repi/agents, plus override files), capped at 24 entries. Descriptions are clamped at a sentence boundary so the "how to call this agent" sentence survives. When the catalogue fits it closes with "do not callsubagent_listto discover agents"; when it is truncated the closing line points atsubagent_listinstead, so the hidden agents stay reachable.<repi_subagent_runs>— runs in flight plus finished runs whose result has not been collected, so the model neither duplicates a run nor reports completion without reading a background verdict.subagent_wait(and inspecting a finished run) marks the result as collected, which drops it from the section; the section is deleted entirely when nothing is left, so Pi patches the prompt back to its old shape.
Isolation and permissions
Each run gets an in-process child Pi session:
SessionManager.inMemory()— no transcript is written for P0.- A scoped
DefaultResourceLoaderwithnoExtensions,noSkills,noPromptTemplates,noThemesandnoContextFiles, plus a temporaryagentDirfor settings isolation. The loadercwdstays the real project so the prompt's<cwd>matches tool execution; ambient packages, project extensions, skills, themes, prompt templates andAGENTS.mddo not leak into the child. - Requested tools bring their own extensions. After the allowlist is resolved, the parent's
getAllTools()provenance decides which extension modules the child needs. Those modules are passed asadditionalExtensionPaths, so an agent that declaresweb_searchgets the extension that registersweb_search— not a second copy of every ambient plugin. Host built-ins (codemode,tool_search, MCP resource tools) are recreated through the SDK factories because SDK-created sessions do not load CLI built-ins. The parent@restranger/repi-permission-system-core,@restranger/repi-permission-system-modesand@restranger/repi-uiextensions register no child tools, so they stay parent-side;subagent*is always removed and@restranger/repi-subagentsis never loaded recursively. - Custom providers keep their runtime. The child receives the parent's
ModelRuntime(ctx.modelRegistry.runtime) instead of building a new one against the temporaryagentDir. Extension-registered providers, OAuth credentials and per-provider API adapters therefore work exactly as in the parent — a child can useopencode-free/*,antigravity/*or any other keyless/header-authenticated provider without re-authenticating. - Only the declaration's body (appended to Pi's base prompt or replacing it), model/thinking level, tool allowlist and the extensions that provide those tools are inherited.
- No parent conversation is inherited (fresh context); put all needed context in
task(promptis accepted as an alias for Claude-style callers).
When @restranger/repi-permission-system-core is installed, every child tool call is checked against the parent
session's re:permissions@1 service with source: "subagent". Hard denies and the parent's
active mode therefore still apply. P0 fails closed on ask (there is no parent-prompt routing
yet). Without @restranger/repi-permission-system-core, the declaration's tools: list is the authority.
Concurrency and background runs
Subagent runs share an in-process FIFO pool (default 4 concurrent). Concurrency can be configured via:
- Programmatic option:
maxConcurrentinSubagentsPluginOptions. - JSON override config:
"maxConcurrent": 8in.repi/subagents.jsonor~/.config/repi/subagents.json.
Runs beyond the concurrency limit enter the queued state and automatically start when an active slot frees up. Runs are not persisted across a Pi restart; P1 will add durable records and artifacts. subagent_wait can collect finished background results after they complete.
UI
Three surfaces share the manager's live run table. All of them are display-width aware: SGR colours survive truncation, while cursor movement, OSC titles and other control sequences are stripped from child/tool text before it reaches the terminal.
- Inline progress. A foreground
subagentcall streams into its own tool call throughonUpdate: status, elapsed time, tool count, turn budget, the two most recent finished steps and the child's current tool (↳ bash bun run test). The result card ends with the outcome or error. The widget stays out of the way of foreground runs, so the same progress is never shown twice. - Status widget above the editor. A tree of background runs plus the runs that just finished:
Agents · 2 active · 1 finished · 14.2k tok, one branch per run, the current child tool under the active row, tool count, tokens, turn budget and the result/error preview for finished rows. A completed run leaves the widget on the parent's next turn (errors and aborts after two turns), and the widget is unmounted when nothing is left to show. Every line is truncated to therender(width)value and the whole widget is bounded byterminal.rows(3–12 lines, six rows reserved for the dock), so it cannot push Pi's editor off screen. Hosts without a TUI (RPC, print, JSON) receive plain lines instead of the component. /subagents fleetinspector. An overlay pane (anchor: "center",width: "95%",maxHeight: "85%") — matchingpi-subagents— with a bordered roster on the left and the selected run on the right: status, id/model, elapsed time, tool count, tokens, turn budget, current tool, step tree, forwarded extensions, diagnostics, the task and the output/error.Enterexpands the detail to the full pane;u/dor page keys scroll it. Navigation uses Pi's keybindings (tui.select.up/down/confirm/cancel), so a remap inkeybindings.jsonapplies;j/k,Enter,xandq/Escwork regardless.xarms cancellation and a secondx/yconfirms it;n/Esckeeps the run. The roster scrolls to keep the selection visible and the footer prints the bindings actually configured. In hosts without a custom TUI component the same dashboard is emitted as a text notification.
Activity comes from the child session's tool_execution_start/tool_execution_end events and
from assistant turns, so the surfaces reflect the child's work without parsing its transcript.
The inspector keeps the chronological step list (SubagentStep[]), not the full conversation.
P0 limitations / next steps
- No parent-context fork, steering, intercom or batch fan-out. The
/subagents fleetinspector is read-only apart from cancelling a run; result handoff into the parent conversation is still manual viasubagent_wait. - No transcript drill-in: child sessions are in-memory (
SessionManager.inMemory()), so/subagents fleetshows the result preview and the recent tool list, not the child's conversation. - No Git worktree isolation; all children share the parent
cwd. - No shared task board or DAG tasks.
askis denied inside children until parent prompt routing lands.- No structured
yield_resultcontract; the final assistant text is the result.