pi-subprocess
Minimal subprocess isolation for Pi agents. Spawns isolated Pi subprocesses and returns curated results.
Package details
Install pi-subprocess from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-subprocess- Package
pi-subprocess- Version
0.4.1- Published
- Jul 13, 2026
- Downloads
- 438/mo · 31/wk
- Author
- juanjeojeda
- License
- MIT
- Types
- extension
- Size
- 19.3 KB
- Dependencies
- 0 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./extensions"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
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-subprocess
From git:
pi install git+https://github.com/juanje/pi-subprocess.git
Or load directly without installing:
pi -e /path/to/pi-subprocess/extensions/subprocess.ts
Quick start
Once installed, a subprocess tool becomes available in your Pi session:
> Use subprocess to investigate how error handling works in the tools/ directory
The 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 constraints
subprocess(
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 + test
License
MIT — see LICENSE.