pi-subagents gives pi a real subagent runtime.
Pi is a minimal coding harness. It gives you extensions, skills, prompts, and packages, then stays out of your way. Subagents are not built into core on purpose. They belong in a package where the behavior is explicit and replaceable.
This package is that layer.
It began as a fork of HazAT/pi-interactive-subagents. HazAT built the original async subagent extension and deserves full credit for the foundation. This fork, edxeth/pi-subagents, keeps the original idea, then pushes it much closer to Claude Code CLI territory: blocking launches, background workers, wait/join/detach ownership, stricter runtime control, and better separation between interactive and autonomous agents.
If you want the short version: this package gives pi a more complete subagent model, with explicit control over how child agents are launched, observed, synchronized, and resumed.
2026-04-16_16-46-05.mp4
pi install git:github.com/edxeth/pi-subagents- named subagents instead of ad-hoc prompt blobs
- detached async execution by default
- true blocking execution when you actually need sequential behavior
- interactive foreground children and headless background children
- explicit
wait,join, anddetachsemantics - resumable child sessions through
caller_pingandsubagent_resume - session-scoped artifacts for passing reports, notes, and context around
- frontmatter that controls runtime, not just personality
- a live widget so you can see what your children are doing
That is the difference between “subagents exist” and “subagents are usable.”
A scout, a reviewer, and an implementation worker are not the same thing.
Sometimes you want a child in a pane so you can watch it think. Sometimes you want it headless. Sometimes the parent should keep moving. Sometimes the parent must stop and wait. Sometimes the child should die with the parent. Sometimes it should survive.
Most tools flatten all of that into vague marketing words. This package does not. It exposes the actual runtime model.
That is why it has more than one mode. Not because complexity is fashionable. Because the problem is real.
Every subagent is a named agent definition.
By default, a child launches detached and reports back later. If the job is autonomous, it can run in the background. If the job needs visibility or direct steering, it can run interactively in its own pane. If the parent truly depends on the answer right now, the child can be awaited or launched as blocking.
So the runtime splits across a few hard boundaries:
- interactive vs background
- detached vs awaited/joined
- async vs blocking
- autonomous exit vs manual close
- terminate vs cancel vs abandon on parent shutdown
That is the core of the package.
Agents live in either of these places:
.pi/agents/in the project~/.pi/agent/agents/globally
Project-local agents override global ones with the same name.
This package leans heavily on frontmatter. Agent files are not just prompt wrappers. They are runtime declarations.
| Field | Default | What it does | When to use it |
|---|---|---|---|
name |
filename | Agent name used by agent: "..." |
Always set it explicitly if you care about stable naming |
description |
unset | Human-readable description; also used for ambient routing | Write one short, sharp line if you want the parent to discover and route to it well |
enabled |
true |
Hides the agent from discovery and blocks launch when false |
Disable agents without deleting them |
model |
pi default | Sets the model for that agent | Pin a model when the role needs a specific speed/quality tradeoff |
thinking |
model default | Sets pi thinking level | Raise it for scouts/reviewers, lower it for cheap utility agents |
tools |
session default | Built-in pi tools only: read, bash, edit, write, grep, find, ls |
Lock the agent down to only the tools it actually needs |
skills |
unset | Auto-loads named skills | Use when an agent always needs the same external guidance |
system-prompt |
task-body routing | append uses --append-system-prompt; replace uses --system-prompt |
Use replace for hard role isolation, append when you want to preserve more surrounding context |
spawning |
true |
Allows or denies subagent-spawning tools | Set false for workers that should do the job themselves |
deny-tools |
unset | Denies specific child-session tools by name | Use for surgical restrictions without rewriting the whole tool set |
auto-exit |
false |
Child exits automatically after a normal completion | Best for autonomous agents, especially background scouts and reviewers |
blocking |
false |
Makes the parent wait for that agent by default | Use when the parent genuinely cannot continue without that answer |
no-context-files |
false |
Disables automatic AGENTS.md / CLAUDE.md discovery for spawned child sessions |
Use only when you want a clean child run without project context injection |
cwd |
parent cwd | Default working directory for the child | Use for role directories, monorepo packages, or project-specific specialists |
mode |
interactive |
interactive pane or background headless child |
Use background for autonomous work; keep interactive when visibility matters |
fork |
false |
Gives the child a fork of the parent session by default | Use when the child needs the full conversation branch, not just the task |
timeout |
unset | Background timeout in seconds | Use only for background agents that should never run forever |
- Scout / reviewer / analyzer:
mode: background,auto-exit: true, usuallyspawning: false - Interactive specialist:
mode: interactive, usually noauto-exit - Sequential gatekeeper:
blocking: true - Monorepo role agent:
cwd: ./packages/... - Locked-down worker: narrow
tools,spawning: false, maybedeny-tools
If you want a concrete example of the style this package is built for, look at this scout agent:
That gist shows the intended shape: sharp role, explicit contract, minimal ambiguity.
A child can run in one of two ways.
The child gets its own pane or surface.
Use this when you want visibility, live steering, or just prefer seeing the work happen.
Supported backends:
The child runs headlessly as its own pi -p process.
Use this for scouts, reviewers, analyzers, and other autonomous workers that do not need a pane.
Detached is the default. The parent keeps working and the result comes back later.
If the parent depends on a child result, you can claim ownership of delivery with subagent_wait or subagent_join.
If a child should gate the parent immediately, use blocking execution.
That does not turn the whole system into sequential mode. It only means that specific child is awaited at launch time. Detached siblings keep running.
Because there is no single sane policy for all agents.
A codebase scout should usually run autonomously and get out of the way. A reviewer may need blocking behavior. A long-running background worker may need a timeout. An interactive child may need to stay open after user takeover instead of auto-exiting. A parent may want to cancel one child and abandon another.
This package exposes those differences instead of pretending they are the same thing.
That is the whole philosophy.
There are three main ways a child finishes.
Best for autonomous workers. The child exits when its turn finishes normally.
Best when the child should explicitly decide when it is done.
Best when the child needs help from the parent.
A child can stop, send a message upward, and hand back a resumable session file. The parent can answer and resume that exact session later. That gives you a real feedback loop instead of a dead end.
Subagents can write artifacts into a session-scoped store under pi history.
This is the clean handoff layer for:
- scouting reports
- review notes
- research
- intermediate context
- resumable work products
Top-level sessions get read_artifact.
Spawned subagents get both write_artifact and read_artifact.
The point is simple: if a child produces something structured, it should have a place to put it that is not random repo clutter.
Top-level sessions can receive a hidden catalog of available named subagents built from agent descriptions.
That lets the parent model know which specialists exist without spamming visible history. Child sessions do not get this catalog. Agents without descriptions remain launchable, but they are omitted from the ambient routing hint.
If you do not want that behavior, disable it.
These are the ones worth knowing.
PI_SUBAGENT_MUX— force the mux backend:cmux,tmux,zellij, orweztermPI_CODING_AGENT_DIR— override the global pi agent config rootPI_SUBAGENT_DISABLE_AMBIENT_AWARENESS— disable the hidden top-level subagent catalogPI_ARTIFACT_PROJECT_ROOT— override artifact root resolutionPI_SUBAGENT_RENAME_TMUX_WINDOW— opt in to tmux window renamingPI_SUBAGENT_RENAME_TMUX_SESSION— opt in to tmux session renaming
These are normally set by the extension itself, but they matter if you are reading the codebase or debugging behavior:
PI_DENY_TOOLSPI_SUBAGENT_NAMEPI_SUBAGENT_AGENTPI_SUBAGENT_SESSIONPI_SUBAGENT_SURFACEPI_SUBAGENT_AUTO_EXIT
PI_SUBAGENT_ALLOW_LIVE_WINDOWSPI_SUBAGENT_LIVE_MODELPI_SUBAGENT_KEEP_E2E_TMPPI_SUBAGENT_LIVE_LOCK_PATH
The package adds two useful pieces of UI.
The parent session gets a live subagent widget above the editor showing running children, elapsed time, activity, and basic context usage.
Each child session also gets its own tools widget so you can see what is available and what is denied.
That sounds minor until you start juggling several agents. Then it stops sounding minor.
There are ordinary tests and live end-to-end smoke tests.
npm test
PI_SUBAGENT_ALLOW_LIVE_WINDOWS=1 npm run test:e2e-live
PI_SUBAGENT_ALLOW_LIVE_WINDOWS=1 npm run test:e2e-live-blocking
PI_SUBAGENT_ALLOW_LIVE_WINDOWS=1 npm run test:e2e-live-mix-blocking
npm run test:e2e-live-deny-toolsThe live tests are intentionally gated so they do not spray terminal windows all over your machine by accident.
- upstream foundation: HazAT/pi-interactive-subagents
- this fork: edxeth/pi-subagents
MIT