@maxiaochao/pi-toolkit 0.11.5 → 0.11.7

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/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 2026-10-13 - v0.11.7
2
+
3
+ - bundle herdr-subagents v0.5.0: simplify lifecycle to one report-first state machine with strict serial and bounded read-only parallel execution
4
+
5
+ ## 2026-10-13 - v0.11.6
6
+
7
+ - add a Why column to the child package table in README
8
+
1
9
  ## 2026-10-13 - v0.11.5
2
10
 
3
11
  - bundle herdr-subagents v0.4.14: allow explicit extension sources with native Pi package semantics and reliable cleanup checks
package/README.md CHANGED
@@ -28,14 +28,14 @@ Restart Pi after updating. The `todo` tool and widget will no longer load. `pi u
28
28
 
29
29
  ## Child packages
30
30
 
31
- | Package | Capability | Install | Update |
32
- |---|---|---|---|
33
- | [pi-todo](packages/todo/README.md) | Optional branch-local execution plan UI; not bundled with pi-toolkit | `pi install npm:@maxiaochao/pi-todo` | `pi update npm:@maxiaochao/pi-todo` |
34
- | [pi-cache-export](packages/cache-export/README.md) | Tau-aligned interactive cache dashboard for Pi sessions | `pi install npm:@maxiaochao/pi-cache-export` | `pi update npm:@maxiaochao/pi-cache-export` |
35
- | [pi-codex-edit](packages/codex-edit/README.md) | Codex-harness `apply_patch` routing for selected GPT models | `pi install npm:@maxiaochao/pi-codex-edit` | `pi update npm:@maxiaochao/pi-codex-edit` |
36
- | [pi-herdr-subagents](packages/herdr-subagents/README.md) | Interactive Herdr Pi Agents with bounded concurrency, direct navigation, and recovery | `pi install npm:@maxiaochao/pi-herdr-subagents` | `pi update npm:@maxiaochao/pi-herdr-subagents` |
37
- | [pi-scheduler](packages/scheduler/README.md) | Session-scoped interval prompts with Agent and `/schedule` controls | `pi install npm:@maxiaochao/pi-scheduler` | `pi update npm:@maxiaochao/pi-scheduler` |
38
- | [pi-worktree](packages/worktree/README.md) | Worktree CLI, current-session switching Extension, and agent skill | `pi install npm:@maxiaochao/pi-worktree` | `pi update npm:@maxiaochao/pi-worktree` |
31
+ | Package | Capability | Install | Update | Why |
32
+ |---|---|---|---|---|
33
+ | [pi-todo](packages/todo/README.md) | Optional branch-local execution plan UI; not bundled with pi-toolkit | `pi install npm:@maxiaochao/pi-todo` | `pi update npm:@maxiaochao/pi-todo` | I don't recommend this for now, as both OpenAI and Claude Code official have stated that strong models are currently cumbersome in Todo |
34
+ | [pi-cache-export](packages/cache-export/README.md) | Tau-aligned interactive cache dashboard for Pi sessions | `pi install npm:@maxiaochao/pi-cache-export` | `pi update npm:@maxiaochao/pi-cache-export` | Because I watched the cache video on @alejandro.ao YouTube, which has a Tau style page for viewing cache |
35
+ | [pi-codex-edit](packages/codex-edit/README.md) | Codex-harness `apply_patch` routing for selected GPT models | `pi install npm:@maxiaochao/pi-codex-edit` | `pi update npm:@maxiaochao/pi-codex-edit` | The core lies in the fact that the Codex model is naturally good at apply_patch, and the model is trained on this during training. However, hash-based in-context patch schemes have high token costs and complexity |
36
+ | [pi-herdr-subagents](packages/herdr-subagents/README.md) | Visible Herdr Pi Agents coordinated by a small task state machine | `pi install npm:@maxiaochao/pi-herdr-subagents` | `pi update npm:@maxiaochao/pi-herdr-subagents` | I wanted simple serial or bounded-parallel dispatch while each task stays a real interactive Pi session in its own Herdr pane, and the main conversation only receives short summaries instead of every child's full transcript |
37
+ | [pi-scheduler](packages/scheduler/README.md) | Session-scoped interval prompts with Agent and `/schedule` controls | `pi install npm:@maxiaochao/pi-scheduler` | `pi update npm:@maxiaochao/pi-scheduler` | I don't recommend this, it's just that it sends messages to the main session at loop intervals |
38
+ | [pi-worktree](packages/worktree/README.md) | Worktree CLI, current-session switching Extension, and agent skill | `pi install npm:@maxiaochao/pi-worktree` | `pi update npm:@maxiaochao/pi-worktree` | In addition to the basic worktree CLI + skill, what can be achieved is to directly switch to the worktree path in the main conversation to continue the task conversation after communicating the requirements in the main conversation |
39
39
 
40
40
  Each child README owns its feature description, motivation or upstream alignment, examples, screenshots/demos, configuration, and test documentation.
41
41
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maxiaochao/pi-toolkit",
3
- "version": "0.11.5",
3
+ "version": "0.11.7",
4
4
  "description": "Personal pi coding agent toolkit: scheduler, /btw, /cache_export, apply_patch, browser automation, and bundled theme/skills.",
5
5
  "type": "module",
6
6
  "workspaces": [
@@ -1,408 +1,112 @@
1
- # Herdr Subagents architecture and decision-pause design
1
+ # Herdr Subagents architecture
2
2
 
3
- This document describes the package's current architecture, the problems exposed by failure and blocking semantics, and the target decision-pause model. Sections marked **Current** describe implemented behavior. Sections marked **Target** are an implementation plan, not the current contract.
3
+ ## Goal
4
4
 
5
- ## 1. Product boundary
5
+ Herdr owns terminal presentation and pane operations. The package owns scheduling and durable state. Pi children own only their attempt result.
6
6
 
7
- Herdr Subagents runs ordinary interactive Pi Agents in visible Herdr panes and keeps their complete sessions and results in project-local durable records. The parent receives compact status, questions, summaries, and document paths.
7
+ The implementation deliberately stays small: one task state machine, one run aggregation rule, and one bounded worker pool. Serial and read-only parallel dispatch share the same path. There are no alternate lifecycle engines for background work, blocking, retries, or resume.
8
8
 
9
- A batch is a resource-bounded collection of **independent tasks**:
9
+ ## State machines
10
10
 
11
- - array order controls FIFO scheduling, pane numbering, and result order;
12
- - `concurrency` controls how many tasks may be active at once;
13
- - a batch containing a write-capable persona is forced to concurrency one;
14
- - concurrency one does **not** express `A -> B` dependency semantics;
15
- - tasks that consume another task's result must be orchestrated by the parent as separate runs.
11
+ Task:
16
12
 
17
- The package does not currently need a DAG scheduler. If dependency workflows become a first-class product requirement, they should be introduced explicitly with dependency and skip-propagation semantics instead of inferred from array order.
18
-
19
- ## 2. Architecture overview
20
-
21
- ```text
22
- Parent Pi tool call
23
- |
24
- v
25
- Extension lifecycle and foreground handoff
26
- | extensions/herdr-subagents.ts
27
- v
28
- Global run dispatcher ---- persisted background queue
29
- | src/dispatcher.ts, src/queued-runs.ts
30
- v
31
- Batch runner and bounded workers
32
- | src/batch-runner.ts
33
- +---- pane allocation / Herdr Agent lifecycle
34
- | src/run-pane-allocator.ts, src/live-agent.ts, src/herdr.ts
35
- +---- attempt-scoped structured report
36
- | src/attempts.ts, src/protocol.ts, src/records.ts
37
- +---- durable run/task/session records
38
- | .pi/herdr-subagents/runs/<run>/...
39
- v
40
- Aggregate status, monitor, control, recovery and cleanup
41
- src/run-status.ts, src/status.ts, src/fleet*.ts,
42
- src/blocking.ts, src/historical-resume.ts,
43
- src/reconcile.ts, src/tab-cleanup.ts
44
- ```
45
-
46
- ### Responsibilities
47
-
48
- | Layer | Responsibility |
49
- | --- | --- |
50
- | Extension | Register tools, bind parent-session lifetime, return foreground results, send final background follow-ups. |
51
- | Dispatcher | Give one run ownership of the global submission lane and queue later submissions FIFO. |
52
- | Batch runner | Persist the run, start bounded workers, allocate one pane per task, and aggregate task results. |
53
- | Live Agent adapter | Start or continue an interactive Pi Agent and distinguish runtime telemetry from business reports. |
54
- | Records | Atomically persist run, task, turn, report, attempt, ownership, and resume state. |
55
- | Control | Inspect, answer, retry/continue saved work, cancel, resume history, and clean archives. |
56
- | Recovery | Reconcile stale owners and processes, settle abandoned work, and clean identifiable tabs. |
57
- | Fleet | Project durable business state plus transient runtime telemetry into the parent UI. |
58
-
59
- ## 3. Authoritative state and invariants
60
-
61
- 1. A matching attempt-scoped `subagent_report` is authoritative for business `completed`, `blocked`, or `failed`.
62
- 2. Herdr `working`, `blocked`, `idle`, and `done` are transport/runtime telemetry. Herdr UI `blocked` projects to `waiting_interaction`; it does not make the business task blocked.
63
- 3. Each task owns one pane and one Pi session. A pane is never reused by another task.
64
- 4. A task session has at most one writer. Task resume locks enforce that invariant.
65
- 5. Shared `run.json` changes occur under the short-lived run-state lock. An Agent turn never holds that lock.
66
- 6. Every new prompt has a unique attempt ID. A late report from an older attempt cannot settle a newer attempt.
67
- 7. Task and report state is persisted before it is exposed as an actionable parent result.
68
- 8. Running work is not forcibly interrupted merely because a sibling needs a decision.
69
-
70
- ## 4. Current execution flow
71
-
72
- ### Submission
73
-
74
- 1. Tool parameters are validated.
75
- 2. Configuration and personas are loaded and resolved.
76
- 3. A stable run ID is allocated.
77
- 4. Background runs are durably queued before dispatch; foreground runs wait for the dispatcher lane.
78
- 5. The batch runner creates `run.json`, task directories, task records, prompts, and session paths.
79
- 6. Effective concurrency is bounded by settings and forced to one if any persona is write-capable.
80
-
81
- ### Task execution
82
-
83
- Each worker repeatedly claims the next FIFO task, allocates a pane, starts an interactive Pi Agent, waits for the matching structured report, persists the result, and claims another task. A failed task does not currently stop that worker. A blocked task stops only its worker lane.
84
-
85
- ### Current foreground outcomes
86
-
87
- | Event | Current foreground behavior | Queued siblings |
88
- | --- | --- | --- |
89
- | All tasks complete | Return after the whole batch settles. | Completed normally. |
90
- | Failure with concurrency one | Continue later tasks, then return terminal `failed` or `partial`. | Continue automatically. |
91
- | Failure with concurrency greater than one and unfinished siblings | Persist the failure, return early, detach the batch, and let it finish in the background. | Continue automatically. |
92
- | Business block | Wait for the other worker lanes to settle, then return the question and retain the dispatcher lane. | A blocked worker stops, but other workers keep claiming tasks. |
93
- | Herdr UI block | Keep waiting for an authoritative report while showing `waiting_interaction`. | Unchanged. |
94
-
95
- The failure and block rows are asymmetric: parallel failure gives control back promptly, while block may withhold its question until unrelated work finishes. Serial failure also assumes later tasks are independent. The target design removes both ambiguities.
96
-
97
- ## 5. Dispatcher ownership in plain language
98
-
99
- The dispatcher is the global submission lane, not the task-concurrency limiter.
100
-
101
- | Operation | Meaning |
102
- | --- | --- |
103
- | `detach` | The run continues in the background but gives up the submission lane, so another run may start. |
104
- | `retain` | The run is waiting for a parent decision and keeps the lane; a new foreground run is rejected and a background run stays queued. |
105
- | `release` | A retained run is resolved or cancelled and gives up the lane. |
106
-
107
- Current parallel failure uses `detach`; current business block eventually uses `retain`.
108
-
109
- ## 6. Target decision-pause model
110
-
111
- ### Goal
112
-
113
- Any actionable business problem returns control to the parent immediately and stops new task dispatch until the parent decides what to do. Already-running siblings are allowed to finish safely.
114
-
115
- ```text
116
- A reports failed or blocked
117
- |
118
- +---- persist task/report/attempt state
119
- +---- pause new queue claims
120
- +---- return pause details to the parent immediately
121
- +---- retain the dispatcher lane
122
- |
123
- B and C were already running ---- continue to a terminal report
124
- D and E were queued ------------- remain queued
125
- ```
126
-
127
- "Pause" means pausing **dispatch**, not freezing an Agent process at an arbitrary instruction. Forcibly suspending or cancelling running siblings could leave tools, file writes, or external operations in an unknown state.
128
-
129
- ### Run control state must be separate from task outcome
130
-
131
- The current `RunStatus` reuses task statuses and aggregates them into `running`, `blocked`, `partial`, and terminal values. That combines two different questions:
132
-
133
- 1. May the scheduler dispatch more work?
134
- 2. What outcomes have tasks produced?
135
-
136
- The target model separates them conceptually:
137
-
138
- ```ts
139
- type RunPhase = "queued" | "running" | "paused" | "cancelling" | "settled";
140
- type RunOutcome = "completed" | "partial" | "failed" | "cancelled";
141
- ```
142
-
143
- The public status projection may continue exposing `status: "paused"` for convenience, but durable control logic should use the phase. While a run is paused, some task activities may still be `running` as already-started siblings settle.
144
-
145
- ### Durable pause reasons
146
-
147
- A pause is tied to a specific task attempt so stale answers cannot resolve newer work:
148
-
149
- ```ts
150
- interface PauseReason {
151
- taskId: string;
152
- taskOrder: number;
153
- attemptId: string;
154
- kind: "blocked" | "failed";
155
- resolution: "pending" | "responded" | "retried" | "continued" | "cancelled";
156
- createdAt: string;
157
- resolvedAt?: string;
158
- }
159
- ```
160
-
161
- The durable reason should reference authoritative task/report records instead of duplicating mutable summary, question, and error text. Status and tool responses project a detailed view:
162
-
163
- ```json
164
- {
165
- "status": "paused",
166
- "pauseReasons": [
167
- {
168
- "task": 1,
169
- "kind": "failed",
170
- "summary": "Authentication review failed.",
171
- "error": "Provider request failed.",
172
- "allowedActions": ["retry", "continue", "cancel"]
173
- }
174
- ]
175
- }
13
+ ```mermaid
14
+ stateDiagram-v2
15
+ [*] --> queued
16
+ queued --> running: worker slot available
17
+ queued --> cancelled: parent cancellation
18
+ running --> completed: valid completed report
19
+ running --> failed: valid failed report or process exits without report
20
+ running --> cancelled: parent cancellation
21
+ completed --> [*]
22
+ failed --> [*]
23
+ cancelled --> [*]
176
24
  ```
177
25
 
178
- Multiple already-running siblings may subsequently fail or block. Their reasons accumulate. No queued task starts while any pending reason remains.
179
-
180
- ### Decision actions
181
-
182
- | Reason | Action | Effect |
183
- | --- | --- | --- |
184
- | `blocked` | `respond` | Continue the same live/saved session with the answer. |
185
- | `failed` | `retry` | Retry or continue the selected task explicitly; never infer a task. |
186
- | `failed` | `continue` | Accept that task's failure and allow the run to proceed without retrying it. |
187
- | Any | `cancel` | Cancel running and queued work and settle the run as cancelled. |
188
-
189
- `respond` should no longer be overloaded for failed tasks once `retry` exists. This makes control intent and audit history explicit.
190
-
191
- The queue resumes only when every pending pause reason is resolved. A retry or response that blocks/fails again creates a reason for the new attempt.
192
-
193
- ### Failure classification
194
-
195
- Both child-reported failures and generated terminal failures can pause a run:
196
-
197
- - valid `subagent_report(status="failed")`;
198
- - child process or prompt API terminal error without a valid report;
199
- - Agent settled without publishing a report after the grace period;
200
- - pane or Agent startup failure.
201
-
202
- Ambiguous prompt delivery remains `delivery_unknown` while the child is alive and must not be converted into a retryable failure. Retry safety should be projected explicitly when the implementation can prove whether a prompt was submitted; the system must never automatically replay an attempt with uncertain side effects.
203
-
204
- ### Foreground handoff
205
-
206
- Failure and block should share one foreground-handoff mechanism:
207
-
208
- 1. observe an actionable, durably persisted task attempt;
209
- 2. atomically pause dispatch and register its reason;
210
- 3. detach the parent tool-call abort signal without cancelling the run;
211
- 4. retain dispatcher ownership;
212
- 5. return the projected pause details immediately;
213
- 6. keep already-running siblings and final background lifecycle tracking alive;
214
- 7. send at most one terminal follow-up after the run eventually settles.
215
-
216
- The event-specific policy only determines allowed decisions and response rendering. It should not duplicate lifecycle, persistence, or notification machinery.
217
-
218
- ## 7. Target flows
219
-
220
- ### Independent parallel tasks
221
-
222
- ```text
223
- Submit A, B, C, D with concurrency 3
224
- A/B/C start; D queued
225
- A fails
226
- -> run phase paused
227
- -> D remains queued
228
- -> parent receives A failure immediately
229
- B/C continue safely
230
- Parent retries A, continues past A, or cancels
231
- -> once all pending reasons are resolved, dispatch may resume
26
+ The three terminal states are immutable. Follow-up work creates a new task or run.
27
+
28
+ Run:
29
+
30
+ ```mermaid
31
+ stateDiagram-v2
32
+ [*] --> running
33
+ running --> completed: every task completed
34
+ running --> failed: every task failed
35
+ running --> cancelled: every task cancelled
36
+ running --> partial: terminal outcomes are mixed
37
+ completed --> [*]
38
+ failed --> [*]
39
+ cancelled --> [*]
40
+ partial --> [*]
232
41
  ```
233
42
 
234
- ### Serial tasks
235
-
236
- ```text
237
- Submit A, B, C with concurrency 1
238
- A starts; B/C queued
239
- A fails or blocks
240
- -> run phase paused
241
- -> B/C do not start
242
- -> parent decides
43
+ Run state is derived from task state. `partial` means terminal tasks have mixed outcomes.
44
+
45
+ Scheduler and arbitration:
46
+
47
+ ```mermaid
48
+ flowchart TD
49
+ Q[Queued tasks] -->|FIFO, free worker slot| S[Start Pi in Herdr pane]
50
+ S --> P[Deliver prompt exactly once]
51
+ P --> R{Attempt report exists?}
52
+ R -->|yes| V[Validate attempt and report]
53
+ V --> T[Commit immutable terminal task]
54
+ R -->|no| L{Child Pi process alive?}
55
+ L -->|yes| W[Herdr wait wake-up]
56
+ W --> R
57
+ L -->|no| C{Final disk reconciliation}
58
+ C -->|report found| V
59
+ C -->|no report| F[Commit failed task]
60
+ T --> Q
61
+ F --> Q
243
62
  ```
244
63
 
245
- This makes serial execution safer, but still does not make B consume A's result. A real `A -> B` workflow remains parent-orchestrated as separate runs.
246
-
247
- ### Runtime-only Herdr block
248
-
249
- ```text
250
- Herdr reports blocked
251
- -> task remains business running
252
- -> Fleet shows waiting_interaction
253
- -> no decision pause yet
254
- Child publishes matching structured blocked report
255
- -> create pause reason
256
- -> return exact question
257
- ```
258
-
259
- ## 8. Configuration: keep fewer concepts, not necessarily fewer files
260
-
261
- ### Current user-facing sources
262
-
263
- | Scope | Runtime settings and persona overrides | Persona definitions and prompts |
264
- | --- | --- | --- |
265
- | Project | `.pi/herdr-subagents.json` | `.pi/herdr-subagents/agents/*.md` |
266
- | Global | `~/.pi/agent/herdr-subagents.json` | `~/.pi/agent/herdr-subagents/agents/*.md` |
267
- | Package | Built-in defaults | Built-in `agents/*.md` |
268
-
269
- The two formats have distinct jobs:
270
-
271
- - JSON is suitable for environment policy and small overrides.
272
- - Markdown frontmatter plus body is suitable for a named persona and its system prompt.
273
-
274
- Merging them into one physical file would either put long prompts into JSON or require runtime policy to be parsed from Markdown. It would also force users to copy an entire built-in persona merely to override its model. Therefore the two physical forms should remain.
275
-
276
- ### Sources of confusion to remove
277
-
278
- 1. Persona Markdown and JSON both expose `model`, `thinking`, `skills`, and `extensions`; this is intentional override layering but must be described as one resolution pipeline.
279
- 2. Call-level task model overrides are resolved later in `tool.ts`, after configuration loading.
280
- 3. TypeBox validates shape while `validation.ts` validates action-dependent requirements; these are complementary but currently look like duplicated validation.
281
- 4. Downstream modules receive partially resolved values instead of one canonical run plan.
282
-
283
- ### Canonical normalization boundary
284
-
285
- All sources should be normalized once before persistence or dispatch:
286
-
287
- ```text
288
- Built-in defaults
289
- <- global JSON
290
- <- project JSON
291
- <- effective persona Markdown
292
- <- global persona override
293
- <- project persona override
294
- <- call/task override
295
- |
296
- v
297
- ResolvedRunPlan + diagnostics + source metadata
298
- ```
299
-
300
- A target canonical plan can contain only execution-ready values:
301
-
302
- ```ts
303
- interface ResolvedRunPlan {
304
- label: string;
305
- requestedConcurrency: number;
306
- effectiveConcurrency: number;
307
- tasks: Array<{
308
- name: string;
309
- prompt: string;
310
- persona: string;
311
- access: "read" | "write";
312
- model?: string;
313
- thinking?: string;
314
- tools?: string[];
315
- skills: string[];
316
- extensions: string[];
317
- systemPrompt: string;
318
- }>;
319
- provenance: Record<string, string>;
320
- diagnostics: string[];
321
- }
322
- ```
323
-
324
- After this boundary, the batch runner, persistence, recovery, and UI should not know about global/project/package precedence.
325
-
326
- ### Configuration reductions
64
+ Herdr `idle`, `blocked`, and `done` never transition a business task; they only wake the reconciliation loop.
327
65
 
328
- Do:
66
+ Legacy readers still accept old `starting` and `blocked` values so existing archives can be inspected and cleaned up. New execution does not produce them.
329
67
 
330
- - retain one JSON settings file per scope and one persona directory per scope;
331
- - centralize precedence and call overrides in a single `resolveRunPlan` step;
332
- - expose resolved values and provenance through `list/settings` diagnostics;
333
- - state prominently that batch tasks are independent;
334
- - make decision pause the safe fixed behavior rather than adding a new failure-policy option;
335
- - keep runtime-only Herdr states out of business configuration.
68
+ ## Scheduling
336
69
 
337
- Do not add now:
70
+ A run uses a bounded worker pool:
338
71
 
339
- - DAG or `dependsOn` configuration;
340
- - configurable `failurePolicy` variants;
341
- - separate block/failure handoff settings;
342
- - automatic retry counts;
343
- - configuration for dispatcher `detach`/`retain` behavior.
72
+ 1. Tasks begin FIFO.
73
+ 2. With concurrency one, the next task cannot start until the previous task is terminal.
74
+ 3. With concurrency N, at most N tasks own live child processes.
75
+ 4. Failure consumes only that task's lane; queued siblings continue.
76
+ 5. Parallel execution is rejected if any task is write-capable.
77
+ 6. The caller remains attached until all tasks are terminal or the caller cancels.
344
78
 
345
- These options would multiply state-machine branches before a demonstrated need. The safe decision gate should be the invariant.
79
+ There is no global dispatcher, persisted background queue, blocked response lane, historical resume, or early detach.
346
80
 
347
- ### Validation ownership
81
+ ## Child boundary
348
82
 
349
- - `parameters.ts`: public schema, field types, basic bounds, and model-visible descriptions.
350
- - `validation.ts`: cross-field and action-specific requirements.
351
- - `resolveRunPlan`: persona existence, precedence, capability constraints, effective concurrency, and canonical values.
352
- - runtime state machine: whether an action is legal for the selected run/task/attempt.
83
+ Each task owns one Herdr pane and one single-task Pi process. Herdr first starts and detects the interactive Pi, then submits the prompt exactly once. The child extension exits the process at Pi’s final `agent_settled` boundary, giving each task an unambiguous process lifetime without parent-side prompt retries.
353
84
 
354
- This division avoids both duplicated validation and an oversized configuration loader.
85
+ The child writes:
355
86
 
356
- ## 9. Implementation seams for the target model
87
+ - `results/<attempt-id>.md`
88
+ - `reports/<attempt-id>.json`
357
89
 
358
- | Area | Required change |
359
- | --- | --- |
360
- | `records.ts` | Separate run phase/outcome, persist attempt-scoped pause reasons, and preserve backward-compatible reads. |
361
- | `run-status.ts` | Aggregate task outcomes independently from scheduler phase. |
362
- | `batch-runner.ts` | Add a shared dispatch gate; stop queue claims immediately when a reason is registered. |
363
- | `extensions/herdr-subagents.ts` | Replace failure-only early return with shared actionable-event handoff. |
364
- | `dispatcher.ts` | Retain paused runs and release only after resolution/cancellation; keep ownership transitions explicit. |
365
- | `blocking.ts` / control | Split blocked `respond` from failed `retry`; add explicit `continue`. |
366
- | `continue-run.ts` | Resume queued dispatch only when no pending reason remains. |
367
- | `reconcile.ts` | Recover paused runs and cancel them when their owning parent session disappears. |
368
- | `status.ts` / Fleet | Show pause reasons, allowed actions, and still-running sibling activity together. |
369
- | `parameters.ts` / `validation.ts` | Add `retry` and `continue`, clarify independent-task semantics. |
370
- | tests | Cover immediate handoff, dispatch pause, multiple reasons, resolution races, restart recovery, and exactly-once final notification. |
90
+ Both are attempt-scoped. The report is published with atomic rename. The orchestrator validates it, verifies the attempt identity, and promotes it to `report.json`.
371
91
 
372
- ## 10. Required tests
92
+ The orchestrator writes:
373
93
 
374
- 1. Serial failure pauses before the next queued task starts.
375
- 2. Serial block pauses before the next queued task starts.
376
- 3. Parallel failure returns immediately while already-running siblings continue.
377
- 4. Parallel block returns immediately while already-running siblings continue.
378
- 5. Queued siblings never start while a reason is pending.
379
- 6. A second already-running sibling can add another pause reason without losing the first.
380
- 7. Resolving only one of multiple reasons does not resume dispatch.
381
- 8. `continue` preserves the failed task result and eventually produces `partial` when other tasks succeed.
382
- 9. Retry/response is scoped to task and attempt; stale resolution is rejected.
383
- 10. Herdr UI `blocked` alone never pauses business dispatch.
384
- 11. `delivery_unknown` never causes automatic replay.
385
- 12. A paused run retains the dispatcher lane; foreground submissions fail fast and background submissions remain queued.
386
- 13. Cancellation settles running/queued tasks and releases the retained lane.
387
- 14. Parent-session shutdown and startup reconciliation do not leave ownerless paused work.
388
- 15. Foreground handoff and final follow-up are each delivered at most once.
94
+ - `task.json`
95
+ - `run.json`
96
+ - promoted `report.json`
389
97
 
390
- ## 11. Non-goals
98
+ ## Completion arbitration
391
99
 
392
- - Inferring dependencies from task order or prompt text.
393
- - Freezing arbitrary live Agent processes.
394
- - Automatically retrying failed or ambiguously delivered prompts.
395
- - Treating Herdr UI state as business truth.
396
- - Loading complete child results into parent context.
397
- - Adding policy configuration for every state transition.
100
+ 1. Check for a valid attempt report.
101
+ 2. If present, the report wins, including against a concurrent cancellation observation.
102
+ 3. Otherwise inspect child process liveness.
103
+ 4. While the process is alive, keep waiting. Herdr agent states only wake reconciliation.
104
+ 5. If the process has exited, check disk once more and fail only when no report exists.
398
105
 
399
- ## 12. Summary
106
+ There is no fixed drain delay and no transcript parsing. Pi retries are internal to the same one-shot process, so transient provider or transport errors cannot create a premature terminal task.
400
107
 
401
- The architecture becomes clearer when it separates four concerns:
108
+ Writing the same report again is idempotent. A conflicting replacement is rejected.
402
109
 
403
- 1. **Task outcome:** what each child authoritatively reported.
404
- 2. **Run phase:** whether new work may be dispatched or a parent decision is required.
405
- 3. **Runtime telemetry:** what Herdr currently observes without changing business truth.
406
- 4. **Dispatcher ownership:** whether another run may enter the global submission lane.
110
+ ## Cancellation and recovery
407
111
 
408
- The immediate next design step is a shared decision-pause and foreground-handoff mechanism for business failure and block. Configuration should be simplified through one canonical resolution boundary and fewer policy choices, not by forcing settings and persona prompts into one file.
112
+ Caller or parent-session cancellation aborts active waits, marks nonterminal tasks cancelled, and closes the owned Herdr tab. Startup recovery is scoped by recorded parent ownership and retains readers for prior record formats. Recovery never resumes or mutates an already terminal task.
@@ -1,3 +1,7 @@
1
+ ## 2026-10-13 - v0.5.0
2
+
3
+ - simplify lifecycle to one report-first state machine with strict serial and bounded read-only parallel execution
4
+
1
5
  ## 2026-10-13 - v0.4.14
2
6
 
3
7
  - allow explicit extension sources with native Pi package semantics and reliable cleanup checks