@henryqw/pi-subagent 27.3.1 → 27.4.1
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 +105 -359
- package/docs/orchestration.md +324 -29
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -1,107 +1,56 @@
|
|
|
1
1
|
# `@henryqw/pi-subagent`
|
|
2
2
|
|
|
3
|
-
Delegate work to configured Pi Roles
|
|
3
|
+
Delegate bounded work to configured Pi Roles through [Herdr](https://herdr.dev/). Direct tasks share your checkout; isolated tasks produce checked candidates for explicit integration. Both return a handle so Main can continue working.
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Isolated work requires Herdr 0.9.3 or later. It also requires a running Herdr server on API protocol 22 or later. Pi Subagent checks both before it starts.
|
|
9
|
+
Isolated work requires Herdr 0.9.3 or later for both the client and server. The server must run on API protocol 22 or later. Pi Subagent checks Herdr and server support before it starts.
|
|
12
10
|
|
|
13
11
|
```bash
|
|
14
12
|
pi install npm:@henryqw/pi-task-models
|
|
15
13
|
pi install npm:@henryqw/pi-subagent
|
|
16
14
|
```
|
|
17
15
|
|
|
18
|
-
Run `/task-models
|
|
16
|
+
Run `/task-models` and configure the `fast`, `balanced`, `frontier`, and `fav` routes you use. Direct writer termination proof requires native `lsof`.
|
|
19
17
|
|
|
20
18
|
### Upgrade from 26.x
|
|
21
19
|
|
|
22
|
-
Version 27.0.0
|
|
20
|
+
Version 27.0.0 requires direct tasks to declare `access` and rejects unknown Role frontmatter keys. The library replaces `loadRoles` with `loadRoleCatalog` and `findRole`. Read [Migrate from 26.x to 27.0.0](./docs/migration.md).
|
|
23
21
|
|
|
24
22
|
## Works with
|
|
25
23
|
|
|
26
24
|
| Package | Relationship | Purpose |
|
|
27
25
|
| --- | --- | --- |
|
|
28
|
-
| [`@henryqw/pi-task-models`](https://pi.henry.wang/extensions/pi-task-models) | Required | Provides
|
|
26
|
+
| [`@henryqw/pi-task-models`](https://pi.henry.wang/extensions/pi-task-models) | Required | Provides model routes for delegated Roles. |
|
|
29
27
|
|
|
30
28
|
## Use
|
|
31
29
|
|
|
32
|
-
Ask Main
|
|
33
|
-
|
|
34
|
-
Commands are for you. Delegation and state tools and the packaged skill are for Main. `git_read` is only for children whose Role declares it. Main cannot use it. You do not need to call agent tools or manage candidate identities.
|
|
30
|
+
Ask Main: “Have a scout trace sign-in without editing files.” Main calls `delegate_task` and stays available until progress and results arrive.
|
|
35
31
|
|
|
36
|
-
|
|
32
|
+
Commands and UI are for you. Tools and the packaged skill are for Main, except `git_read`, which is only for Role-declared children.
|
|
37
33
|
|
|
38
34
|
| Surface | Type | Purpose |
|
|
39
35
|
| --- | --- | --- |
|
|
40
|
-
| `/subagent` | command | Browse
|
|
41
|
-
| `/subagent roles` | command | List
|
|
42
|
-
| `/subagent prune` | command | Review remaining worker and integration
|
|
43
|
-
| `/subagent recover` | command | Classify orphaned isolated work in the
|
|
36
|
+
| `/subagent` | command | Browse direct and isolated work. Stop or close owned direct workers, inspect isolated status, send follow-ups, or edit pending instructions. Requires interactive TUI or RPC. |
|
|
37
|
+
| `/subagent roles` | command | List Role sources, resources, resolved model and thinking level, route errors, and file errors. Read-only; requires no Herdr pane. |
|
|
38
|
+
| `/subagent prune` | command | Review remaining worker and integration branches and worktrees. Remove merged resources after confirmation. Requires a running Herdr server; without interactive UI, only reports. |
|
|
39
|
+
| `/subagent recover` | command | Classify orphaned isolated work in the canonical repository. Send Main request IDs, blockers, and next actions. Requires no UI or Herdr pane. |
|
|
44
40
|
| `delegate_task` | tool | Start authorized shared-checkout work or a durable isolated checked graph. |
|
|
45
|
-
| `subagent_status` | tool | Read
|
|
46
|
-
| `subagent_resume` | tool | Perform the reported `retry`, `verify`, or `finalize` continuation
|
|
47
|
-
| `subagent_stage` | tool | Stage, resolve, reject, or revise an exact candidate.
|
|
48
|
-
| `subagent_integrate` | tool | Advance
|
|
49
|
-
| `subagent_abort` | tool |
|
|
50
|
-
| `git_read` | tool |
|
|
51
|
-
| `pi-subagent` | skill | Guide Main through
|
|
52
|
-
| Direct status widget (`D`) | ui |
|
|
53
|
-
| Isolated status widget (`I`) | ui |
|
|
54
|
-
|
|
55
|
-

|
|
56
|
-
|
|
57
|
-
`delegate_task`, `subagent_resume`, `subagent_stage`, `subagent_integrate`, and `subagent_abort` are model-only. Pi's `codemode` scripts cannot call them, because delegation and guarded state transitions need Main's visible reasoning. Scripts can still call `subagent_status`.
|
|
58
|
-
|
|
59
|
-
Main's calls that can write can run together without writer ownership. This includes all Bash calls and nested `codemode` writes. Only a direct request with a task that declares `access: "write"` reserves the checkout. Such a request cannot start while a direct writer owns the checkout. It also cannot start while a Main call that can write is in progress there.
|
|
60
|
-
|
|
61
|
-
The extension tracks each Main call separately until its result or execution end. The result of a script does not release its active nested writes. Reads never wait. To keep Main free to write, use `mode: isolated`. This mode adds worktree checks and explicit integration.
|
|
62
|
-
|
|
63
|
-
The coordinator is extension code that runs in Main's Pi process. It is not another agent. It saves the request, launches the Herdr subagent, checks its committed work, and reports saved results. Main chooses what to stage and promote.
|
|
64
|
-
|
|
65
|
-
If a worker fails, the coordinator reports attention after the wave settles. It does not always report immediately while siblings work. If Main's Pi process stops, a follow-up is not guaranteed. Restart Pi. Then run `/subagent recover` in the canonical repository.
|
|
66
|
-
|
|
67
|
-
This command classifies orphaned interruptions and sends Main one recovery report. Main then uses `subagent_status` for exact evidence and deliberate next actions. A stale `running` state does not prove that a worker is still active. The extension never replays interrupted actions or actions with unclear outcomes automatically.
|
|
68
|
-
|
|
69
|
-
The TUI has two separate compact status widgets. Each widget has one row for each visible worker or task. `D` marks direct work, and `I` marks isolated work. Badges such as `[S]` and `[I3]` identify the Role initial. Isolated badges also include the model class: `1` fast, `2` balanced, `3` frontier, `*` fav.
|
|
70
|
-
|
|
71
|
-
Each direct row starts with a saved direct reference such as `D7.1`. `D7` is the workflow number in this Pi session, and `.1` is the position of the worker in the original request. `/subagent` uses the same reference and name. The Herdr tab label shows them at launch. Numbers continue after reload, and the session never uses a number again.
|
|
72
|
-
|
|
73
|
-
A session switch can move a workflow into a session that already uses its number. In that case, the workflow gets a new number there. An existing Herdr tab keeps its original launch label.
|
|
74
|
-
|
|
75
|
-
The direct widget shows the launched model, thinking level, elapsed time, and measured task tokens (`— tok` until usage is available). Failed rows show before working and completed rows. When rows overflow, `… N more` includes counts by status.
|
|
76
|
-
|
|
77
|
-
The isolated widget shows the recorded task state and any retained workspace. It does not show reliable live model, thinking, or token readings from Herdr. Attention shows before ordinary work, and overflow uses `+N more · /subagent`. An aborted request with visible tasks has its own `request aborted` row. This row does not change the recorded statuses of the tasks.
|
|
78
|
-
|
|
79
|
-
A committed worker without a checked candidate can show attention, not readiness. Status glyphs use the active TUI theme. The text also names the status without color.
|
|
41
|
+
| `subagent_status` | tool | Read saved isolated state, exact identities, failed review verdicts, and allowed continuation. Does not replay work. Supports structured output for `codemode`. |
|
|
42
|
+
| `subagent_resume` | tool | Perform the reported `retry`, `verify`, or `finalize` continuation, not staging or integration. Same-worker correction retries accept optional `instruction` text. |
|
|
43
|
+
| `subagent_stage` | tool | Stage, resolve, reject, or revise an exact candidate. Rejecting a staged candidate freezes its generation. |
|
|
44
|
+
| `subagent_integrate` | tool | Advance dependents, refresh, validate, correct, promote, reconcile, clean up promotion, or release rejected and superseded resources. |
|
|
45
|
+
| `subagent_abort` | tool | Terminate an isolated request without discarding retained work. Retained candidates and integration work require release or proof of absence. |
|
|
46
|
+
| `git_read` | tool | Let Role-declared children inspect bounded local Git evidence without Bash, tests, network access, or writes. Not available to Main. |
|
|
47
|
+
| `pi-subagent` | skill | Guide Main through authorization, delegation, checks, integration, and recovery. |
|
|
48
|
+
| Direct status widget (`D`) | ui | Show direct references, names, Role badges, status, routes, elapsed time, measured task tokens, and tool activity in the TUI. |
|
|
49
|
+
| Isolated status widget (`I`) | ui | Show recorded task state, Role/model-class badges, and retained workspaces in the TUI. Readiness does not mean promotion. |
|
|
80
50
|
|
|
81
|
-
|
|
51
|
+
`delegate_task`, `subagent_resume`, `subagent_stage`, `subagent_integrate`, and `subagent_abort` are model-only. Main must make these decisions visibly; `codemode` scripts can call only `subagent_status`. Delegation and continuation tools use plain-object parameter schemas, including for providers that omit root-union tools. Each mode and action still requires its exact arguments.
|
|
82
52
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
### Direct tool activity
|
|
86
|
-
|
|
87
|
-
Direct rows can show `pending read, bash` and `last read 125ms recorded`. Pending means that Pi saved the call, but the session of this task has no matching result. It does not prove that execution started. Parallel calls stay pending until their own results arrive.
|
|
88
|
-
|
|
89
|
-
Recorded time comes only from the `durationMs` of the latest matched tool result. The extension does not calculate it from assistant timestamps. If the latest result has no timing, the row shows no tool time, even if an earlier result had timing. Older sessions, and calls rejected before execution, can have no recorded time. Task elapsed time is a separate metric.
|
|
90
|
-
|
|
91
|
-
Activity uses the existing session sample and file-size cache. The extension ignores a partial trailing JSONL entry until it is complete. For display, the extension removes terminal control characters from tool names. Narrow rows remove activity before other metrics, so worker identity and failure state stay visible. Activity and time are display information, not proof of task completion, worker ownership, or a timeout.
|
|
92
|
-
|
|
93
|
-
### How Main routes delegation
|
|
94
|
-
|
|
95
|
-
Main chooses the mode from your request. You do not need to select one. Words such as “direct” and “isolated” can show your intent, but the work sets the route. Main declares the selected mode in each `delegate_task` call. The extension never falls back between modes.
|
|
96
|
-
|
|
97
|
-
| Mode | Request that triggers it | Checkout behavior |
|
|
98
|
-
| --- | --- | --- |
|
|
99
|
-
| `direct` | Bounded research, review, or explicitly authorized writes and commits in the shared checkout | Opens Herdr tabs without focus in Main's current workspace. Creates no worktree. |
|
|
100
|
-
| `isolated` | Implementation or a checked task graph | Runs changesets in owned Herdr worktrees. Main selects, validates, and promotes exact candidates. |
|
|
101
|
-
|
|
102
|
-
Keep trivial mechanically verifiable work in Main. Keep tightly coupled changes under one owner. Do not split them by file count.
|
|
103
|
-
|
|
104
|
-
### Direct delegation
|
|
53
|
+
### Direct workflow
|
|
105
54
|
|
|
106
55
|
A read-only task:
|
|
107
56
|
|
|
@@ -115,7 +64,7 @@ A read-only task:
|
|
|
115
64
|
}
|
|
116
65
|
```
|
|
117
66
|
|
|
118
|
-
|
|
67
|
+
Choose exactly one shape:
|
|
119
68
|
|
|
120
69
|
```text
|
|
121
70
|
Single: { mode: "direct", role, name, task, access, ... }
|
|
@@ -123,362 +72,159 @@ Parallel: { mode: "direct", tasks: [{ role, name, task, access, ... }] }
|
|
|
123
72
|
Chain: { mode: "direct", chain: [{ role, name, task, access, ... }] }
|
|
124
73
|
```
|
|
125
74
|
|
|
126
|
-
Every
|
|
127
|
-
|
|
128
|
-
A request is a write request when any task declares `write`. Read requests skip checkout admission and return plain-text answers. Their parallel `tasks` run concurrently up to `maxSubagents`, but a `chain` still runs in order. Use isolated mode for checked writes.
|
|
129
|
-
|
|
130
|
-
Direct tasks use the declared tools, extensions, Skills, and MCP servers of the selected Role, including resources that can write. Authorization comes from your request and Main's bounded task packet, not from the capabilities of the Role. Name the permitted paths, actions, and exclusions. Preserve unrelated edits and staged changes. Authorize commits or external actions explicitly.
|
|
131
|
-
|
|
132
|
-
For example, a configured Git operator with `bash` can stage named pending files and commit them on the `fast` route. Use isolated mode for a checked changeset.
|
|
133
|
-
|
|
134
|
-
Direct writes change Main's checkout immediately. They require no clean checkout. They give no automatic checks, rollback, or isolated integration guarantee. A write request cannot start while a direct writer owns the checkout. It also cannot start while a Main call that can write is in progress there.
|
|
135
|
-
|
|
136
|
-
A write request runs its tasks in sequence. It holds checkout admission after the initial handle returns. Competing direct writers and Main writes fail until the extension proves that all owned workers stopped. To keep Main free to write, use `mode: isolated`. This mode gives worktree checks and explicit integration, not immediate changes to the shared checkout. Parallel read requests still run concurrently.
|
|
75
|
+
Every task requires `access: "read"` or `access: "write"`. Declare `write` for file, Git, or external-resource changes. **Read access is not enforced and is not a sandbox.** The worker keeps its Role's tools.
|
|
137
76
|
|
|
138
|
-
|
|
77
|
+
Read requests run parallel tasks up to `maxSubagents`. Chains run in order, replace literal `{previous}` with the preceding successful answer, and stop on failure. Any `write` task makes the whole request serial and reserves checkout admission until all owned workers stop.
|
|
139
78
|
|
|
140
|
-
|
|
79
|
+
Direct writes change Main's checkout immediately, including dirty checkouts. They have no automatic checks, rollback, or isolated integration guarantee. Specify permitted paths, actions, and exclusions. Preserve unrelated edits and staged changes; authorize commits and external actions explicitly.
|
|
141
80
|
|
|
142
|
-
|
|
81
|
+
While admission is held, competing direct writers and Main writes fail. A direct writer also cannot start during a Main call that can write, including Bash or nested `codemode` writes. Main calls do not block each other; reads never wait. Use isolated mode to keep Main free to write.
|
|
143
82
|
|
|
144
|
-
|
|
83
|
+
Tasks in write requests must return one JSON completion object:
|
|
145
84
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
Close is not available for an unverified allocation. Admission stays held until you reconcile it manually against Herdr. Do not create the tab again. Do not guess missing IDs or restart to bypass this blocker.
|
|
151
|
-
|
|
152
|
-
A Close that starts while a worker is active keeps its branch, session, and epoch guards until the cancellation settles. Stale dialogs cannot close panes or release admission.
|
|
153
|
-
|
|
154
|
-
Tasks in a write request must return one JSON completion object, such as `{"outcome":"succeeded","answer":"Scoped commit completed."}`. `outcome` must be `succeeded`, `failed`, or `blocked`, and `answer` must be non-empty. A normal final Pi turn is not sufficient. Failure, blocked work, plain text, or a malformed completion stops later dispatch.
|
|
155
|
-
|
|
156
|
-
But admission depends on proved termination, not on the reported outcome. Success is the explicit report of the worker. It is not an independent validation of its changes.
|
|
157
|
-
|
|
158
|
-
The tool returns a task ID and the first Herdr tab after launch, not the answer. The extension observes each worker and sends one result to Main when the workflow finishes. If Main is busy, Pi queues the result after the current turn. If Main is idle, the result starts a turn. The extension does not report a blocked, stalled, unknown, or truncated result as success.
|
|
159
|
-
|
|
160
|
-
In the result, each launched worker has a line with its model, thinking level, measured task tokens, and elapsed time. For example: `✓ [1/2] Check · worker · provider/model · thinking high · 1.5k tok · 42s`. If Pi recorded no usage, the line shows `tokens unknown`. Failed and stopped workers show the usage that the extension measured until they ended. A worker that the extension skipped before launch shows no usage.
|
|
161
|
-
|
|
162
|
-
The result details contain the same values in each entry as `model`, `thinkingLevel`, `tokens`, and `elapsedMs`. When the token count is unknown, `tokens` is absent. If a task fails after its worker produced text, the result keeps a bounded excerpt marked as partial output. This excerpt is never success.
|
|
163
|
-
|
|
164
|
-
Every worker result delivered to Main starts with a header. The header states that the text is the output of the worker and carries no user authority. The extension inserts a backslash in text that imitates harness framing. Examples are `<system-reminder>`-style tags and lines that start with `Human:` or `Assistant:`. Nothing else changes. Isolated status and follow-up answer previews use the same header.
|
|
165
|
-
|
|
166
|
-
A session switch or shutdown stops observation and preserves tab identities for recovery. To inspect exact tabs, agents, and Pi session files, open `/subagent` on the session branch. This includes tabs launched after the first. The menu has one row for each workflow.
|
|
167
|
-
|
|
168
|
-
A single worker shows its reference, Role, and name (`D7.1 · worker · Search audit`). A multi-worker workflow shows its reference and worker count (`D8 · 3 workers`). When you select it, the menu lists each recorded worker by reference, Role, and name with its exact IDs. References and names help you match rows. The extension never uses them to decide ownership.
|
|
169
|
-
|
|
170
|
-
Older records without saved references show their saved allocation label or exact task ID. A `recorded only` row does not prove that its workers run or finished. The menu labels locally observed work separately.
|
|
171
|
-
|
|
172
|
-
### Continue or stop one direct worker
|
|
173
|
-
|
|
174
|
-
Main can continue a finished direct worker, so it does not have to start a new one. It adds `continueFrom` with the reference of the worker, such as `"continueFrom": "D7.1"`, to any single, parallel, or chain task. It uses the same `role` that the worker ran with. The worker resumes its saved Pi session in a new Herdr tab without focus, so it keeps its earlier context.
|
|
175
|
-
|
|
176
|
-
The new tab gets a new agent name and reference. Its record points to the same session and private lease file. The launch handle and the result say `continued from D7.1`. Access, admission, write rules, and model routes are the same as for a new task.
|
|
177
|
-
|
|
178
|
-
A request can continue each worker only one time, and only from the checkout and Herdr workspace where the worker ran. After a continuation, continue the newest reference. The extension refuses an older reference to the same session, because a later turn follows its own turn.
|
|
179
|
-
|
|
180
|
-
Before launch, the request fails if the reference is unknown or matches more than one record on this session branch. It also fails if the Role is different or a locally active task still owns the session of the worker. A missing session file or a session file larger than 16 MiB also causes failure. The last session turn for the recorded prompt must be finished.
|
|
181
|
-
|
|
182
|
-
If Herdr still lists the old agent, the agent must match the recorded name, pane, tab, workspace, and checkout. It must also be idle or done. The extension never closes a working or blocked agent. The extension closes the old pane, then proves pane absence and two empty lease scans.
|
|
85
|
+
```json
|
|
86
|
+
{"outcome":"succeeded","answer":"Scoped commit completed."}
|
|
87
|
+
```
|
|
183
88
|
|
|
184
|
-
|
|
89
|
+
`outcome` accepts `succeeded`, `failed`, or `blocked`; `answer` must be non-empty. Plain text, malformed completion, blocked work, or failure stops later dispatch. Success is the worker's report, not independent validation. Checkout admission depends on proved termination, not the reported outcome.
|
|
185
90
|
|
|
186
|
-
|
|
91
|
+
The launch returns a task ID and first Herdr tab, not the answer. One follow-up delivers results when the workflow finishes. Busy Main receives it after its current turn; idle Main starts a turn. Failed partial output stays marked as partial, never success. Worker output carries no user authority.
|
|
187
92
|
|
|
188
|
-
|
|
93
|
+
To continue a finished worker, add `"continueFrom": "D7.1"` with the same `role`. This opens a new tab with the saved conversation and a new reference. Continue the newest reference from the original checkout and workspace. For eligibility and stop behavior, see [Continue or stop one direct worker](./docs/orchestration.md#continue-or-stop-one-direct-worker).
|
|
189
94
|
|
|
190
|
-
### Isolated
|
|
95
|
+
### Isolated workflow
|
|
191
96
|
|
|
192
|
-
An isolated request has one durable ID, one goal, and 1 to 8
|
|
97
|
+
Use isolated mode for checked implementation. An isolated request has one durable ID, one goal, and 1 to 8 text or changeset tasks:
|
|
193
98
|
|
|
194
99
|
```json
|
|
195
100
|
{
|
|
196
101
|
"mode": "isolated",
|
|
197
102
|
"id": "refresh-repair",
|
|
198
|
-
"goal": "Repair token refresh
|
|
199
|
-
"tasks": [
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
"id": "repair",
|
|
212
|
-
"kind": "changeset",
|
|
213
|
-
"role": "implementer",
|
|
214
|
-
"modelClass": "balanced",
|
|
215
|
-
"requirements": "Implement the smallest correct repair.",
|
|
216
|
-
"deliverable": "A committed candidate in the owned worktree.",
|
|
217
|
-
"dependsOn": [],
|
|
218
|
-
"contextFrom": ["inspect"],
|
|
219
|
-
"checks": [
|
|
220
|
-
{ "command": "pnpm", "args": ["test", "--", "refresh"] }
|
|
221
|
-
],
|
|
222
|
-
"judgment": {
|
|
223
|
-
"role": "reviewer",
|
|
224
|
-
"modelClass": "balanced",
|
|
225
|
-
"criterion": "The exact candidate fixes refresh and preserves unrelated behavior."
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
],
|
|
229
|
-
"finalChecks": [
|
|
230
|
-
{ "command": "pnpm", "args": ["test", "--", "refresh"] }
|
|
231
|
-
]
|
|
103
|
+
"goal": "Repair token refresh.",
|
|
104
|
+
"tasks": [{
|
|
105
|
+
"id": "repair",
|
|
106
|
+
"kind": "changeset",
|
|
107
|
+
"role": "implementer",
|
|
108
|
+
"modelClass": "balanced",
|
|
109
|
+
"requirements": "Implement the smallest correct repair.",
|
|
110
|
+
"deliverable": "A committed candidate in the owned worktree.",
|
|
111
|
+
"dependsOn": [],
|
|
112
|
+
"contextFrom": [],
|
|
113
|
+
"checks": [{ "command": "pnpm", "args": ["test", "--", "refresh"] }]
|
|
114
|
+
}],
|
|
115
|
+
"finalChecks": [{ "command": "pnpm", "args": ["test", "--", "refresh"] }]
|
|
232
116
|
}
|
|
233
117
|
```
|
|
234
118
|
|
|
235
|
-
`dependsOn` controls scheduling. `contextFrom` also schedules dependencies and
|
|
236
|
-
|
|
237
|
-
The canonical root `package.json` must have a test script. If `pnpm test` is not in the final checks, the runner adds it. Main runs it on the combined integration checkout before promotion. Checks and judgments bind to exact Git identities. Changes to the candidate or Main, changes during validation, unclear outcomes, or conflicts stop promotion. The extension retains evidence.
|
|
238
|
-
|
|
239
|
-
`delegate_task`, `subagent_resume`, and `subagent_integrate advance` return a durable request ID after the extension saves the wave. Productive work continues while Main is free. Main can do other work or end its turn. It does not need to sleep or poll. Pi sends a follow-up in the launching session when a checked worker becomes ready or a worker needs attention. Pi sends another follow-up when the wave finishes.
|
|
240
|
-
|
|
241
|
-
A worker can end its exact turn without a changed clean commit, for example after a failed or aborted turn. That worker needs attention, and the extension does not infer a candidate. Use `subagent_status` for its saved evidence.
|
|
242
|
-
|
|
243
|
-
A turn can end with tracked or untracked changes in the worktree. The coordinator then first sends the same worker one saved reminder for each dispatch try. The reminder tells the worker to commit the changes or explain why not. The reminder does not use a correction or a dispatch try. The coordinator never commits, stages, stashes, or discards the changes itself. If the worktree is still dirty after the reminder, the task needs attention, and the changes stay in place.
|
|
244
|
-
|
|
245
|
-
Follow-ups show only a short preview of a failed review verdict. They tell Main to run `subagent_status` for the full text. Session replacement or shutdown suppresses stale delivery. The extension then logs the request ID and reason, without prompts or credentials.
|
|
246
|
-
|
|
247
|
-
The extension reports synchronous delivery failures and does not replay them automatically. Pi reports asynchronous `send_message` failures through its native runtime. If delivery fails, inspect `subagent_status`.
|
|
248
|
-
|
|
249
|
-
The extension saves completed text answers independently of cleanup. Status and terminal follow-ups include a bounded preview of the accepted answer and cleanup evidence. Ignored automatic artifacts can retain a checkout, and this does not violate the read-only contract. The extension deletes no ignored files to make cleanup pass.
|
|
250
|
-
|
|
251
|
-
Tracked or untracked changes, a changed checkout identity, or unproved inspection still require attention. The completed answer stays saved. But the extension does not accept it as dependency context or retry it automatically. Retained text checkouts require deliberate manual inspection and cleanup. A retained checkout alone is not evidence that the Role edited source.
|
|
252
|
-
|
|
253
|
-
Isolated workers can start while Main has staged, unstaged, or untracked changes. They use only Main's pinned committed branch, HEAD, and tree. The extension does not copy those local edits into worker worktrees. It also does not stash, stage, reset, or merge them automatically. Main must stay at that committed identity while workers run. Changes to the branch or HEAD block new waves.
|
|
254
|
-
|
|
255
|
-
The worker produces a committed candidate without tracked or untracked changes. Then it runs focused preliminary checks and optional judgment. Ignored generated files do not block candidacy, but they prevent automatic worktree cleanup. Inspect them before you delete retained work. The runner records each ready candidate immediately but **does not integrate it automatically**. Main can inspect `subagent_status`.
|
|
256
|
-
|
|
257
|
-
While siblings still work, Main can use `subagent_stage` to select the exact candidate in an owned integration worktree. Main resolves conflicts there. Stage and resolve are available during an active wave, but rejection and revision wait until the wave settles. `subagent_integrate` can advance dependent tasks from a staged snapshot.
|
|
119
|
+
`dependsOn` controls scheduling. `contextFrom` also schedules dependencies and supplies completed text outputs in order. Do not repeat a task in both fields. Changesets require focused checks; graphs with changesets require final checks. The canonical root `package.json` must have a test script. The runner adds `pnpm test` to final checks if absent.
|
|
258
120
|
|
|
259
|
-
|
|
121
|
+
Workers use Main's pinned committed branch, HEAD, and tree, not staged, unstaged, or untracked edits. Branch or HEAD changes block new waves. Candidates must be committed with no tracked or untracked changes. Ignored generated files permit candidacy but prevent automatic cleanup.
|
|
260
122
|
|
|
261
|
-
|
|
123
|
+
1. Start the request and keep its durable ID. Main can work or end its turn without polling.
|
|
124
|
+
2. Inspect ready candidates with `subagent_status`. Main can stage exact candidates while siblings run and resolve conflicts there.
|
|
125
|
+
3. Use `subagent_integrate advance` for dependents on a staged snapshot.
|
|
126
|
+
4. After the wave settles, validate the combined integration tip with final checks and any final judgment.
|
|
127
|
+
5. Explicitly promote passing work into unchanged, clean Main.
|
|
262
128
|
|
|
263
|
-
|
|
129
|
+
Checks and judgments bind to exact Git identities. Staging, combined validation, and promotion require clean Main at the pinned identity. Changed identities, conflicts, or uncertain outcomes block promotion and preserve evidence. A definitive combined check or review failure permits one committed integration correction and another validation.
|
|
264
130
|
|
|
265
|
-
|
|
131
|
+
The extension sends follow-ups when a candidate becomes ready, a worker needs attention, and the wave finishes. A missed follow-up does not authorize replay. Read [Isolated contract](./docs/orchestration.md#isolated-contract) and [Exact integration actions](./docs/orchestration.md#exact-integration-actions) for graph, judgment, revision, refresh, and release details.
|
|
266
132
|
|
|
267
|
-
|
|
133
|
+
### Inspect work
|
|
268
134
|
|
|
269
|
-
|
|
135
|
+
Open `/subagent` to browse direct work on this session branch and isolated requests in the current canonical Git checkout, including other sessions. **Refresh** reloads saved status without recovery or mutation. Invalid state IDs stay preserved with a warning. Direct recovery remains available outside Git or without isolated inventory.
|
|
270
136
|
|
|
271
|
-
|
|
137
|
+
**Inspect status and recovery** opens a separate unfocused Herdr tab using the configured `scout` Role and `fast` route. It requires a Herdr-managed pane. The model receives bounded saved status, including retained paths, but not raw launch environment or session transcripts. Its analysis stays in that tab and does not start a Main turn. Missing Herdr, Role, or route fails without changing the request; Main can use `subagent_status` instead.
|
|
272
138
|
|
|
273
|
-
|
|
139
|
+
For locally active unsealed changesets, **Send follow-up instructions** queues a revision. **Edit queued instructions** withdraws all pending instructions before opening the editor; cancel leaves them removed. Already-claimed instructions cannot be recalled. Submission queues one replacement, and late submissions can fail after sealing. Read [Inspect and revise active work](./docs/orchestration.md#inspect-and-revise-active-work) before editing queued instructions.
|
|
274
140
|
|
|
275
|
-
|
|
141
|
+
See [Status widgets](./docs/orchestration.md#status-widgets) for reference numbering, token counts, and activity metrics, and [Choose a delegation mode](./docs/orchestration.md#choose-a-delegation-mode) for routing guidance.
|
|
276
142
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
`subagent_integrate validate` acknowledges only after it saves the validation intent of the exact generation. Then it runs checks and any final judgment in the background. A later turn cancellation does not cancel acknowledged validation. Session replacement or shutdown still stops it.
|
|
280
|
-
|
|
281
|
-
Completion sends a follow-up to the launching session. If delivery fails, use `subagent_status`. An acknowledgement is not passing evidence.
|
|
282
|
-
|
|
283
|
-
After an interruption to validation, first prove that the old coordinator and check processes stopped. Never take over a live productive lease. Use guarded `reconcile` on the saved generation and `combinedTip`. Missing checks or review never authorize `correct` or `promote`.
|
|
284
|
-
|
|
285
|
-
For a `validation_failed` generation with **no recorded checks, review, or prior combined correction**, `refresh` also accepts identical `expectedMain` and `newMain`. Supply the exact old combined `expectedTip` and the next generation number. Both Main and the retained integration tip must stay exact and clean. This action explicitly allocates a new checkout. It does not resume old checks.
|
|
286
|
-
|
|
287
|
-
Before promotion, restage the selected immutable candidates. Then run new full-suite checks and the required final judgment. The old generation stays retained, and the two-checkout limit still applies. Correction allowances do not reset. Other failures keep their existing recovery requirements.
|
|
288
|
-
|
|
289
|
-
After a coordinator interruption, run `/subagent recover` one time. It gets the repository productive lease before it changes any orphaned `pending` or `running` state. It preserves unreadable state files and retained candidates. It reports blockers and existing continuations to Main. It does not replay prompts, merges, promotion, or cleanup.
|
|
290
|
-
|
|
291
|
-
If another productive run holds the lease, the command only reads status and reports the live owner. Wait. Do not take over. You can safely run the command again.
|
|
292
|
-
|
|
293
|
-
Main uses `subagent_status` for exact identities. Main uses the recovery tools in the interface table above for deliberate decisions. The command never stages or promotes. Direct Herdr tab recovery stays in `/subagent`.
|
|
294
|
-
|
|
295
|
-
### Prune leftover worktrees
|
|
296
|
-
|
|
297
|
-
Run `/subagent prune` to clean up leftover worker and integration checkouts under `.worktrees/`. Their branches have the name `pi-subagent/subagent-` plus 24 hex characters. The command also cleans up such branches that have no checkout. The review lists each item with its path, branch, and tip. For each item, it also shows why the command can remove the item, or it shows every exact blocker. The command can remove an item only when all of these conditions are true:
|
|
298
|
-
|
|
299
|
-
- Its branch tip is already in Main's HEAD or in the local `origin` default-branch ref. The command does not fetch.
|
|
300
|
-
- Its checkout has no tracked or untracked changes. No merge, rebase, cherry-pick, revert, or bisect is in progress.
|
|
301
|
-
- No unfinished isolated request, in any checkout of this repository, records it. An unreadable state file blocks every item that it mentions.
|
|
302
|
-
- No productive run holds a repository lease.
|
|
303
|
-
- No Herdr pane works inside the checkout. If the command cannot inspect Herdr, it refuses every checkout.
|
|
304
|
-
|
|
305
|
-
One confirmation removes every listed removable item. When the command removes a checkout, it also deletes the ignored files of the checkout, such as `node_modules` or `dist`. So the command includes a checkout with ignored files only after a second confirmation. That confirmation names each ignored entry, and its approval covers all contents of each named entry.
|
|
306
|
-
|
|
307
|
-
If a top-level ignored entry is new or changed, the command skips the checkout. If the full list of ignored entries of a checkout does not fit in that dialog, the command excludes the checkout. The command blocks checkouts with initialized submodules. It also blocks owned checkouts that are detached or on another branch. Remove them manually.
|
|
308
|
-
|
|
309
|
-
The list shows removable items first. The command never cuts a long list silently. The list ends with `+N more not shown`, and the command does not remove the items that it did not show in that run. Run `/subagent prune` again to review them.
|
|
310
|
-
|
|
311
|
-
The command checks each item again immediately before removal and skips an item that changed. If the session or branch changes during removal, the command skips the remaining steps. The command deletes a branch only if the branch still points at the reviewed tip. Then the command reconciles each aborted request that recorded a removed resource. It uses the same guarded path as a repeated `subagent_abort`, so the cleanup of that request no longer shows as pending.
|
|
312
|
-
|
|
313
|
-
The report lists removed, skipped, and failed items, and each request that the command could not reconcile. Without interactive UI, the command only reports.
|
|
314
|
-
|
|
315
|
-
If an isolated worker produced no candidate, `subagent_abort` terminates it. It removes only owned resources that it proves are unchanged and clean. Cleanup includes ignored-file checks and never discards unique commits. The request stays aborted with retained-resource evidence if productive work has not settled, termination is uncertain, or cleanup fails.
|
|
316
|
-
|
|
317
|
-
Inspect `subagent_status`. Resolve the reported blocker. Then run `subagent_abort` again to reconcile cleanup. This does not replay worker prompts. Dirty work, unique commits, and uncertain allocations stay for deliberate manual recovery.
|
|
318
|
-
|
|
319
|
-
If you removed the checkouts, branches, and Herdr workspaces of a request outside Pi Subagent, `subagent_abort` can close the request. Abort examines each retained candidate and each integration generation with stages. It proves that the checkout is not registered, its path does not exist, and its branch does not exist.
|
|
320
|
-
|
|
321
|
-
Abort also proves worker absence with the same pane and lease checks. Then it records the candidates as rejected and released, and it completes the cleanup records. If one of these resources still exists, abort fails and does not change the request. In that case, release the resources first.
|
|
322
|
-
|
|
323
|
-
The following details describe exact identity and retained-work requirements.
|
|
324
|
-
|
|
325
|
-
A checked candidate stays retained if Main is dirty. Staging, combined validation, and promotion require Main to be clean at the pinned committed identity. Clean your local edits deliberately before you use those actions. The extension does not replay or merge dirty work automatically.
|
|
326
|
-
|
|
327
|
-
To stage, pass the exact `generation`, candidate (`taskId`, `attempt`, `candidate`), and `expectedTip` identities that status reports. To integrate, pass the generation and the combined `expectedTip`. If Main advances cleanly before promotion, call `subagent_integrate refresh` with the recorded `expectedMain`, the old `expectedTip`, and the new clean `newMain`. Main must restage selected immutable candidates into the new generation. Then Main must run combined checks again. Dirty or divergent Main blocks refresh.
|
|
328
|
-
|
|
329
|
-
Stale identities fail. If integration allocation was uncertain, `subagent_stage resolve` first proves that the owned checkout is still at its base. Then it starts the selected merge. Otherwise, it retains the intent.
|
|
330
|
-
|
|
331
|
-
Each request can keep at most two unreleased integration worktrees. A superseded generation is read-only.
|
|
332
|
-
|
|
333
|
-
To release a superseded *clean* integration checkout, call `subagent_integrate` with `{ id, action: "release", generation, expectedTip }`. As `expectedTip`, use the recorded tip of that generation. After `correct`, this is the correction tip. Otherwise, it is the last staged tip, or the integration base when no stage completed. A superseded generation keeps its correction record for this purpose.
|
|
334
|
-
|
|
335
|
-
You can release a rejected candidate after release of all generations that use it. This includes a dependent candidate that a refresh or a rejection made invalid.
|
|
336
|
-
|
|
337
|
-
Release first proves that the exact worker stopped. If the worker is already gone, release records the proof of absence. If the idle worker still runs, release closes its exact pane. Then it proves pane absence and two empty lease scans. Release never tries again to close a worker after an uncertain termination.
|
|
338
|
-
|
|
339
|
-
To release the candidate, pass `{ id, action: "release", generation: <latest generation number, or 1>, taskId, attempt, expectedTip: <candidate tip> }`. Release saves each host, checkout, and branch step. It verifies ownership and cleanliness, including ignored files. It deletes the branch only if its ref still names the exact tip.
|
|
340
|
-
|
|
341
|
-
Dirty, conflicted, changed, or uncertain resources stay for manual inspection. After you resolve the obstacle, do the same release again. Each released checkout frees a retained slot. Abort is available after release of every retained resource. Abort also removes an empty integration generation that a refresh created, if its checkout is clean at its base.
|
|
342
|
-
|
|
343
|
-
Rejection can invalidate dependent work. A rejection does not fail because of dependent work that a refresh or an earlier rejection already made invalid. If new dependent execution is not possible, start a new request. Do not force promotion.
|
|
344
|
-
|
|
345
|
-
Productive requests have no whole-run wall-clock deadline. Resume does not reset the recorded policy or correction count. Text tasks have two dispatch tries. Inspection failures before dispatch do not use a try. Verification requires passing preliminary checks and any required judgment. It cannot override a failed review.
|
|
346
|
-
|
|
347
|
-
Child limits, abort signals, process I/O, status inspection, exact termination, and cleanup keep finite safety bounds.
|
|
348
|
-
|
|
349
|
-
The extension never pushes, opens a pull request, publishes, deploys, force-cleans recoverable work, or silently falls back to Main.
|
|
143
|
+

|
|
350
144
|
|
|
351
145
|
## Config
|
|
352
146
|
|
|
353
|
-
|
|
147
|
+
Package-owned: `~/.pi/agent/config/pi-subagent/config.json`. Missing files silently use defaults. No key is required; the extension preserves the file and never rewrites it automatically.
|
|
354
148
|
|
|
355
149
|
| Name | Description | Values | Default |
|
|
356
150
|
| --- | --- | --- | --- |
|
|
357
|
-
| `maxSubagents` | Concurrent direct
|
|
358
|
-
| `maxTurns` | Provider
|
|
359
|
-
| `maxTokens` | Optional
|
|
151
|
+
| `maxSubagents` | Concurrent direct workers and ephemeral children | Safe integer ≥ 1 | `5` |
|
|
152
|
+
| `maxTurns` | Provider turns per child | Safe integer ≥ 1 | `50` |
|
|
153
|
+
| `maxTokens` | Optional tokens per child | Safe integer ≥ 1 | Unlimited |
|
|
360
154
|
| `maxCorrections` | Same-worker automatic corrections per isolated request | Safe integer ≥ 0 | `1` |
|
|
361
|
-
| `timeout.idleMinutes` | Direct worker and ephemeral child idle timeout | Positive
|
|
362
|
-
| `timeout.maxMinutes` | Ephemeral child hard runtime | Greater than idle
|
|
363
|
-
| `roleDefaults` |
|
|
155
|
+
| `timeout.idleMinutes` | Direct worker and ephemeral child idle timeout | Positive; within Node's timer range | `10` |
|
|
156
|
+
| `timeout.maxMinutes` | Ephemeral child hard runtime | Greater than idle; within Node's timer range | `30` |
|
|
157
|
+
| `roleDefaults` | Shared resources for built-in and user Roles | Object with `extensions`, `tools`, or `skills` arrays; same validation as Role fields | — |
|
|
364
158
|
|
|
365
|
-
|
|
159
|
+
`roleDefaults` entries precede Role entries; merging removes duplicates before resource resolution. Use it for a provider extension that every child needs. Limits come only from this file. Requests cannot override or replenish them. Durable requests keep recorded policy; a lower current correction limit can tighten recovery. There is no whole-run timeout.
|
|
366
160
|
|
|
367
|
-
|
|
161
|
+
The extension reports each new problem once per session. It reads config at launch, `delegate_task`, later direct workers, isolated Role launches, `/subagent roles`, and status inspection.
|
|
368
162
|
|
|
369
|
-
|
|
163
|
+
- Unknown keys warn and are ignored. A likely misspelling, such as `maxToken` for missing `maxTokens`, counts as invalid for that key.
|
|
164
|
+
- Invalid `maxSubagents`, `maxTurns`, `maxCorrections`, or `timeout` values warn and use finite defaults. If maximum timeout does not exceed idle timeout, the whole `timeout` uses defaults.
|
|
165
|
+
- Unknown or invalid `roleDefaults` keys warn; only those keys are ignored, so Roles receive fewer default resources.
|
|
166
|
+
- Invalid or misspelled `maxTokens` blocks delegation. Malformed JSON, invalid UTF-8, files above 64 KiB, and unreadable files also block delegation. The extension does not fall back to unlimited tokens.
|
|
370
167
|
|
|
371
|
-
|
|
372
|
-
- A misspelled key that is near a missing key, such as `maxToken` for `maxTokens`, counts as an invalid value of that key. The warning gives the likely key.
|
|
373
|
-
- An invalid value in `maxSubagents`, `maxTurns`, `maxCorrections`, or `timeout` shows a warning. The extension uses the finite default for that key. If `timeout.maxMinutes` is not greater than `timeout.idleMinutes`, the extension uses the default `timeout`.
|
|
374
|
-
- An unknown or invalid key in `roleDefaults` shows a warning. The extension ignores only that key, so Roles get fewer default resources.
|
|
375
|
-
- An invalid or misspelled `maxTokens` shows an error and blocks delegation. Malformed JSON, invalid UTF-8, a file larger than 64 KiB, or an unreadable file also causes this block. The default token limit is unlimited, so the extension does not use a default in these cases. `/subagent` stays available. Correct the file to enable delegation again.
|
|
376
|
-
|
|
377
|
-
The block also applies to work that already runs. The next worker of a direct workflow, or the next Role launch of an isolated request, fails before it starts. A workflow that runs keeps the limits that it started with. If the file had the problem when the session started, also run `/reload`. The session took its execution limits from the defaults.
|
|
378
|
-
|
|
379
|
-
No key is required. The extension preserves the file and never rewrites it automatically.
|
|
168
|
+
`/subagent` remains available during a block. Correct the file to enable delegation. The next worker or isolated Role launch fails while the block remains; running workers retain their original limits. If the problem existed at session start, also run `/reload`, because that session took default execution limits.
|
|
380
169
|
|
|
381
170
|
### Roles
|
|
382
171
|
|
|
383
|
-
Role Markdown
|
|
172
|
+
Role Markdown files in `~/.pi/agent/config/pi-subagent/` require frontmatter and a Markdown system prompt.
|
|
384
173
|
|
|
385
174
|
| Field | Requirement |
|
|
386
175
|
| --- | --- |
|
|
387
176
|
| `name`, `description` | Required non-empty text without terminal control characters |
|
|
388
177
|
| `modelClass` | Optional `fast`, `balanced`, `frontier`, or `fav` default |
|
|
389
|
-
| `tools` | Required
|
|
390
|
-
| `extensions` | Required array of trusted absolute paths, supported package sources, or Pi built-
|
|
178
|
+
| `tools` | Required base or internal tool-name array; `[]` selects none. Name `codemode` or `git_read` to activate it. |
|
|
179
|
+
| `extensions` | Required array of trusted absolute paths, supported package sources, or Pi built-ins such as `builtin:codemode` |
|
|
391
180
|
| `skills` | Required array of effective Pi Skill names |
|
|
392
|
-
| `mcps` | Optional exact server names from `~/.pi/agent/mcp.json
|
|
181
|
+
| `mcps` | Optional exact global server names from `~/.pi/agent/mcp.json`, using native `mcpServers` format. Omitted or `[]` denies MCP access. |
|
|
393
182
|
| body | Required system instructions |
|
|
394
183
|
|
|
395
|
-
The
|
|
396
|
-
|
|
397
|
-
Roles describe responsibility and capabilities, not write access or isolation. Each task declares access, and each request chooses its mode. A user Role with the same name overrides a built-in Role. The package ships `implementer`, `reviewer`, and `scout`.
|
|
398
|
-
|
|
399
|
-
The built-in reviewer includes `git_read`. To opt in, add `git_read` to the `tools` array of an existing user reviewer. No additional extension or Bash access is necessary.
|
|
400
|
-
|
|
401
|
-
### Reviewer Git inspection
|
|
402
|
-
|
|
403
|
-
`git_read` is an internal child tool. The extension loads and registers it only for Roles that declare it. It accepts structured parameters, not shell commands or arbitrary Git options:
|
|
404
|
-
|
|
405
|
-
| `operation` | Parameters and evidence |
|
|
406
|
-
| --- | --- |
|
|
407
|
-
| `status` | Optional `path`; staged, unstaged, and untracked status |
|
|
408
|
-
| `diff` | `mode: "working"` (default, unstaged), `"staged"`, or `"committed"`; committed requires `base` and `tip`. Optional `path` |
|
|
409
|
-
| `show` | Optional `revision` (default `HEAD`) and `path`; commit patch or file content at that commit |
|
|
410
|
-
| `log` | Optional `revision`, `path`, and `maxCount` (default 20, maximum 100) |
|
|
411
|
-
| `blame` | Required `path`, optional `revision` and paired `startLine`/`endLine` |
|
|
412
|
-
| `rev-parse` | Optional `revision`; resolves one commit ID |
|
|
413
|
-
|
|
414
|
-
Revisions accept commit IDs or named refs with optional `~N`/`^N` ancestry, not ranges or reflog expressions. Paths are literal and relative to the assigned cwd. The tool rejects absolute paths, traversal, `.git` components, and paths that look like options.
|
|
415
|
-
|
|
416
|
-
Use named candidate refs. Do not assume that Main's checkout contains an isolated candidate. In isolated judgment, the supplied exact patch stays authoritative. Git inspection supplies only referenced context, not a replacement diff. Reviewers still cannot run tests, write, commit, or push. They approve only with exact `PASS`.
|
|
417
|
-
|
|
418
|
-
You can cancel each call, and each call has a limit of 30 seconds. Results keep at most the last 32 KiB of UTF-8 output, with an explicit `truncated` flag and notice. If output is truncated, make the path, log count, or blame lines narrower. Do not treat truncated evidence as complete. Missing refs or files, non-repositories, invalid UTF-8, timeouts, and Git failures fail visibly. The tool writes no full-output artifact.
|
|
419
|
-
|
|
420
|
-
Git must support `--no-lazy-fetch`. Older versions fail and do not permit network access. The tool disables lazy fetch, pager, optional locks, hooks, fsmonitor, external diffs, textconv, and clean and process filters. So working-tree comparisons use unfiltered bytes and can be different from filter-aware Git output (for example Git LFS). The tool does not inspect submodule contents. Concurrent edits can still make direct inspection stale.
|
|
184
|
+
The package ships `implementer`, `reviewer`, and `scout`; same-name user Roles override built-ins. Roles define capabilities, not access or isolation. Unknown frontmatter keys invalidate that file and report its path and key. Other valid Roles load; duplicate names become unavailable. Delegation to an invalid file's claimed Role fails with that file's error. Inspect `/subagent roles`.
|
|
421
185
|
|
|
422
|
-
|
|
186
|
+
The built-in reviewer includes `git_read`; existing user reviewers must add it to `tools`. No additional extension or Bash access is necessary. See [Reviewer Git inspection](./docs/orchestration.md#reviewer-git-inspection) for operations, parameters, limits, and Git requirements.
|
|
423
187
|
|
|
424
|
-
Children
|
|
188
|
+
Children load only declared resources and required adapters. Roles must list their model provider extension. `codemode` requires both `builtin:codemode` in `extensions` and `codemode` in `tools`. Missing Skills, tools, MCP servers, Roles, or routes fail before productive work. Main-only delegation/recovery tools and `ask_question` stay unavailable to children.
|
|
425
189
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
Main's nested calls pass admission by their own tool names, not by script or ancestor ownership. Each call that can write, including Bash, prevents the start of a direct writer until that call returns a result or execution end. Main calls do not block each other. The completion of a script does not release its active nested calls. A nested call can still pass admission after its parent ends if no direct writer owns the checkout.
|
|
429
|
-
|
|
430
|
-
To let a Role run `codemode` scripts, list `builtin:codemode` in `extensions`. Also list `codemode` in `tools`. Both are required, because the built-in registers the tool as inactive and the Role tool policy activates it. If `tools` has `codemode` alone, the launch fails with an unavailable tool.
|
|
431
|
-
|
|
432
|
-
Pi's `codemode.mode` and `codemode.inlineBudget` settings apply in the child without change. So the Role never forces codemode-only operation. MCP configuration never activates `codemode` in a child. Scripts can call only the active tools of the Role, plus `codemode` and `deferred` extension and MCP tools. Inactive base tools such as `bash` stay unreachable.
|
|
433
|
-
|
|
434
|
-
The servers named in `mcps` come only from the global `~/.pi/agent/mcp.json`. In a Role that activates `codemode`, each selected server keeps its configured `exposure` and `toolExposure`. Pi's default `codemode` exposure makes tools callable from scripts without declarations. `direct` declares them. `deferred` tools stay reachable from scripts, and `hidden` tools stay unreachable. An invalid exposure value fails the launch.
|
|
435
|
-
|
|
436
|
-
In every other Role, the extension forces selected servers to `direct` exposure. It ignores `toolExposure`, because that child cannot reach undeclared tools. Declared tools show to the model as `mcp__<server>__<tool>` after the server connects. Pi replaces `-` in server and tool names with `_`. Pi appends a hash suffix when two tool names collide or a name is longer than 64 characters.
|
|
437
|
-
|
|
438
|
-
Before launch, the extension checks each selected entry against Pi's documented `mcpServers` rules, in Main and again in the child. The launch fails with the file path and field for each of these conditions:
|
|
439
|
-
|
|
440
|
-
- An entry is disabled, malformed, or uses an unknown transport.
|
|
441
|
-
- A server name is invalid.
|
|
442
|
-
- Two selected names differ only in `-` and `_`.
|
|
443
|
-
- `auth.provider` uses plain HTTP outside `localhost`, `127.0.0.1`, or `[::1]`.
|
|
444
|
-
- `oauth.authServerMetadataUrl` does not use HTTPS outside those hosts.
|
|
445
|
-
|
|
446
|
-
The extension never modifies the file. Fix the entry or choose another server. The extension passes valid `auth`, `oauth`, and `description` fields through, so Pi's native provider auth and OAuth apply. `oauth.clientRegistration` must be `dcr` or `cimd`. A `cimd` entry cannot use `clientId` or `clientName`. Any `callbackUrl` must use localhost or 127.0.0.1 with path `/callback`.
|
|
447
|
-
|
|
448
|
-
The extension still ignores project MCP overrides. A project cannot change the global server allowlist or exposure of the Role. Missing Skills, tools, MCP servers, Roles, or routes fail before productive work starts. The extension excludes Main-only delegation and recovery tools and `ask_question` from children.
|
|
190
|
+
Read [Role and resource policy](./docs/orchestration.md#role-and-resource-policy) for extension exposure, MCP validation, OAuth constraints, and child budgets. Project MCP overrides cannot change a Role's global allowlist or exposure.
|
|
449
191
|
|
|
450
192
|
## API
|
|
451
193
|
|
|
452
194
|
| Surface | Type | Purpose |
|
|
453
195
|
| --- | --- | --- |
|
|
454
|
-
| `loadRoleCatalog`, `findRole`, `parseRoleName`, `parseRoleDefaults` | functions | Load
|
|
455
|
-
| `registerRoleDefaultsReporting(pi, agentDir?)` | function |
|
|
196
|
+
| `loadRoleCatalog`, `findRole`, `parseRoleName`, `parseRoleDefaults` | functions | Load, validate, and select Roles with shared defaults and per-file errors. |
|
|
197
|
+
| `registerRoleDefaultsReporting(pi, agentDir?)` | function | Report problems at session start, once per session. Returns `report(ctx)`; call before a lazy `loadRoleCatalog`. |
|
|
456
198
|
| `resolveRoleSkills`, `resolveRoleLaunch`, `resolveConfiguredRoleLaunch` | functions | Resolve effective Pi resources and model routes. |
|
|
457
199
|
| `prepareRoleLaunch`, `finalizeRoleLaunch` | functions | Prepare Role prompts, arguments, and tool policy. |
|
|
458
200
|
| `createEphemeralSubagentExecutor` | function | Run bounded no-session Pi children through a FIFO pool. |
|
|
459
201
|
| `createChildWorktree`, `finalizeChildWorktree` | functions | Create and conservatively finalize child worktrees. |
|
|
460
202
|
| `prepareExactReviewEvidence` | function | Prepare private exact base-to-tip review evidence. |
|
|
461
203
|
| `ExecuteRequestSchema`, `StageRequestSchema`, `IntegrationActionSchema` | schemas | Validate checked request and integration inputs. |
|
|
462
|
-
| `IsolatedRunner`, `FileRunStore` | classes | Run checked work and persist
|
|
463
|
-
| `RoleLaunchRuntime`, `HerdrHostRuntime`, `CheckedGitRuntime` | classes | Supply launch, host, and Git behavior
|
|
464
|
-
| `ExecutionPolicySnapshot`, `RunState`, `CoordinatorRuntime` | types | Describe
|
|
465
|
-
|
|
466
|
-
Role route and launch helpers require only model routing fields and `isProjectTrusted()` from the context, plus `cwd` for configured package resources. They do not require UI methods.
|
|
204
|
+
| `IsolatedRunner`, `FileRunStore` | classes | Run checked work and persist request state. |
|
|
205
|
+
| `RoleLaunchRuntime`, `HerdrHostRuntime`, `CheckedGitRuntime` | classes | Supply launch, host, and Git behavior. |
|
|
206
|
+
| `ExecutionPolicySnapshot`, `RunState`, `CoordinatorRuntime` | types | Describe saved policy, state, and runner integration. |
|
|
467
207
|
|
|
468
|
-
|
|
208
|
+
Role helpers require model routing fields and `isProjectTrusted()`, plus `cwd` for configured package resources, not UI methods. See [Role launch API](./docs/orchestration.md#role-launch-api) for routing and worktree results.
|
|
469
209
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
See [Orchestration and package-author API](./docs/orchestration.md) for the detailed contracts and recovery model.
|
|
210
|
+
The executor accepts concurrency, turn/token, idle/hard-runtime limits, and abort, output, token, and activity callbacks. Queue time uses no child timeout; resources resolve after admission. See [Ephemeral executor API](./docs/orchestration.md#ephemeral-executor-api) for bounded output, abort results, errors, and accounting.
|
|
473
211
|
|
|
474
212
|
## State and storage
|
|
475
213
|
|
|
476
|
-
|
|
214
|
+
Private durable state lives under `config/pi-subagent/state/`. Isolated worker sessions use mode `0600` under `config/pi-subagent/leases/`; worker umask stays unchanged. Reads stop at 16 MiB. Larger sessions require inspection and cannot prove completion.
|
|
477
215
|
|
|
478
|
-
|
|
216
|
+
Sessions are removed only after exact worker-tab cleanup. They can contain prompts and answers: do not share them. State v5 rejects v4 and older files without migration. Preserve old state and recover its work manually.
|
|
479
217
|
|
|
480
218
|
## Limits and recovery
|
|
481
219
|
|
|
482
|
-
Role extensions and MCP servers are trusted executable code, not a sandbox. Select the smallest resource set
|
|
220
|
+
Role extensions and MCP servers are trusted executable code, not a sandbox. Select the smallest resource set and authorize write scope explicitly. Admission coordinates this Main's Pi calls, not other sessions, trusted extension lifecycle code, or external processes. Concurrent edits can make direct reads stale.
|
|
221
|
+
|
|
222
|
+
For uncertain direct termination, open `/subagent`, select the exact workflow, and choose **Close/cancel-and-release ALL owned workers in this workflow**. This stops all owned workers, not only the selected one. Resolve reported blockers and repeat the action. Recorded-only tasks cannot release admission. Restarting Pi does not prove termination. Inspect partial changes before new writes; never blindly repeat commits or delete work.
|
|
223
|
+
|
|
224
|
+
Unverified tab allocations retain evidence but offer no Close action. Reconcile them manually against Herdr; do not recreate tabs, guess IDs, or restart to bypass admission. See [Direct contract](./docs/orchestration.md#direct-contract).
|
|
225
|
+
|
|
226
|
+
After coordinator interruption, restart Pi and run `/subagent recover` in the canonical repository. Use `subagent_status` for exact evidence; never take over a live productive lease or replay uncertain prompts, merges, or promotion. See [Recover after interruption](./docs/orchestration.md#recover-after-interruption) and [Recovery and state](./docs/orchestration.md#recovery-and-state).
|
|
227
|
+
|
|
228
|
+
Run `/subagent prune` for merged leftovers. Removing a checkout deletes its ignored files only after a separate confirmation naming those entries. Dirty, conflicted, changed, or uncertain resources require deliberate inspection. See [Prune leftover worktrees](./docs/orchestration.md#prune-leftover-worktrees) before removal.
|
|
483
229
|
|
|
484
|
-
|
|
230
|
+
For aborted requests with retained resources, inspect status, resolve blockers, and repeat `subagent_abort` to reconcile cleanup without replaying work. Release rejected candidates and superseded generations explicitly. The extension never pushes, opens pull requests, publishes, deploys, force-cleans recoverable work, or silently falls back to Main.
|