@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 +385 -337
- package/agents/cleaner.md +50 -45
- package/agents/documenter.md +40 -42
- package/agents/explorer.md +40 -45
- package/agents/reviewer.md +82 -82
- package/agents/synthesizer.md +39 -0
- package/agents/worker.md +43 -45
- package/package.json +55 -55
- package/src/agents.ts +25 -5
- package/src/announcements.ts +78 -75
- package/src/background.ts +11 -0
- package/src/completion.ts +19 -9
- package/src/config.ts +3 -10
- package/src/dispatch.ts +815 -647
- package/src/durable.ts +443 -402
- package/src/format.ts +173 -179
- package/src/index.ts +6 -6
- package/src/models.ts +4 -6
- package/src/monitor.ts +56 -5
- package/src/prompt.ts +14 -21
- package/src/recovery.ts +145 -145
- package/src/rpc-run.ts +993 -993
- package/src/runtime.ts +22 -4
- package/src/session-fork.ts +2 -0
- package/src/setup.ts +23 -43
- package/src/spawn.ts +668 -654
- package/src/temp-hygiene.ts +230 -174
- package/src/thread-lifecycle.ts +1487 -1399
- package/src/tools.ts +436 -712
- package/src/widget.ts +195 -157
- package/src/workflow.ts +24 -8
- package/src/worktree.ts +18 -0
package/README.md
CHANGED
|
@@ -1,337 +1,385 @@
|
|
|
1
|
-
# pi-subagents
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@ferris1225/pi-subagents)
|
|
4
|
-
[](https://www.npmjs.com/package/@ferris1225/pi-subagents)
|
|
5
|
-
[](./LICENSE)
|
|
6
|
-

|
|
7
|
-

|
|
8
|
-
|
|
9
|
-
A managed engineering team for [pi](https://github.com/earendil-works/pi):
|
|
10
|
-
specialized sub-agents, durable threads, automatic
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
## Why
|
|
14
|
-
|
|
15
|
-
Delegation
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
`cleaner`
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
1
|
+
# pi-subagents
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@ferris1225/pi-subagents)
|
|
4
|
+
[](https://www.npmjs.com/package/@ferris1225/pi-subagents)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+

|
|
7
|
+

|
|
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 writers — and 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
|