omp packages

@restranger/repi-subagents0.0.1-ca9b82c

Declarative subagents with Markdown definitions, Fleet UI, and isolated child sessions for pi-coding-agent

restranger Published 1 hour ago MIT ~605 downloads/mo

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.

Did it work for you?

Result

One report per person. A new report replaces your old one.

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:

  1. $PI_CODING_AGENT_DIR/agents/**/*.md, or ~/.config/pi/agent/agents/**/*.md and ~/.pi/agent/agents/**/*.md
  2. $XDG_CONFIG_HOME/repi/agents/**/*.md (default ~/.config/repi/agents)
  3. <project>/.pi/agents/**/*.md
  4. <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:

  1. $XDG_CONFIG_HOME/repi/subagents.json (default ~/.config/repi/subagents.json)
  2. <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:

  • null removes 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": 0 removes a Markdown turn limit.
  • "tools": "inherit" resets the allowlist to the default built-in tools; "none" / [] means no tools; "*" means every parent tool.
  • "enabled": false hides the agent. A higher-priority layer can re-enable it.
  • systemPrompt replaces the Markdown body; promptMode then 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:

  1. <rules> — the subagent tool declares promptGuidelines, so Pi renders six bullets in the ordinary system-prompt rules block, next to the bash/read/edit rules: 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 nor AGENTS.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 exclude subagent*). promptSnippet adds the tool to Pi's Available tools list.
  2. <repi_subagents> — the catalogue injected from before_agent_start: name, description and tool allowlist for every agent discovered on disk (user directories, project .pi/agents and .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 call subagent_list to discover agents"; when it is truncated the closing line points at subagent_list instead, so the hidden agents stay reachable.
  3. <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 DefaultResourceLoader with noExtensions, noSkills, noPromptTemplates, noThemes and noContextFiles, plus a temporary agentDir for settings isolation. The loader cwd stays the real project so the prompt's <cwd> matches tool execution; ambient packages, project extensions, skills, themes, prompt templates and AGENTS.md do 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 as additionalExtensionPaths, so an agent that declares web_search gets the extension that registers web_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-modes and @restranger/repi-ui extensions register no child tools, so they stay parent-side; subagent* is always removed and @restranger/repi-subagents is 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 temporary agentDir. Extension-registered providers, OAuth credentials and per-provider API adapters therefore work exactly as in the parent — a child can use opencode-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 (prompt is 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:

  1. Programmatic option: maxConcurrent in SubagentsPluginOptions.
  2. JSON override config: "maxConcurrent": 8 in .repi/subagents.json or ~/.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 subagent call streams into its own tool call through onUpdate: 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 the render(width) value and the whole widget is bounded by terminal.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 fleet inspector. An overlay pane (anchor: "center", width: "95%", maxHeight: "85%") — matching pi-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. Enter expands the detail to the full pane; u/d or page keys scroll it. Navigation uses Pi's keybindings (tui.select.up/down/confirm/cancel), so a remap in keybindings.json applies; j/k, Enter, x and q/Esc work regardless. x arms cancellation and a second x/y confirms it; n/Esc keeps 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 fleet inspector is read-only apart from cancelling a run; result handoff into the parent conversation is still manual via subagent_wait.
  • No transcript drill-in: child sessions are in-memory (SessionManager.inMemory()), so /subagents fleet shows 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.
  • ask is denied inside children until parent prompt routing lands.
  • No structured yield_result contract; the final assistant text is the result.