@ferris1225/pi-subagents 4.1.18 → 4.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,337 +1,385 @@
1
- # pi-subagents
2
-
3
- [![npm version](https://img.shields.io/npm/v/@ferris1225/pi-subagents?color=blue)](https://www.npmjs.com/package/@ferris1225/pi-subagents)
4
- [![downloads](https://img.shields.io/npm/dm/@ferris1225/pi-subagents)](https://www.npmjs.com/package/@ferris1225/pi-subagents)
5
- [![license](https://img.shields.io/npm/l/@ferris1225/pi-subagents)](./LICENSE)
6
- ![platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey)
7
- ![pi](https://img.shields.io/badge/pi-extension-orange)
8
-
9
- A managed engineering team for [pi](https://github.com/earendil-works/pi): five
10
- specialized sub-agents, durable threads, automatic quality gates, and Git
11
- worktree isolation installed once, then your main agent delegates on its own.
12
-
13
- ## Why pi-subagents
14
-
15
- Delegation should **remove** coordination work, not create more of it. Most
16
- sub-agent launchers stop at "spawn a child with a prompt"; the coordination
17
- burden — when to delegate, how wide to fan out, who reviews, what happens when a
18
- model dies, how results come back — stays with you. pi-subagents owns that
19
- burden:
20
-
21
- - **The main model actually delegates.** A lean delegation directive is injected
22
- into its system prompt: child contexts are cheap and yours is scarce
23
- non-trivial implementation defaults to `worker`, trivial work stays inline,
24
- and dispatching never blocks or ends the main turn, so it can fire several
25
- dispatches and keep working while they run.
26
- - **Fan-out is the model's call, not a cap.** One parallel dispatch carries as
27
- many tasks as the work genuinely decomposes into. The runtime paces execution
28
- at a process-slot pool that scales with the machine (cores/2, bounded 4–16);
29
- extra tasks simply queue and start automatically as slots free, so wide
30
- batches never fail, never flood your context (results deliver compact, with
31
- the full text on disk), and queueing is always visible pacing never a
32
- hidden dispatch limit.
33
- - **Quality gates are built in and converge by themselves.** Successful
34
- worker/cleaner runs continue through one independent reviewer gate. A failing
35
- gate is fixed by the reviewer itself — the same retained session gets write
36
- access and applies its own fix instructions, then a converging re-review
37
- verifies the fixes — bounded rounds; a still-failing gate returns to the main
38
- agent with every finding and fix instruction. No guessing what satisfies the
39
- reviewer.
40
- - **Documentation stops drifting.** Writers sync the docs they directly affect;
41
- documentation drift is an ordinary gate finding, and dispatching the
42
- documenter for real remaining drift stays the main agent's decision.
43
- - **Parallel edits are safe.** Parallel workers default to isolated Git
44
- worktrees and integrate back without touching your index; shared-checkout
45
- writers serialize through one repository lane.
46
- - **Work survives everything.** Threads keep retained sessions across resume,
47
- stop, and pi reloads or crashes; a model failure hands the same session to
48
- the current main model instead of losing progress.
49
- - **Failures are visible.** Crashes, partial starts, and integration failures
50
- come back as results with recovery records — never as silent hangs.
51
-
52
- ## How it works
53
-
54
- ```text
55
- You
56
- └─ pi main agent
57
- ├─ explorer ─── retrieval index only (never an automatic gate)
58
- ├─ worker ───── implements ─┬─▶ reviewer PASS deliver
59
- ├─ cleaner ──── cleans up ──┘ └─ FAIL reviewer fixes itself
60
- ├─ documenter explicit docs/comments task deliver │
61
- └─ reviewer ─── advisory report (no VERDICT), or managed gate ◀──────┘
62
- └─ direct REVIEW_FAIL findings + fix instructions main agent fixes
63
-
64
- Worker and cleaner update existing docs/comments they directly affect. The stable
65
- parent returns one final result when its complete managed workflow settles.
66
- ```
67
-
68
- Every child is an isolated leaf Pi process with its own context window and no
69
- memory of your conversation — the brief is its only input. Completions resume
70
- the main agent automatically; there is no polling loop.
71
-
72
- ## Quick start
73
-
74
- Requires **pi >= 0.84.4** and **Node.js >= 22.19.0**.
75
-
76
- ```bash
77
- pi install npm:@ferris1225/pi-subagents
78
- ```
79
-
80
- Open pi and run `/subagents-setup` to pick agents, models, and thinking
81
- strengths. Fresh installs enable all five built-in agents on the current main
82
- model, and until a config file exists each session start points you at
83
- `/subagents-setup`. Then just ask:
84
-
85
- ```text
86
- Map how authentication works, fix the refresh race, run the tests, and review the diff.
87
- ```
88
-
89
- The main agent decides when delegation pays off; you can also call the tools
90
- directly for exact control.
91
-
92
- ## The team
93
-
94
- | Agent | Access | Best for |
95
- | ------------ | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
96
- | `explorer` | Read-only | Broad search, unfamiliar-area mapping, symbol/dependency tracing. Fast model, returns a retrieval index — never proof. |
97
- | `worker` | Full | The default route for any non-trivial, self-contained implementation, fix, refactor, or test task carried through verification. |
98
- | `cleaner` | Full | Explicitly authorized cleanup, removal, simplification, deduplication. Every safe proven cut applies without item-by-item approval. |
99
- | `documenter` | Docs/comments | Standalone docs/comments work, including syncing real drift a change left behind. May make zero edits; never changes runtime behavior. |
100
- | `reviewer` | Read-only (review) / full (fix stage) | Audits, code-health checks, plans, PR/issue validation, and independent gates; a failing managed gate continues into the reviewer's own write-enabled fix stage. |
101
-
102
- A good brief carries the goal, exact paths, constraints, and expected output
103
- the injected delegation guidance does this automatically when the main agent
104
- dispatches for you.
105
-
106
- ## Dispatch and fan-out
107
-
108
- ```ts
109
- // One task
110
- subagent({
111
- agent: "worker",
112
- task: "Fix the cache invalidation bug in src/cache, add regression tests, run the checks.",
113
- });
114
-
115
- // Parallel: as many genuinely independent units as the work has
116
- subagent({
117
- tasks: [
118
- {
119
- agent: "explorer",
120
- task: "Trace model fallback from dispatch to completion.",
121
- },
122
- { agent: "worker", task: "Add edge-case tests for config migration." },
123
- ],
124
- });
125
- ```
126
-
127
- The main agent owns the breadth there is no per-call task cap. The runtime
128
- runs a machine-scaled pool of child processes at once and queues the rest;
129
- dispatch confirmations and `subagent_status` state the live running/queued
130
- counts and the slot capacity, so pacing is never mistaken for a limit. A
131
- generation that moves on to its managed stages (gate review, fix rounds) or
132
- waits on the shared-checkout writer lane releases its slot, so neither managed
133
- work nor serialized writers starve new dispatches. Parallel write-capable
134
- agents default to isolated worktrees and integrate via a three-way merge, so
135
- disjoint edits from parallel workers land without conflicts. One child owns one
136
- coherent deliverable and its files; dependent work starts only after its
137
- prerequisite delivers.
138
-
139
- ## Review gates and fixes
140
-
141
- ```ts
142
- subagent({
143
- agent: "reviewer",
144
- task: "Gate the current diff for correctness, regressions, and missing tests.",
145
- });
146
- ```
147
-
148
- A gate ends with exactly one verdict line: `VERDICT: REVIEW_PASS` or
149
- `REVIEW_FAIL`. Every gate finding carries a concrete fix instruction, and the
150
- reviewer must surface the complete finding set in one pass — never rationing
151
- findings across later rounds.
152
-
153
- A failing **managed** gate (after a top-level worker/cleaner) converges inside
154
- the workflow: the same retained reviewer session continues with write access
155
- and applies its own fix instructions, then a fresh gate verifies the fixes and
156
- hunts regressions they introduced (re-reviews converge on the fixes instead of
157
- re-scanning the whole surface). The loop is bounded to two fix rounds, after
158
- which the still-failing gate returns to the main agent with every finding.
159
-
160
- A failing gate **you dispatched directly** returns the full findings to the
161
- main agent, which resolves them itself (inline or via a worker it briefs)
162
- without waiting for you; only a genuinely destructive or scope-changing fix is
163
- worth asking about. It re-verifies once, then reports remaining findings and
164
- moves on — gate dispatches never loop. Generic audits and read-only reviews
165
- are advisory by default: no `VERDICT`, no edits.
166
-
167
- `cleaner` is dispatch-authorized cleanup: asking for an audit never silently
168
- authorizes code changes, and asking for cleanup never rewards speculative
169
- deletion. A top-level `documenter` is an explicit docs-writing task that
170
- delivers without another gate.
171
-
172
- ## Safe parallel editing
173
-
174
- - Single tasks default to the shared checkout; every parallel write-capable
175
- agent (`worker`, `cleaner`, `documenter`, custom writers) defaults to a
176
- detached Git worktree (requires a committed `HEAD`; read-only agents reject
177
- worktree mode), so parallel writers run concurrently.
178
- - An isolated workflow's reviewer and documenter run inside the same worktree;
179
- tracked, deleted, untracked, and binary changes integrate back exactly once
180
- after the workflow settles nothing is staged and your index is untouched.
181
- - Integration is a three-way merge: parallel workers that touched disjoint
182
- files or regions land cleanly even when earlier patches drifted the checkout.
183
- A genuine overlap keeps conflict markers in the checkout plus the retained
184
- worktree and patch for you to resolve.
185
- - Shared-checkout writers (and reviewers snapshotting their diff) serialize
186
- through one repository lane, so two shared writers never race.
187
- - Setup or integration failures keep the useful patch/worktree and record
188
- recovery info in `~/.pi/agent/pi-subagents-recovery.json`; a parked isolated
189
- thread keeps its worktree and resumes there.
190
-
191
- ## Follow, redirect, or stop
192
-
193
- Every dispatch returns a stable `#id` the handle for all control tools:
194
-
195
- | Tool | What it does |
196
- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
197
- | `subagent_control` | `resume` a parked/settled thread with its full retained context, optionally with a new `objective` appended. Only interrupted (parked) threads survive a reload. |
198
- | `subagent_status` | List active and recent runs, or return one run's full result and failed-tool diagnostics. |
199
- | `subagent_wait` | Non-blocking in-turn lookup; `timeoutMs` only when you must wait. |
200
- | `subagent_stop` | Destructively cancel, deliver the partial output, retire the thread. Stopping also drops any steering/follow-up messages still queued in the child so a stopped or later resumed thread cannot be revived by stale queue entries. |
201
-
202
- ```ts
203
- subagent_control({ action: "resume", id: 7, objective: "Finish the tests." });
204
- ```
205
-
206
- Threads are durable while work is unfinished: parked sessions, worktree
207
- checkpoints, and result excerpts live under
208
- `~/.pi/agent/ferris-pi-subagents/<project>/` (grouped per project; nothing is
209
- written to the OS temp directory transient per-run scratch lives in the
210
- project's `tmp/` and is swept for dead owners on the next load) and are
211
- restored when pi reloads or restarts — a reload
212
- interrupts a live run into a restorable checkpoint instead of losing it. A
213
- thread that completes or fails cleanly drops its durable record, so the
214
- threads manifest exists only
215
- while interrupted work needs it; parked work stays resumable for 30 days, and
216
- a project directory idle for three days is deleted wholesale on the next load
217
- (parked threads' references always win), so per-project storage never grows
218
- forever. All control operations are bounded; they never hang on a generation
219
- that is still settling.
220
-
221
- ## Results and live status
222
-
223
- The TUI widget projects each managed workflow as a timeline plus its current
224
- child:
225
-
226
- ```text
227
- #12 worker workflow · src/cache.ts · wt:a91f3c · 42s
228
- implement review docs
229
- #15 reviewer · final review · claude-sonnet-4-5/high · 10s
230
- #23 worker · queued · redirect to ripgrep crates · 5m02s
231
- ```
232
-
233
- The widget is capped at ten lines: when many runs are live at once, extra rows
234
- collapse into a `… +N more (subagent_status)` marker so the editor area keeps
235
- its space; `subagent_status` always shows the full picture.
236
-
237
- Completions resume the main agent automatically with a compact block (40 lines
238
- by default; longer output lands unchanged in a temporary Markdown artifact
239
- reachable via `subagent_status`). Roles author result-only handoffs — outcome,
240
- paths, verification, unresolved blockers and the main agent is told to add
241
- its conclusion, not restate what you already saw.
242
-
243
- ## Models, thinking, and vision
244
-
245
- Each agent runs on the current main model or one picked in `/subagents-setup`
246
- (vision/text-only labels included). If a selected model is missing, rate-limited,
247
- or fails at the provider level, the **same retained session** continues on the
248
- main model finished searches, reads, and edits are preserved; ordinary task
249
- failures do not trigger a handoff. Thinking defaults to **Auto**: the role's
250
- preference, clamped to what the effective model supports. `/subagents-setup` →
251
- _Configure an agent_ also offers a manual strength per agent, listing only the
252
- levels that model supports. There is no separate
253
- vision mode: assign a multimodal model and name the image paths in the task.
254
-
255
- Every dispatch, managed stage, resume, retry, and fallback snapshots the
256
- parent's currently active tools: roles without an explicit list inherit the
257
- full set; explicit lists keep their Pi built-in boundary while their shell slot
258
- (`bash`/`powershell`) follows the parent and active extension tools are
259
- appended. Read-only roles never gain `edit`/`write`; all `subagent*` tools are
260
- stripped so children stay leaves. An empty snapshot starts the child with
261
- `--no-tools`.
262
-
263
- ## Configuration
264
-
265
- `/subagents-setup` stays one level deep: enabled agents, per-agent models and
266
- thinking strengths, and the delegation-injection toggle. Everything else is
267
- config-file only, stored at
268
- `~/.pi/agent/pi-subagents.json` (follows `PI_CODING_AGENT_DIR`):
269
-
270
- ```json
271
- {
272
- "enabledAgents": ["explorer", "worker", "cleaner", "documenter", "reviewer"],
273
- "agentModels": { "explorer": "anthropic/claude-haiku-4-5" },
274
- "agentThinkingLevels": { "reviewer": "high" },
275
- "notifyOnReviewPass": false,
276
- "maxResultLines": 40,
277
- "proactiveInjection": true,
278
- "agentScope": "user",
279
- "idleTimeoutSec": 90
280
- }
281
- ```
282
-
283
- | Field | Meaning |
284
- | --------------------- | --------------------------------------------------------------------------------- |
285
- | `enabledAgents` | Agents available for discovery and delegation. `[]` disables all. |
286
- | `agentModels` | Optional `provider/model-id` per agent; missing = current main model. |
287
- | `agentThinkingLevels` | Optional manual level per agent; missing = Auto. |
288
- | `notifyOnReviewPass` | Deliver a standalone passing gate without waking the main agent. Default `false`. |
289
- | `maxResultLines` | Lines kept in a completion message before the artifact takes over. Default `40`. |
290
- | `proactiveInjection` | Inject the delegation directive into the main system prompt. Default `true`. |
291
- | `agentScope` | Discover `user`, `project`, or `both` agent directories. Default `user`. |
292
- | `idleTimeoutSec` | Seconds without child RPC output before termination; `0` disables. Default `90`. |
293
-
294
- Invalid values fall back safely; stale keys (including the former
295
- `maxConcurrency`/`maxFixRounds` knobs) are dropped automatically. At session
296
- start, model overrides Pi no longer reports are removed with a one-time notice.
297
- When pi's own session compaction fails mid-thread, a notice surfaces the error
298
- (and the automatic retry) instead of failing silently.
299
-
300
- ## Custom agents
301
-
302
- Built-ins ship in the package; add or replace them with Markdown files:
303
-
304
- - User agents: `~/.pi/agent/agents/`
305
- - Project agents: nearest `.pi/agents/` in a trusted project
306
- - Precedence: project > user > built-in (same `name` wins)
307
-
308
- ```yaml
309
- ---
310
- name: explorer
311
- description: Fast read-only codebase reconnaissance
312
- model: anthropic/claude-haiku-4-5
313
- thinking: low
314
- tools: read, bash
315
- ---
316
- …additional system prompt…
317
- ```
318
-
319
- Wizard choices override frontmatter defaults; an explicit `tools` list stays the
320
- capability boundary (shell slot follows the parent, active extension tools are
321
- appended), and omitting it inherits the parent's complete active set.
322
-
323
- ## Development
324
-
325
- ```bash
326
- npm install
327
- npm run check
328
- npm test
329
- ```
330
-
331
- No bundled runtime dependencies — pi and TypeBox are peers. Source is split by
332
- responsibility: dispatch/workflow policy, thread lifecycle, RPC transport,
333
- worktree integration, completion delivery, tools, and TUI status.
334
-
335
- ## License
336
-
337
- MIT
1
+ # pi-subagents
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@ferris1225/pi-subagents?color=blue)](https://www.npmjs.com/package/@ferris1225/pi-subagents)
4
+ [![downloads](https://img.shields.io/npm/dm/@ferris1225/pi-subagents)](https://www.npmjs.com/package/@ferris1225/pi-subagents)
5
+ [![license](https://img.shields.io/npm/l/@ferris1225/pi-subagents)](./LICENSE)
6
+ ![platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey)
7
+ ![pi](https://img.shields.io/badge/pi-extension-orange)
8
+
9
+ A managed engineering team for [pi](https://github.com/earendil-works/pi): six
10
+ specialized sub-agents, durable threads, automatic review gates, and Git worktree
11
+ isolation. You install it once and your main agent delegates on its own.
12
+
13
+ ## Why
14
+
15
+ Delegation is supposed to remove coordination work. Most sub-agent launchers stop
16
+ at "spawn a child with a prompt" and leave the hard parts — when to delegate, how
17
+ wide to fan out, who reviews, what happens when a model dies, how results come
18
+ back — with you. This extension owns them:
19
+
20
+ - The main model delegates without being asked, because a delegation directive is
21
+ always in its system prompt.
22
+ - Dispatching never blocks or ends the main turn, so it can start several runs and
23
+ keep working while they execute.
24
+ - Results deliver themselves. There is no status tool to poll and no lookup step.
25
+ - Successful implementation work goes through an independent reviewer gate, and a
26
+ failing gate fixes itself before it reaches you.
27
+ - Parallel writers get their own Git worktrees, so concurrent edits do not collide
28
+ and your index is never touched.
29
+ - Threads keep their context across resume, stop, reload, and crash; a dead model
30
+ hands its session to the current main model instead of losing progress.
31
+ - Crashes, partial starts, and integration failures come back as results with
32
+ recovery records — never as silent hangs.
33
+
34
+ ## Install
35
+
36
+ Requires **pi >= 0.84.4** and **Node.js >= 22.19.0**.
37
+
38
+ ```bash
39
+ pi install npm:@ferris1225/pi-subagents
40
+ ```
41
+
42
+ Open pi and run `/subagents-setup` to choose agents, models, and thinking
43
+ strengths. A fresh install enables every agent on the current main model, and each
44
+ session start points you at the wizard until a config file exists. Then just ask
45
+ for work:
46
+
47
+ ```text
48
+ Map how authentication works, fix the refresh race, run the tests, and review the diff.
49
+ ```
50
+
51
+ The main agent decides when delegation pays off. You can also call the tools
52
+ directly when you want exact control.
53
+
54
+ ## The team
55
+
56
+ | Agent | Access | Best for |
57
+ | ------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
58
+ | `explorer` | Read-only | Broad search, unfamiliar-area mapping, symbol and dependency tracing. Returns a retrieval index — never proof. |
59
+ | `worker` | Full | The default route for any non-trivial, self-contained implementation, fix, refactor, or test task, carried through verification. |
60
+ | `cleaner` | Full | Cleanup, removal, simplification, deduplication requested by you or dispatched proactively when finished work leaves dead code. The brief is its edit authorization and every safe proven cut applies. It cleans the uncommitted diff by default; a brief can scope it to a Git range or a directory instead, and scope bounds its edits without ever narrowing the search that proves a cut safe. |
61
+ | `documenter` | Docs/comments | Standalone docs and comment work, including syncing real drift a change left behind. May make zero edits; never changes runtime behavior. |
62
+ | `synthesizer` | Read-only | Merging a fan-out's result artifacts or other long sources into one deduplicated, attributed brief. Conflicts and gaps stay explicit, and your main context never re-reads the inputs. |
63
+ | `reviewer` | Read-only (review) / full (fix stage) | Audits, code-health checks, plans, PR and issue validation, and independent gates. A failing managed gate continues into the reviewer's own write-enabled fix stage. |
64
+
65
+ Every child is an isolated leaf pi process with its own context window and no
66
+ memory of your conversation, so the brief is its only input. A good brief carries
67
+ the goal, exact paths, constraints, and expected output — which is what the
68
+ injected delegation guidance produces when the main agent dispatches for you.
69
+
70
+ ```text
71
+ You
72
+ └─ pi main agent
73
+ ├─ explorer ─── retrieval index only (never an automatic gate)
74
+ ├─ worker ───── implements ─┬─▶ reviewer PASS → deliver
75
+ ├─ cleaner ──── cleans up ──┘ └─ FAIL → reviewer fixes itself
76
+ ├─ documenter ─ explicit docs/comments task → deliver │
77
+ ├─ synthesizer ─ merges fan-out results into one brief │
78
+ └─ reviewer ─── advisory report (no VERDICT), or managed gate ◀──────┘
79
+ └─ direct REVIEW_FAIL → findings + fix instructions → main agent fixes
80
+ ```
81
+
82
+ ## Dispatching work
83
+
84
+ ```ts
85
+ // One task
86
+ subagent({
87
+ agent: "worker",
88
+ task: "Fix the cache invalidation bug in src/cache, add regression tests, run the checks.",
89
+ });
90
+
91
+ // Parallel: as many genuinely independent units as the work has
92
+ subagent({
93
+ tasks: [
94
+ { agent: "explorer", task: "Trace model fallback from dispatch to completion." },
95
+ { agent: "worker", task: "Add edge-case tests for config migration." },
96
+ ],
97
+ });
98
+ ```
99
+
100
+ Breadth is the main agent's call, not a configured limit. There is no per-call
101
+ task cap: put every genuinely independent unit in one `tasks` array. The runtime
102
+ paces execution instead, running a pool of child processes that scales with the
103
+ machine (half its cores, bounded to 4–16) and starting queued runs automatically
104
+ as slots free.
105
+
106
+ Because queueing is pacing rather than refusal, it is always reported as such.
107
+ Dispatch confirmations name each waiting run's real reason — waiting for a free
108
+ process slot, serialized behind the shared-checkout write lane, or already
109
+ starting its child — alongside the slot capacity. A run that moves into its
110
+ managed stages or waits for the write lane releases its slot first, so managed
111
+ work and serialized writers never starve new dispatches.
112
+
113
+ One child owns one coherent deliverable and its files. Dependent work starts only
114
+ after its prerequisite delivers.
115
+
116
+ ## Review gates
117
+
118
+ ```ts
119
+ subagent({
120
+ agent: "reviewer",
121
+ task: "Gate the current diff for correctness, regressions, and missing tests.",
122
+ });
123
+ ```
124
+
125
+ A gate ends with exactly one verdict line, `VERDICT: REVIEW_PASS` or
126
+ `VERDICT: REVIEW_FAIL`. Every finding carries a concrete fix instruction, and the
127
+ complete finding set must arrive in one pass findings are never rationed across
128
+ later rounds.
129
+
130
+ Gates are proportional to the change. A small, contained diff gets a fast review
131
+ of its correctness, regressions, and blast radius rather than a whole-surface
132
+ audit, and `review: "none"` on a `worker` or `cleaner` task skips the gate
133
+ outright for mechanical, low-risk edits you verify yourself: typos, comments, doc
134
+ strings, config value tweaks. The default remains one fresh gate whenever behavior
135
+ can change, and a resumed thread keeps the choice its dispatch made.
136
+
137
+ A run that changed nothing is not gated either — there is no diff to review, and
138
+ making zero edits is a valid outcome for a cleaner that found no safe cut. That
139
+ one is decided afterwards rather than at dispatch, and only on proof: an isolated
140
+ worktree starts at its integration base, so an empty diff against that base is
141
+ proof. A shared checkout is shared with you and your editor, so nothing in it can
142
+ be attributed to one run and the gate always runs.
143
+
144
+ A failing **managed** gate — the automatic one after a top-level `worker` or
145
+ `cleaner` — converges inside the workflow. The same retained reviewer session
146
+ gains write access and applies its own fix instructions, then a fresh gate
147
+ verifies those fixes and hunts regressions they introduced. Re-reviews converge on
148
+ the fixes instead of rescanning everything, and the loop is capped at two fix
149
+ rounds, after which the still-failing gate returns to the main agent with every
150
+ finding.
151
+
152
+ A failing gate **you dispatched directly** returns its full findings to the main
153
+ agent, which resolves them itself, inline or through a worker it briefs, without
154
+ waiting for you. Only a genuinely destructive or scope-changing fix is worth
155
+ asking about. It re-verifies once, then reports what remains and moves on: gate
156
+ dispatches never loop.
157
+
158
+ Generic audits and read-only reviews are advisory by default no verdict, no
159
+ edits. Role authority stays honest in both directions: asking for an audit never
160
+ silently authorizes code changes, and asking for cleanup never rewards
161
+ speculative deletion. A top-level `documenter` is an explicit docs-writing task
162
+ that delivers without another gate.
163
+
164
+ ## Parallel edits
165
+
166
+ - Single tasks use your checkout. Every parallel write-capable agent (`worker`,
167
+ `cleaner`, `documenter`, custom writers) defaults to a detached Git worktree, so
168
+ parallel writers run at the same time. Worktree mode needs a committed `HEAD`,
169
+ and read-only agents reject it.
170
+ - A role file can pin its own default with `isolation: worktree` or
171
+ `isolation: shared` in the frontmatter. Precedence is an explicit per-dispatch
172
+ `isolation`, then the role's declaration, then the parallel write default.
173
+ - An isolated workflow's reviewer and documenter run inside the same worktree.
174
+ Tracked, deleted, untracked, and binary changes integrate back exactly once,
175
+ after the workflow settles. Nothing is staged and your index is untouched.
176
+ - Integration is a three-way merge, so parallel workers that touched disjoint
177
+ files or regions land cleanly even when earlier patches moved the checkout
178
+ underneath them. A genuine overlap leaves conflict markers in the checkout and
179
+ keeps the worktree and patch for you to resolve.
180
+ - Shared-checkout writersand reviewers snapshotting a diff serialize through
181
+ one repository lane, so two of them never race. A run waiting there is reported
182
+ as a lane wait, not as slot queueing, and its process slot is already released.
183
+ - Setup and integration failures keep the useful patch and worktree, and record
184
+ where they are in `~/.pi/agent/pi-subagents-recovery.json`. Every later session
185
+ start repeats that notice until you remove the artifacts.
186
+
187
+ ## Threads: wait, resume, stop
188
+
189
+ Every dispatch returns a stable `#id`, which is the handle for the thread tools:
190
+
191
+ | Tool | What it does |
192
+ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
193
+ | `subagent_wait` | Block in-turn until already-dispatched run(s) settle and return their results (`id` or prefix; omit for all active runs). |
194
+ | `subagent_control` | `resume` a parked or settled thread with its full retained context, optionally appending a new `objective`. |
195
+ | `subagent_stop` | Destructively cancel, deliver the partial output, and retire the thread. Steering and follow-up messages still queued in the child are dropped so nothing can revive it later. |
196
+
197
+ ```ts
198
+ subagent_control({ action: "resume", id: 7, objective: "Finish the tests." });
199
+ ```
200
+
201
+ There is deliberately no status or polling tool. Every result delivers itself,
202
+ the TUI widget shows what is live, and blocking is event-driven only: `wait:
203
+ true` on a dispatch holds the turn for that call's results — the escape hatch
204
+ for one-shot `pi -p` parents, which exit at end of turn and would otherwise
205
+ never see them — and `subagent_wait` does the same for a run that is already
206
+ in flight when the turn cannot proceed without it. Neither wait runs on a
207
+ timer or a timeout the model picks: a waiter resolves the instant its run
208
+ settles, a parked run answers immediately with its resume handle, and
209
+ aborting the turn is the escape hatch. Control operations are all bounded, so
210
+ they never hang on a generation that is still settling.
211
+
212
+ A thread stays durable while its work is unfinished. Parked sessions, worktree
213
+ checkpoints, and result excerpts are recorded in a manifest beside your config, so
214
+ a pi reload, restart, or crash interrupts a run into a resumable checkpoint
215
+ instead of losing it, and an isolated thread resumes in the worktree it was
216
+ already working in. Restore happens at load, and everything that answers for a run
217
+ waits for it `subagent_control`, `subagent_stop`, and a new dispatch before it
218
+ takes an id so the first call after a reload can never report parked work as
219
+ missing or hand its id to something else.
220
+
221
+ Only interrupted work needs a record, so a thread that completes or fails cleanly
222
+ drops its own. That also means a reload keeps interrupted threads resumable, while
223
+ threads that had already finished keep only their delivered result.
224
+
225
+ ## Live status and results
226
+
227
+ The TUI widget renders one compact line per run in fixed columns — status icon,
228
+ right-aligned `#id`, padded agent name, then the task label — so every label
229
+ starts at the same column, with the live activity dimmed after ` — ` and one
230
+ right-aligned telemetry column (worktree badge, model/thinking, wait state,
231
+ elapsed) so times line up at the right edge. A managed workflow adds exactly
232
+ one more line: a `└`-connected stage timeline that carries the live stage's
233
+ telemetry instead of extra child rows:
234
+
235
+ ```text
236
+ ◆ #12 worker src/cache.ts wt:a91f3c · 1m42s
237
+ implement review read src/auth.ts · 10s
238
+ #15 explorer src/models.ts grep fallback haiku-4-5/low · 22s
239
+ #23 worker src/config.ts repo lane
240
+ #24 worker ↻ tests/config.test.ts queued · 5m02s
241
+ ```
242
+
243
+ Queued rows state what they actually wait for in the telemetry column —
244
+ `queued` for a free process slot, `repo lane` for shared-checkout write
245
+ serialization, or `starting` and a resumed thread carries a dim `↻` in its
246
+ agent column with its cumulative time. The widget is capped at ten lines: when
247
+ many runs are live, the extra ones collapse into a `… +N more` marker so the
248
+ editor keeps its space.
249
+
250
+ Completions resume the main agent on their own, with a compact block of at most 40
251
+ lines by default; longer output lands unchanged in a Markdown artifact whose path
252
+ comes with the message. Roles write result-only handoffs — outcome, paths,
253
+ verification, unresolved blockers and the main agent is told to add its
254
+ conclusion rather than restate what you already read. A successful managed
255
+ workflow delivers the writer's handoff plus the integration outcome, and a failed
256
+ run adds its failed-tool diagnostics.
257
+
258
+ ## Models, thinking, and tools
259
+
260
+ Each agent runs on the current main model or on one you pick in
261
+ `/subagents-setup`, which labels vision and text-only models. If a selected model
262
+ is missing, rate-limited, or fails at the provider level, the **same retained
263
+ session** continues on the main model, so finished searches, reads, and edits
264
+ survive. Ordinary task failures do not trigger a handoff.
265
+
266
+ Thinking defaults to **Auto**: the role's own preference, clamped to what the
267
+ effective model supports. `/subagents-setup` _Configure an agent_ also offers a
268
+ manual strength, listing only the levels that model supports. There is no separate
269
+ vision mode — assign a multimodal model and name the image paths in the task.
270
+
271
+ Every dispatch, managed stage, resume, retry, and fallback snapshots the parent's
272
+ currently active tools. A role with no explicit list inherits the full set. An
273
+ explicit list keeps its pi built-in boundary and gains active extension tools,
274
+ while its shell slot follows the parent: a role file naming `bash` runs
275
+ `powershell` when that is the shell you enabled. When you run both, the child gets
276
+ the one that fits the host — PowerShell on Windows, Bash elsewhere — rather than
277
+ two terminals to choose between. A child never receives a shell you disabled,
278
+ since pi's `--tools` allowlist overrides its own `defaultTools`. Read-only roles
279
+ never gain `edit` or `write`, and all `subagent*` tools are stripped so children
280
+ stay leaves. An empty snapshot starts the child with `--no-tools`.
281
+
282
+ Shell guidance in the shipped roles is portable for the same reason: they reach
283
+ for pi's own `read`/`grep`/`find`/`ls` tools, which behave identically everywhere,
284
+ and keep shell examples to `git` queries instead of POSIX binaries a PowerShell
285
+ child cannot run.
286
+
287
+ ## Configuration
288
+
289
+ `/subagents-setup` stays one level deep: enabled agents, plus a model and thinking
290
+ strength per agent. Everything else is config-file only, stored at
291
+ `~/.pi/agent/pi-subagents.json` (following `PI_CODING_AGENT_DIR`):
292
+
293
+ ```json
294
+ {
295
+ "enabledAgents": ["explorer", "worker", "cleaner", "documenter", "synthesizer", "reviewer"],
296
+ "agentModels": { "explorer": "anthropic/claude-haiku-4-5" },
297
+ "agentThinkingLevels": { "reviewer": "high" },
298
+ "notifyOnReviewPass": false,
299
+ "maxResultLines": 40,
300
+ "agentScope": "user",
301
+ "idleTimeoutSec": 90
302
+ }
303
+ ```
304
+
305
+ | Field | Meaning |
306
+ | --------------------- | --------------------------------------------------------------------------------- |
307
+ | `enabledAgents` | Agents available for discovery and delegation. `[]` disables all. |
308
+ | `agentModels` | Optional `provider/model-id` per agent; missing = current main model. |
309
+ | `agentThinkingLevels` | Optional manual level per agent; missing = Auto. |
310
+ | `notifyOnReviewPass` | Deliver a standalone passing gate without waking the main agent. Default `false`. |
311
+ | `maxResultLines` | Lines kept in a completion message before the artifact takes over. Default `40`. |
312
+ | `agentScope` | Discover `user`, `project`, or `both` agent directories. Default `user`. |
313
+ | `idleTimeoutSec` | Seconds without child RPC output before termination; `0` disables. Default `90`. |
314
+
315
+ The delegation directive is always injected; there is no toggle. Invalid values
316
+ fall back safely, and stale keys — including the former `proactiveInjection`,
317
+ `maxConcurrency`, and `maxFixRounds` knobs — are dropped automatically. At session
318
+ start, model overrides pi no longer reports are removed with a one-time notice. If
319
+ pi's own session compaction fails mid-thread, a notice surfaces the error and the
320
+ automatic retry instead of failing quietly.
321
+
322
+ ## Custom agents
323
+
324
+ Built-ins ship with the package. Add or replace them with Markdown files:
325
+
326
+ - User agents: `~/.pi/agent/agents/`
327
+ - Project agents: the nearest `.pi/agents/` in a trusted project
328
+ - Precedence: project > user > built-in, where the same `name` wins
329
+
330
+ ```yaml
331
+ ---
332
+ name: explorer
333
+ description: Fast read-only codebase reconnaissance
334
+ thinking: low
335
+ isolation: shared
336
+ tools: read, bash
337
+ ---
338
+ …additional system prompt…
339
+ ```
340
+
341
+ `description` is the routing line the main model reads, and `thinking` is the
342
+ role's Auto preference, which a wizard choice overrides. `isolation` pins the
343
+ role's default boundary as described under [Parallel edits](#parallel-edits).
344
+ Models come only from `/subagents-setup`; an agent file cannot pin one. An
345
+ explicit `tools` list is the capability boundary, and omitting it inherits the
346
+ parent's complete active set.
347
+
348
+ ## Storage and cleanup
349
+
350
+ Everything lives under your pi agent directory, grouped per project. Nothing
351
+ long-lived is written to the OS temp directory, and every class of file has a rule
352
+ that removes it, so this directory does not grow without bound:
353
+
354
+ | Path | Holds | Removed |
355
+ | ------------------------------------------ | ---------------------------------------------------- | ---------------------------------------------------------------- |
356
+ | `pi-subagents.json` | Your configuration | Never — it is yours |
357
+ | `pi-subagents-threads.json` | One record per interrupted thread | When the thread settles, or after 30 days |
358
+ | `pi-subagents-recovery.json` | Worktree integration and cleanup failures | When the retained patch or worktree it points at is gone |
359
+ | `ferris-pi-subagents/<project>/sessions/` | Retained child sessions that a resume continues from | When the pi session that produced it ends, or its owner is gone |
360
+ | `ferris-pi-subagents/<project>/worktrees/` | Isolated checkouts for parallel writers | On integration, or when its owning process is gone |
361
+ | `ferris-pi-subagents/<project>/results/` | Full text of truncated results | After 7 days, or beyond 50 per project |
362
+ | `ferris-pi-subagents/<project>/tmp/` | Child prompt copies and the no-retry policy shim | When its owning process exits |
363
+ | `ferris-pi-subagents/<project>/` | All of the above for one checkout | When the whole directory has been idle for 3 days |
364
+
365
+ Cleanup runs at extension load and is deliberately conservative. A directory goes
366
+ away only when the process that created it is gone and no manifest record still
367
+ claims it, so a live sibling pi instance never loses state and parked work
368
+ outlives its own process by design — a reference from the threads manifest always
369
+ beats an age rule.
370
+
371
+ ## Development
372
+
373
+ ```bash
374
+ npm install
375
+ npm run check
376
+ npm test
377
+ ```
378
+
379
+ There are no bundled runtime dependencies; pi and TypeBox are peers. The source is
380
+ split by responsibility: dispatch and workflow policy, thread lifecycle, RPC
381
+ transport, worktree integration, completion delivery, tools, and TUI status.
382
+
383
+ ## License
384
+
385
+ MIT