pi-subprocess
v0.4.0
Published
Minimal subprocess isolation for Pi agents. Spawns isolated Pi subprocesses and returns curated results.
Maintainers
Readme
pi-subprocess
Minimal subprocess isolation for Pi agents. Spawns isolated Pi subprocesses and returns curated results — keeps the parent's context clean.
Install
From npm:
pi install npm:pi-subprocessFrom git:
pi install git+https://github.com/juanje/pi-subprocess.gitOr load directly without installing:
pi -e /path/to/pi-subprocess/extensions/subprocess.tsQuick start
Once installed, a subprocess tool becomes available in your Pi session:
> Use subprocess to investigate how error handling works in the tools/ directoryThe agent spawns an isolated Pi subprocess that investigates independently and returns a summary. The parent session's context grows by the summary size only, not by all the files the subagent read.
How it works
The extension registers a subprocess tool that:
- Spawns a child Pi process in JSON mode with its own system prompt
- Streams the child's JSONL output, collecting
message_endevents - Extracts the final assistant text from the child session
- Truncates the output to a configurable maximum (default: 100 lines)
- Returns the curated text + stats (turns, tool calls, tokens, cost, duration)
Context isolation
The child runs in its own process with a fresh context window. It inherits the parent's working directory and environment (including permission policies from pi-permission-gate if installed), but none of the parent's conversation history.
Project system prompt
If .pi/SUBPROCESS_SYSTEM.md exists in the working directory, its content replaces the default generic worker prompt. This lets a project define subprocess behavior once — identity, rules, tool constraints — instead of repeating it in every call.
Per-call specialization appends on top of the base via system_prompt (inline text) or system_prompt_file (path to a file on disk). Use system_prompt_file for static per-phase identities that don't change between invocations — the parent agent passes a path and never loads the content into its own context.
Prompt hierarchy:
.pi/SUBPROCESS_SYSTEM.md (or built-in default)
└── system_prompt OR system_prompt_file (per-call specialization)
└── task parameter (the work item for this subprocess)Example with multiple worker types:
.pi/
├── SUBPROCESS_SYSTEM.md # Shared base (authority, atomicity, return rules)
└── workers/
├── extract.md # Extraction identity + manifest format
├── write.md # Page-writing rules + link format
└── fix.md # Link-fixing constraintssubprocess(
task = "Read /path/to/manifest.md and write pages...",
system_prompt_file = ".pi/workers/write.md",
tools = "read,write",
timeout_ms = 600000
)Recursion prevention
The extension sets PI_SUBPROCESS_CHILD=1 in the child's environment. If this variable is already set, the extension skips registration entirely — no infinite recursion.
Session persistence
Child sessions are saved alongside the parent session for post-hoc analysis:
~/.pi/agent/sessions/my-project/
├── 2026-06-19_abc123.jsonl # parent session
└── 2026-06-19_abc123/
└── subprocess-x7k9m2/ # child session
├── session.jsonl
└── ...Tool parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| task | string | yes | — | What the worker should do |
| system_prompt | string | no | — | Custom prompt text appended to the worker prompt. Mutually exclusive with system_prompt_file. |
| system_prompt_file | string | no | — | Path (relative to cwd) to a file appended to the worker prompt. Use for static identities. Mutually exclusive with system_prompt. |
| tools | string | no | read,bash,grep,find,ls | Comma-separated tools for the worker |
| max_lines | number | no | 100 | Maximum output lines returned |
| effort | fast | balanced | thorough | no | — | Thinking depth (maps to Pi --thinking low/medium/high) |
| timeout_ms | number | no | 900000 (15 min) | Kill the subprocess after this duration |
Tool result
The tool returns:
content— the subprocess's final text (truncated if overmax_lines)details— stats object:
| Field | Type | Description |
|-------|------|-------------|
| turns | number | Assistant turns in the child session |
| toolCalls | number | Total tool invocations |
| totalTokens | number | Token consumption |
| cost | number | API cost |
| durationMs | number | Wall-clock duration |
| sessionDir | string | Path to child session JSONL |
| timedOut | boolean | Whether the timeout killed the child |
| outputTruncated | boolean | Whether output exceeded max_lines |
| fullOutputFile | string? | Path to untruncated output (only when truncated) |
The details field is visible to the parent agent but not injected into the context text. When output is truncated, the full text is saved to full-output.md in the session directory for post-hoc review.
When to use
- Investigation would flood context — reading multiple files, grepping large codebases, fetching logs
- Research before synthesis — delegate the fact-finding, keep the parent focused on analysis
- Skill-directed isolation — skills can explicitly invoke
subprocessfor specific substeps
When NOT to use
- Simple file reads or single tool calls — the overhead of spawning a subprocess isn't worth it
- Tasks requiring parent conversation history — the child starts fresh
- Tasks requiring write access to parent state — the child's writes don't propagate back
Development
git clone https://github.com/juanje/pi-subprocess.git
cd pi-subprocess
npm install
npm run check # typecheck + lint + testLicense
MIT — see LICENSE.
