@oai404iao/pi-subagent 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,7 @@ The design independently adapts the
5
5
  [DeepSeek Harness subagent seam](https://github.com/deepseek-ai/deepseek-harness/tree/4d03472cd098dc48a630e526ca620f4f37f18a0e/docs/subsystems)
6
6
  to Pi's extension and SDK APIs.
7
7
 
8
- Compatibility: Pi 0.84.2 or newer; tested against 0.84.2.
8
+ Peer floor: Pi 0.85.1; tested against 0.85.1.
9
9
 
10
10
  > npm identity: `@oai404iao/pi-subagent`. Once the selected version is
11
11
  > available on npm, install it from npm; use a local checkout before its
@@ -15,21 +15,31 @@ Compatibility: Pi 0.84.2 or newer; tested against 0.84.2.
15
15
 
16
16
  - **Named providers**
17
17
  - `spawn`: fresh child with no parent conversation
18
- - `fork`: one-shot child seeded through the parent's latest completed turn
19
- - **Two lifecycles**
20
- - foreground one-shot runs return the child's final answer
21
- - background continuable runs return a durable agent id immediately
22
- - **Foreground-only policy** that removes background scheduling and lifecycle controls
18
+ - `fork`: child seeded through the parent's latest completed turn
19
+ - **Readable task paths** such as `/root/review/auth`, with relative addressing
20
+ - **Explicit context inheritance**: `fresh`, `all_completed`, or
21
+ `last_n_completed`
22
+ - **One scheduling mode per session** (`runtimeMode`)
23
+ - `foreground`: one-shot runs return the child's final answer
24
+ - `background`: continuable runs return a readable path and stable agent id
25
+ at prompt acceptance
26
+ - **Foreground-only policy** that removes background scheduling and lifecycle
27
+ controls when `runtimeMode` is `foreground`
23
28
  - **Independent context and session** for every child
24
- - **Bundled presets without filesystem writes by default**, with opt-in
25
- materialization, backup, and replacement
29
+ - **User-owned agent catalog** with bundled templates used only for
30
+ first-install and package-version initialization
26
31
  - **Durable descriptors and lineage** stored in child JSONL sessions
27
- - **Cold resume** through `send_message`
32
+ - **Durable mailbox protocol**: enqueue-only `send_message` plus explicit
33
+ `followup_task` turn starts
34
+ - **Quiet durable completion updates** with event-driven `wait_agent`
28
35
  - **Control plane** with listing and interruption
29
- - **Child-to-parent `report` channel** for continuable children
36
+ - **Child-to-parent `report` channel** for continuable children (quiet: it never
37
+ starts a parent turn)
30
38
  - **Nested delegation** with an absolute persisted depth limit
31
39
  - **Dynamic agent-name enums** generated from the effective user/project catalog
32
40
  - **Parallel-safe delegation**: multiple `subagent` calls in one assistant message may overlap
41
+ - **Bounded background execution** with per-agent cold-resume serialization
42
+ - **Optional idle runtime LRU** with transparent cold resume
33
43
  - **Composable tool ceilings** that preserve model/extension tool decisions
34
44
  - **Usage accounting, streaming progress, output caps, and custom TUI rendering**
35
45
 
@@ -57,18 +67,20 @@ For a temporary test:
57
67
  pi -e /absolute/path/to/pi-extensions/pi-subagent
58
68
  ```
59
69
 
60
- This implementation targets Pi `0.84.2`.
70
+ Development and the supported compatibility floor are pinned to Pi `0.85.1`.
61
71
 
62
72
  ## Model-facing tools
63
73
 
64
74
  | Tool | Behavior |
65
75
  | --- | --- |
66
- | `subagent` | Starts a fresh child. Background continuable mode is the default unless configured otherwise; foreground-only mode always waits for the answer. |
67
- | `subagent_fork` | Starts a foreground one-shot child with the parent's completed-turn history. The in-flight tool turn is excluded. |
68
- | `send_message` | Sends the next FIFO turn to a direct continuable child; cold-resumes a persisted child when background execution is enabled. |
69
- | `interrupt_agent` | Requests cancellation of a live descendant's current turn without deleting its session. Active only when background execution is enabled. |
70
- | `list_agents` | Lists direct children or all descendants as `running`, `idle`, or `ready`. Active only when background execution is enabled. |
71
- | `report` | Child-only return channel. Installed automatically in continuable children. |
76
+ | `subagent` | Starts a named child with selectable context inheritance. In `background` mode it is continuable and returns at prompt acceptance; in `foreground` mode it waits for the final answer. |
77
+ | `subagent_fork` | Starts a child with all completed parent turns and uses the same session scheduling mode. |
78
+ | `send_message` | Durably appends a message to a direct child's FIFO mailbox. It never starts or resumes the child. |
79
+ | `followup_task` | Targets a direct child by path or id, atomically claims the pending FIFO batch, and starts one scheduled turn. |
80
+ | `wait_agent` | Waits event-driven for unread direct-child completions without starting a model turn or consuming a scheduler slot. |
81
+ | `interrupt_agent` | Requests cancellation of a live descendant by path or id without deleting its session. Active only in `background` mode. |
82
+ | `list_agents` | Lists readable descendant paths as `running`, `idle`, or `ready`, including separate `pending=N` task and `updates=N` completion counts. Active only in `background` mode. |
83
+ | `report` | Child-only return channel. Installed automatically in continuable children; the entry is recorded in the parent session without waking it. |
72
84
 
73
85
  The `/subagents` command shows the effective scheduling mode, available agent definitions,
74
86
  and the current descendant catalog.
@@ -92,52 +104,140 @@ Use subagent_fork with planner to plan the change using our completed discussion
92
104
  List my subagents, then send the scout a follow-up asking for exact call sites.
93
105
  ```
94
106
 
107
+ In the default background mode, enqueue first and start explicitly:
108
+
109
+ ```text
110
+ Send the scout two mailbox messages, then call followup_task once so it handles
111
+ the current FIFO batch in one turn. Call wait_agent when the next action needs
112
+ its quiet completion update.
113
+ ```
114
+
95
115
  Pi executes sibling tool calls in parallel, so this package deliberately accepts one delegation per `subagent` call instead of embedding a separate `tasks` array.
96
116
 
97
- ## Agent definitions
117
+ Every child follows the session's `runtimeMode`; there is no per-call background
118
+ flag. Independent foreground calls still execute in parallel within one
119
+ assistant message.
98
120
 
99
- The package includes `scout`, `planner`, `reviewer`, and `worker`. By default,
100
- these bundled definitions are read directly from the package. Startup does
101
- **not** create, replace, remove, or back up files in the Pi agent directory.
102
- `/subagents` reports those defaults as `(bundled)`.
121
+ ### Task paths and context
122
+
123
+ Every new child has an immutable path rooted at `/root`:
124
+
125
+ ```text
126
+ /root
127
+ ├─ review
128
+ │ └─ auth
129
+ └─ tests
130
+ ```
103
131
 
104
- User and project definitions can override the same names without modifying
105
- package files. Runtime locations and precedence are:
132
+ Set `task_name` to choose the final path segment. Names use 1–64 lowercase
133
+ ASCII letters, digits, hyphens, or underscores. If omitted, the extension
134
+ slugs `description` and appends `-2`, `-3`, and so on to avoid sibling
135
+ collisions. Explicit duplicate sibling names fail before child creation.
106
136
 
107
- 1. bundled package definitions
108
- 2. `<Pi agent dir>/agents/*.md`
109
- 3. nearest trusted `.pi/agents/*.md`
137
+ Control tools retain their existing parameter names for compatibility, but
138
+ accept any of:
139
+
140
+ - a durable UUIDv7 agent id;
141
+ - an absolute path such as `/root/review/auth`;
142
+ - a path relative to the caller, such as `auth`, `./auth`, or `../tests`.
143
+
144
+ References cannot escape `/root`. Path lookup is resolved to the durable agent
145
+ id before per-agent serialization; mailbox ownership, events, and durable
146
+ lineage remain UUID-based. Direct-child restrictions still apply to
147
+ `send_message` and `followup_task`, while `interrupt_agent` still requires a
148
+ descendant. Paths do not bypass those checks.
149
+
150
+ `subagent` accepts an optional context object:
151
+
152
+ ```json
153
+ {
154
+ "task_name": "review",
155
+ "context": {
156
+ "mode": "last_n_completed",
157
+ "completed_turns": 2
158
+ }
159
+ }
160
+ ```
110
161
 
111
- Project definitions replace user and bundled definitions with the same name
112
- when project scope is enabled. Project agents are disabled by the default
113
- `agentScope: "user"`. Setting the scope to `project` explicitly selects only
114
- project definitions; `both` loads bundled definitions, user overrides, then
115
- project overrides.
162
+ Context modes are:
116
163
 
117
- When upgrading from a version that synchronized presets by default, unchanged
118
- previously managed files are recognized read-only and do not shadow newer
119
- package defaults. Edited managed files remain user overrides. The default
120
- never deletes or rewrites those existing files.
164
+ | Mode | Initial child context |
165
+ | --- | --- |
166
+ | `fresh` | No parent conversation. This is the compatible `subagent` default. |
167
+ | `all_completed` | The parent's compaction-aware context through its latest completed assistant turn. |
168
+ | `last_n_completed` | The last `completed_turns` complete parent turns, bounded to 1–100. |
169
+
170
+ The active assistant/tool-call suffix is always excluded. A compaction summary
171
+ is retained when it is the only safe representation of completed history; if
172
+ it prevents exact turn counting, `last_n_completed` keeps that summary only
173
+ when fewer than the requested number of explicit completed turns remain.
174
+ Context is copied once into a new child session. Descriptor, lineage, mailbox,
175
+ completion, and other plain extension-state entries are not copied.
176
+
177
+ `subagent_fork` is the compatibility shortcut for `all_completed` and follows
178
+ the session's `runtimeMode` exactly like `subagent`: in `background` mode the
179
+ fork is continuable and uses the same mailbox lifecycle as a fresh child.
180
+
181
+ Every child persists descriptor version 4 with its task path, context policy,
182
+ and `runtimeMode`. Descriptors written by earlier releases use retired
183
+ scheduling switches and a background-protocol snapshot; they are **not**
184
+ readable any more. Such sessions stay on disk but appear as a corrupt
185
+ diagnostic in `list_agents` and cannot be addressed by path or id.
121
186
 
122
- ### Opt-in managed preset synchronization
187
+ ## Agent definitions
123
188
 
124
- Set `syncBundledAgents: true` only if you explicitly want the package to
125
- materialize its bundled definitions into:
189
+ The package ships `scout`, `planner`, `reviewer`, and `worker` as initialization
190
+ templates. On the first extension startup after installation, and whenever the
191
+ detected package version changes, those templates are materialized into:
126
192
 
127
193
  ```text
128
194
  <Pi agent dir>/agents/*.md
129
195
  ```
130
196
 
131
- With that opt-in, runtime discovery uses the managed user files rather than
132
- reading package copies directly, and `/subagents` reports built-ins as
133
- `(user)`. Synchronization behavior is then:
197
+ The package copies are **never runtime agent definitions or fallbacks**.
198
+ Runtime discovery reads only:
199
+
200
+ 1. `<Pi agent dir>/agents/*.md`
201
+ 2. nearest trusted `.pi/agents/*.md`
202
+
203
+ Project definitions replace user definitions with the same name when project
204
+ scope is enabled. Project agents are disabled by the default
205
+ `agentScope: "user"`. Setting the scope to `project` selects only project
206
+ definitions; `both` loads user definitions followed by project overrides.
207
+
208
+ After the current package version has been initialized, the user directory is
209
+ authoritative. Same-version startups do not restore missing files or refresh
210
+ changed templates. If the user deletes every agent definition, the effective
211
+ catalog is empty and delegation tools are inactive after restart or `/reload`.
212
+
213
+ ### Deleting a bundled preset
214
+
215
+ Deleting a managed preset file is a durable decision, not a transient one:
216
+
217
+ - every startup compares the manifest with the user agent directory; a managed
218
+ preset that is missing is recorded in `agents-manifest.json` as `retired`;
219
+ - later package-version changes install **new** bundled presets but never
220
+ restore a preset you deleted;
221
+ - presets that were never previously managed are still installed, and a preset
222
+ the user deleted before this version was first run is detected on the next
223
+ startup;
224
+ - recreating the file (for example by copying a backup) makes it a managed
225
+ preset again; from then on an ordinary package-version change refreshes it
226
+ with a backup like any other existing preset;
227
+ - deleting every preset leaves delegation tools inactive after restart or
228
+ `/reload`; run `/subagents` to see the effective catalog.
229
+
230
+ Retirement is reported at startup (`deleted by you (not restored): ...`) and a
231
+ name is dropped from the retirement list once it is no longer bundled.
232
+
233
+ Initialization behavior:
134
234
 
135
235
  1. **First startup:** missing presets are installed. A different pre-existing same-name file
136
236
  is backed up before the bundled version replaces it.
137
237
  2. **Ordinary restart of the same release:** user edits are preserved.
138
238
  3. **Plugin update:** differing user presets are backed up, then replaced with the new
139
- bundled versions. A bundled prompt hash change also triggers this refresh even if the
140
- package version was not bumped.
239
+ bundled versions. Presets deleted by the user stay deleted. A bundled prompt
240
+ change without a package-version change does not trigger a refresh.
141
241
  4. **Retired preset:** a formerly bundled name is backed up and removed so an obsolete
142
242
  prompt does not remain silently active.
143
243
  5. Files whose names were never managed bundled presets are left untouched.
@@ -146,8 +246,10 @@ Synchronization holds a cross-process lock, then preflights and stages the whole
146
246
  before changing agent files. If a commit fails, it rolls back already-applied changes and
147
247
  fails extension startup rather than falling back to package prompts. Same-name symbolic
148
248
  links are preserved as symbolic links inside the backup directory before the user path is
149
- replaced. An invalid synchronization manifest is copied to a timestamped `.corrupt-*` file
150
- and startup fails closed until the manifest is repaired or deliberately removed.
249
+ replaced. An invalid synchronization manifest is copied to a content-addressed
250
+ `.corrupt-*` file and skips template initialization; user and project agent discovery
251
+ continues with a warning. Repair the manifest, or deliberately remove it to request a new
252
+ first-install initialization pass.
151
253
 
152
254
  Synchronization state and backups live at:
153
255
 
@@ -236,11 +338,10 @@ See [`config.example.json`](config.example.json) and [`config.schema.json`](conf
236
338
  {
237
339
  "$schema": "/path/to/pi-subagent/config.schema.json",
238
340
  "agentScope": "user",
239
- "syncBundledAgents": false,
240
341
  "maxDepth": 3,
241
- "enableRunInBackground": true,
242
- "defaultBackground": true,
243
- "reportDelivery": "wakeup",
342
+ "runtimeMode": "background",
343
+ "maxConcurrentBackgroundRuns": 4,
344
+ "maxIdleRuntimes": 0,
244
345
  "inheritExtensions": false,
245
346
  "openAIIdentity": false,
246
347
  "maxOutputBytes": 51200
@@ -250,17 +351,37 @@ See [`config.example.json`](config.example.json) and [`config.schema.json`](conf
250
351
  | Setting | Default | Meaning |
251
352
  | --- | --- | --- |
252
353
  | `agentScope` | `user` | Select user definitions, project definitions, or user definitions followed by project overrides. |
253
- | `syncBundledAgents` | `false` | **User-level config only.** Opt in to writing managed bundled presets into `<Pi agent dir>/agents`. `true` may install, replace, retire, and back up those files. |
254
354
  | `maxDepth` | `3` | Absolute delegation depth; a top-level Pi session is depth 0. |
255
- | `enableRunInBackground` | `true` | Enable continuable background children and their model-facing lifecycle controls. Set `false` for strict foreground-only mode. |
256
- | `defaultBackground` | `true` | Default scheduling for fresh `subagent` calls when background execution is enabled. |
257
- | `reportDelivery` | `wakeup` | `wakeup` starts/queues a parent turn; `quiet` waits for the parent's next turn. |
355
+ | `runtimeMode` | `background` | The single scheduling switch. `background` starts continuable children and exposes their lifecycle tools; `foreground` waits for every child's final answer and removes those tools. |
356
+ | `maxConcurrentBackgroundRuns` | `4` | Maximum continuable subagent turns executing at once in one extension runtime. Additional top-level runs wait in FIFO order; nested work fails at capacity instead of deadlocking its parent turn. |
357
+ | `maxIdleRuntimes` | `0` | Process-wide LRU capacity for settled continuable runtimes. `0` preserves immediate unload; a positive value keeps the most recently used idle runtimes and transparently cold-resumes evicted paths. |
258
358
  | `inheritExtensions` | `false` | Load other Pi extensions in child runtimes. This package filters itself out; explicit agent tool ceilings still apply. |
259
359
  | `openAIIdentity` | `false` | For OpenAI Responses child models, inject only the named `pi-codex-minimal-tools` identity lifecycle inline. Codex Session/Thread/Turn/Window ids remain owned and serialized by that package. |
260
- | `maxOutputBytes` | `51200` | Cap for parent-visible foreground output, reports, and settlement notices. Full output remains in the child session. |
360
+ | `maxOutputBytes` | `51200` | Cap for parent-visible foreground output, reports, and completion updates. Full output remains in the child session. |
261
361
 
262
362
  Invalid configuration and unknown child tool names fail loud before the child's first model request.
263
363
 
364
+ ### Migrating an existing configuration
365
+
366
+ Earlier releases configured two booleans (`enableRunInBackground`,
367
+ `defaultBackground`) plus a `backgroundProtocol` selector, and 0.2/0.3 added a
368
+ `syncBundledAgents` switch. Every one of them is retired and is now rejected as
369
+ an unknown setting, and the extension never rewrites a configuration file:
370
+
371
+ | Retired key | Replace with |
372
+ | --- | --- |
373
+ | `enableRunInBackground: false` | `runtimeMode: "foreground"` |
374
+ | `enableRunInBackground: true` (or absent) | `runtimeMode: "background"` |
375
+ | `defaultBackground` | nothing; background children are always continuable |
376
+ | `backgroundProtocol` | nothing; the durable mailbox is the only background protocol |
377
+ | `syncBundledAgents` | nothing; template initialization is automatic |
378
+ | `reportDelivery` | nothing; `report` never starts a parent turn |
379
+
380
+ `reportDelivery` was removed together with the parent-wakeup path. A child
381
+ `report` is appended to the parent session (so the parent model sees it on its
382
+ next turn) and displayed in the TUI, but it never starts or queues a parent
383
+ turn. Durable completion updates are read with `wait_agent`.
384
+
264
385
  `openAIIdentity` and `inheritExtensions` are independent. The former adds only
265
386
  the lightweight Codex identity lifecycle even when normal extension inheritance
266
387
  is disabled. Enable `inheritExtensions` as well when the child should receive
@@ -275,24 +396,23 @@ with an actionable missing-adapter error.
275
396
 
276
397
  ```json
277
398
  {
278
- "enableRunInBackground": false
399
+ "runtimeMode": "foreground"
279
400
  }
280
401
  ```
281
402
 
282
403
  In this mode:
283
404
 
284
- - `subagent` always waits for the child's final answer, even when `defaultBackground` is `true`;
285
- - `run_in_background` is removed from the model-facing schema at session startup;
286
- - a forced `run_in_background: true` call is rejected before a child is created;
287
- - nested subagents inherit the foreground-only policy through the durable runtime snapshot;
288
- - `send_message`, `interrupt_agent`, and `list_agents` are removed from the active
405
+ - `subagent` and `subagent_fork` always wait for the child's final answer;
406
+ - no per-call background flag exists, so a child can never be created continuable;
407
+ - nested subagents inherit the mode through the durable runtime snapshot;
408
+ - `send_message`, `followup_task`, `wait_agent`, `interrupt_agent`, and `list_agents` are removed from the active
289
409
  model tool set, including inside nested children;
290
410
  - sibling foreground calls may still execute in parallel in one assistant message.
291
411
 
292
- `subagent_fork` is already foreground-only and is unchanged. The `/subagents` command
293
- remains available for human inspection of historical children, but persisted continuable
294
- children cannot be resumed until background execution is re-enabled. Run `/reload` or
295
- restart Pi after changing this setting so the active tool set and displayed schema are
412
+ The `/subagents` command remains available for human inspection of historical
413
+ children, but persisted continuable children cannot be resumed until
414
+ `runtimeMode` is set back to `background`. Run `/reload` or restart Pi after
415
+ changing this setting so the active tool set and displayed schema are
296
416
  refreshed.
297
417
 
298
418
  ## Lifecycle
@@ -313,42 +433,128 @@ The caller waits for one isolated child run. Only the child's last non-empty ass
313
433
 
314
434
  ### Continuable
315
435
 
316
- The start tool resolves at prompt preflight acceptance and returns the child's durable
317
- agent id (UUIDv7). Agent ids are independent of Pi session (file) ids: they are
436
+ The start tool resolves at prompt preflight acceptance and returns the child's
437
+ readable task path plus stable agent id (UUIDv7). Agent ids are independent of
438
+ Pi session (file) ids: they are
318
439
  generated once per subagent, recorded in the child's session as `pi-subagent/agent`,
319
440
  and chained through `parentAgentId` in the descriptor, so children stay addressable
320
441
  even when a parent session is forked or re-created. When an activation settles:
321
442
 
322
- 1. the runtime sends the parent a settlement notice with the stop reason and closing message;
323
- 2. the child runtime is disposed once its owned descendants are done;
324
- 3. its persistent session becomes `ready`;
325
- 4. `send_message` can cold-resume that same session for another FIFO turn.
326
-
327
- A child can explicitly call `report` before settlement. Reports and settlement notices are separate by design.
328
-
329
- ### Fork boundary
330
-
331
- The parent is executing a tool when `subagent_fork` starts, so its current assistant/tool-result sequence is incomplete. The provider copies only through the latest assistant message whose stop reason is not `toolUse`. This avoids seeding an invalid unbalanced tool turn.
443
+ 1. the child appends a quiet completion update to the direct parent's session;
444
+ 2. once owned descendants are done, the child runtime is either disposed or
445
+ retained in the optional idle LRU;
446
+ 3. an unloaded persistent session is `ready`; a retained settled runtime is
447
+ `idle`;
448
+ 4. `send_message` plus `followup_task` can cold-resume that same session for
449
+ another turn.
450
+
451
+ A child can explicitly call `report` before settlement. A report is recorded in
452
+ the parent session and never starts or queues a parent turn; it is a content
453
+ channel that is separate from the quiet completion update.
454
+
455
+ Continuable turns share a bounded scheduler. Calls targeting the same durable
456
+ agent are serialized so concurrent messages cannot create multiple cold
457
+ runtimes for one child session. Every scheduler-admitted run has a stable
458
+ `turnId` in delegation details and the paired `pi-subagent:turn-start` /
459
+ `pi-subagent:turn-end` events. FIFO follow-ups accepted while that
460
+ `AgentSession` is already running remain part of the same admitted run.
461
+ Existing `pi-subagent:start` / `pi-subagent:end` events continue to describe
462
+ the wider activation lifecycle and now include `taskPath`.
463
+
464
+ With `maxIdleRuntimes: 0`, disposal behavior is unchanged. A positive value
465
+ retains only settled continuable runtimes with no active run, owned descendant,
466
+ or pending mailbox claim. LRU accounting is serialized across concurrent
467
+ settlements. Eviction disposes only the runtime; the descriptor, path, context,
468
+ session history, task mailbox, and completion mailbox remain durable, so the
469
+ next accepted turn cold-resumes normally.
470
+
471
+ #### Mailbox protocol
472
+
473
+ The mailbox separates delivery from execution:
474
+
475
+ 1. `send_message` appends a bounded message record to the direct child's JSONL
476
+ session and returns its stable message id. It does not create a runtime,
477
+ acquire a scheduler permit, create a `turnId`, or emit turn events.
478
+ 2. `followup_task` snapshots the current pending FIFO prefix, waits for the
479
+ normal background scheduler, and starts one turn containing that batch.
480
+ Messages arriving after the snapshot remain pending for a later turn.
481
+ 3. A claim is committed only after Pi prompt preflight succeeds. The durable
482
+ user-turn marker makes a claim without its corresponding prompt recoverable
483
+ after a crash. Once the user turn is durable, the batch is consumed even if
484
+ that model turn later fails or is interrupted.
485
+ 4. Scheduler rejection, cancellation while queued, and shutdown before prompt
486
+ acceptance leave the batch pending. Concurrent sends and starts for one
487
+ agent are serialized within the extension process.
488
+ 5. A completed turn appends a stable completion record to the direct parent's
489
+ separate notification mailbox before the child unloads. This custom entry
490
+ does not enter model context and does not wake or start the parent.
491
+ 6. `wait_agent` returns existing unread updates immediately or subscribes to
492
+ in-process mailbox activity and rechecks durable state after wakeup. Its
493
+ optional timeout defaults to 30 seconds and is capped at 120 seconds.
494
+ 7. A returned update becomes read only after Pi durably appends the successful
495
+ `wait_agent` tool result. An interrupted/failed delivery is released at the
496
+ end of the parent turn; a process restart also makes an orphan reservation
497
+ available again. Delivery output is bounded to a 256 KiB FIFO prefix.
498
+ 8. If the parent completion append fails, the child records an undelivered
499
+ fallback in its own session and emits `pi-subagent:completion-error` before
500
+ normal residency cleanup; no false completion is exposed to `wait_agent`.
501
+
502
+ Each message is limited to 131,072 characters; a mailbox is limited to 256 pending
503
+ messages and 256 KiB of pending UTF-8 content. `list_agents` exposes task
504
+ `pending` and completion `updates` independently from lifecycle and scheduler
505
+ state.
506
+
507
+ FIFO follows durable append order after target resolution, not the invocation
508
+ order of concurrent `send_message` calls. Each returned `pendingMessages` count
509
+ describes that append. If one message must precede another, await the first send
510
+ before starting the next.
511
+
512
+ The durable mailbox is the only background protocol: `send_message` always
513
+ enqueues and `followup_task` is always required to start the queued batch.
514
+
515
+ `wait_agent` observes only completions written by the current agent's direct
516
+ children. Nested parents consume their own child updates; a root wait does not
517
+ steal grandchild updates. Nothing in this extension wakes a parent turn: work
518
+ continues until the parent reads its mailbox.
519
+
520
+ ### Inherited-context boundary
521
+
522
+ The parent is executing a tool when an inherited-context child starts, so its
523
+ current assistant/tool-result sequence is incomplete. The provider projects
524
+ Pi's active compaction-aware context only through a safe completed boundary,
525
+ then copies model-facing entries into a new child session. This avoids seeding
526
+ an invalid unbalanced tool turn and prevents parent control-log records from
527
+ becoming child descriptors or mailbox ownership.
332
528
 
333
529
  ## Security
334
530
 
335
531
  - Extensions and subagents run with the user's OS permissions.
336
- - Opt-in `syncBundledAgents: true` synchronizes bundled presets into the user
337
- agent directory and may create backups under
338
- `<Pi agent dir>/.pi-subagent/backups`. The default does not write these
339
- paths.
532
+ - First-install and package-version initialization writes bundled templates
533
+ into the user agent directory and may create backups under
534
+ `<Pi agent dir>/.pi-subagent/backups`.
340
535
  - Project-local agents are repository-controlled prompts. They are loaded only when the project is trusted and configuration enables project scope.
341
536
  - `inheritExtensions` is disabled by default because loading an extension in a child executes its code and may duplicate external side effects.
342
537
  - Explicit agent tool lists are enforced as registry ceilings, but this controls model visibility and execution composition rather than providing an OS sandbox.
343
- - A child may send content only to its recorded direct parent through `report`; `send_message` likewise requires direct-parent identity.
538
+ - A child may send content only to its recorded direct parent through `report`;
539
+ path resolution is only an address lookup, and `send_message` /
540
+ `followup_task` still require direct-parent identity.
344
541
 
345
542
  ## Current limitations
346
543
 
347
- - Activations and ownership are process-local; there is no cross-process lease or durable mailbox.
348
- - Pi does not expose stable inbox message ids, so control acknowledgements return the child id rather than a delivery id.
349
- - A process crash can lose a prompt accepted just before Pi writes it to the child JSONL; there is no durable mailbox for accepted-but-unlogged work.
544
+ - Activations, scheduling ownership, and mailbox serialization are process-local;
545
+ two Pi processes must not concurrently control the same child session.
546
+ - Readable-path reservation and idle-LRU accounting are process-local. Durable
547
+ UUID identity remains authoritative when multiple processes are involved,
548
+ which is still unsupported.
549
+ - Resident parents still retain `ownedChildren` until descendants settle;
550
+ actor-graph residency, orphan handling, and background GC are not implemented.
551
+ - Pi lazily creates a new child JSONL file on its first assistant entry. The
552
+ initial background agent id therefore has a crash window after prompt
553
+ acceptance; `send_message` waits for that first durable checkpoint before
554
+ acknowledging an enqueue.
555
+ - A foreground child that is still being created has no mailbox; only
556
+ `runtimeMode: "background"` children accept durable messages.
350
557
  - `interrupt_agent` is fire-and-return and relies on Pi's current `AgentSession.abort()` queue behavior.
351
- - The fork provider is intentionally one-shot.
352
558
  - Structured-output delegation is not implemented yet.
353
559
  - Continuable starts require a persisted parent session; ephemeral (`--no-session`) parents can use foreground one-shot delegation only.
354
560
  - `subagent_fork` needs a persisted parent to copy completed history; before the first completed turn its safe prefix is empty and it behaves like a fresh child.
@@ -368,6 +574,5 @@ The test suite includes provider-boundary, descriptor, configuration, discovery,
368
574
  MIT © 2026 oai404iao. See [LICENSE](LICENSE) and
369
575
  [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
370
576
 
371
- Managed global-preset synchronization is opt-in through
372
- `syncBundledAgents: true`; the default reads bundled definitions without
373
- writing user files.
577
+ Bundled presets are initialization templates only. Runtime agent discovery is
578
+ limited to user and trusted project configuration.
package/agents/worker.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: worker
3
3
  description: General-purpose implementation agent with coding tools
4
- tools: read, grep, find, ls, bash, $mutation, subagent, subagent_fork, send_message, interrupt_agent, list_agents
4
+ tools: read, grep, find, ls, bash, $mutation, subagent, subagent_fork, send_message, followup_task, wait_agent, interrupt_agent, list_agents
5
5
  thinking: high
6
6
  ---
7
7
 
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "$schema": "./config.schema.json",
3
3
  "agentScope": "user",
4
- "syncBundledAgents": false,
5
4
  "maxDepth": 3,
6
- "enableRunInBackground": true,
7
- "defaultBackground": true,
8
- "reportDelivery": "wakeup",
5
+ "runtimeMode": "background",
6
+ "maxConcurrentBackgroundRuns": 4,
7
+ "maxIdleRuntimes": 0,
9
8
  "inheritExtensions": false,
10
9
  "openAIIdentity": false,
11
10
  "maxOutputBytes": 51200
@@ -13,15 +13,14 @@
13
13
  },
14
14
  "agentScope": {
15
15
  "type": "string",
16
- "enum": ["user", "project", "both"],
16
+ "enum": [
17
+ "user",
18
+ "project",
19
+ "both"
20
+ ],
17
21
  "description": "Select user definitions, project definitions, or user definitions followed by project overrides.",
18
22
  "default": "user"
19
23
  },
20
- "syncBundledAgents": {
21
- "type": "boolean",
22
- "description": "User-level configuration only. Opt in to materializing bundled presets under the Pi agent directory. When true, startup may install, replace, retire, and back up managed agent files; when false, bundled definitions are read directly without writing user files.",
23
- "default": false
24
- },
25
24
  "maxDepth": {
26
25
  "type": "integer",
27
26
  "minimum": 0,
@@ -29,21 +28,28 @@
29
28
  "description": "Absolute delegation depth. A top-level Pi session has depth 0.",
30
29
  "default": 3
31
30
  },
32
- "enableRunInBackground": {
33
- "type": "boolean",
34
- "description": "Enable continuable background children and their model-facing lifecycle controls. Set false for strict foreground-only mode.",
35
- "default": true
31
+ "runtimeMode": {
32
+ "type": "string",
33
+ "enum": [
34
+ "foreground",
35
+ "background"
36
+ ],
37
+ "description": "Single execution mode. foreground waits for every child's final answer and exposes no lifecycle tools; background starts continuable mailbox-v2 children that return a readable path plus durable id.",
38
+ "default": "background"
36
39
  },
37
- "defaultBackground": {
38
- "type": "boolean",
39
- "description": "Default run mode for the fresh spawn provider when background execution is enabled. Ignored in foreground-only mode.",
40
- "default": true
40
+ "maxConcurrentBackgroundRuns": {
41
+ "type": "integer",
42
+ "minimum": 1,
43
+ "maximum": 9007199254740991,
44
+ "description": "Maximum number of continuable subagent turns that may execute concurrently within one extension runtime.",
45
+ "default": 4
41
46
  },
42
- "reportDelivery": {
43
- "type": "string",
44
- "enum": ["wakeup", "quiet"],
45
- "description": "Whether child reports trigger a parent turn or wait for the parent's next turn.",
46
- "default": "wakeup"
47
+ "maxIdleRuntimes": {
48
+ "type": "integer",
49
+ "minimum": 0,
50
+ "maximum": 9007199254740991,
51
+ "description": "Maximum settled continuable child runtimes retained in the process-wide idle LRU. Zero unloads immediately.",
52
+ "default": 0
47
53
  },
48
54
  "inheritExtensions": {
49
55
  "type": "boolean",
@@ -59,7 +65,7 @@
59
65
  "type": "integer",
60
66
  "minimum": 1024,
61
67
  "maximum": 1048576,
62
- "description": "Maximum child output inserted into a parent tool result, report, or settlement notice.",
68
+ "description": "Maximum child output inserted into a parent tool result, report, or completion update.",
63
69
  "default": 51200
64
70
  }
65
71
  }
package/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { default } from "./src/index.js";
2
+ export * from "./src/index.js";