pi-agent-tree
v0.1.0
Published
Multiplexer-free async subagent trees for pi, with session takeover and a live agent-tree cost report — based on davis7dotsh/my-pi-setup's subagents extension, enhanced with ideas from pi-interactive-subagents, pi-recursive, and pi-agent-teams.
Downloads
33
Readme
pi-agent-tree
Background subagents for pi: spawn them, watch them, take over one live, get a cost/token rollup for the whole tree — no terminal multiplexer needed.
Install
pi install npm:pi-agent-treeThe tools
Five tools the model calls to run subagents in the background:
| Tool | What it does |
|---|---|
| create_agent | Fire-and-forget spawn. Returns an id immediately. |
| wait_for_agent | Block until the given id(s) settle, return their results. |
| check_agent | Peek at a running agent's status without blocking. |
| list_agent | List every agent in the tree. |
| terminate_agent | Stop one or more running agents. |
create_agent(prompt: "find and fix the flaky test in test/foo.test.ts", name: "flaky-fix", agent: "worker")
-> { id: "agent-3" }
wait_for_agent(ids: ["agent-3"])
-> { "agent-3": "Fixed: test asserted before the promise resolved. ..." }If you don't wait_for_agent, the result is queued back as a follow-up message the moment the agent settles — you don't have to block to get it.
create_agent also takes these optional per-call params:
agent: "worker"— named preset to use as defaults (see Presets below). Unknown or omitted names fall back to the bundledworkerpreset.budget: 1.0— dollar spend cap for this one agent; it's aborted once its own session cost exceeds it.spawning: true|false— whether this agent may itself callcreate_agent. Overrides the resolved preset's frontmatterspawning:, if any.
Presets (agents/*.md)
A preset is a markdown file with frontmatter that sets create_agent defaults, so the model can say agent: "worker" instead of repeating reasoning_effort/model/working_dir on every spawn. Bundled preset:
---
name: worker
reasoning_effort: medium
spawning: true # this preset's children may themselves create_agent
---
You get one bounded task. Follow the prompt, verify your own work, report back concisely.Drop your own into .pi/agents/*.md (project) or ~/.pi/agent/agents/*.md (global) — same name overrides the bundled one.
Guardrails
Nested spawning (an agent's own agent calling create_agent) is opt-in — preset frontmatter spawning: true, or the tool-call spawning: override above — and bounded tree-wide by env vars, so recursion can't run away:
TEAM_MAX_DEPTH=10 TEAM_MAX_CALLS=100 TEAM_MAX_RUNNING=8Spend is capped per agent instead (budget: on create_agent, above), not tree-wide.
/agents — supervise view
Lists every agent as a tree, lets you open one and drive it directly (type into its transcript like a normal chat) instead of switching terminal panes. Shortcut: press ↓ on an empty input box to open the same view.
/agent-stat — cost tree
Same tree, annotated with tokens/cost/elapsed time per agent and rolled up per subtree.
/split + handoff — just a manual subagent
/split spawns a subagent through the exact same path as create_agent — same tree, same guardrails — then immediately opens the supervise view on it, focused and ready to type. The only difference from a normal subagent: it doesn't auto-settle at the end of a turn. It stays open for back-and-forth until something explicitly ends it — either the model calls the handoff tool, or you type /handoff in its supervise view. That handoff settles it through the identical path a normal subagent's result comes back through, so the parent gets it as the same kind of follow-up message.
In short: /split is create_agent you get to steer live, and handoff is that agent's wait_for_agent-equivalent — it just waits on a person instead of a task finishing.
Layout
domain.ts,format.ts— shared types + formatting.session/— the pi backend (turns a piAgentSessioninto a normalized event stream).supervisor/— the registry/orchestration engine (tree limits, result delivery, extension state).tools/— the model-facing surface: the 5 tools,split/handoff, preset loading, prompt strings.stats/—/agent-stat.supervise/— the/agentsinteractive UI.
test/ (repo root) mirrors this by subject, not by folder.
Quality
npm run qualityRuns lint (oxlint), typecheck (tsc), tests+coverage, duplication (jscpd), and deadcode (knip). Lint uses oxlint (not eslint/typescript-eslint) because typescript-eslint doesn't yet support TypeScript's native compiler API, which this repo pins (see .oxlintrc.json).
