@maxiaochao/pi-toolkit 0.11.6 → 0.11.8
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 +11 -0
- package/README.md +2 -1
- package/package.json +5 -3
- package/packages/herdr-subagents/ARCHITECTURE.md +82 -378
- package/packages/herdr-subagents/CHANGELOG.md +4 -0
- package/packages/herdr-subagents/README.md +52 -321
- package/packages/herdr-subagents/TESTING.md +36 -53
- package/packages/herdr-subagents/extensions/herdr-subagents.ts +24 -158
- package/packages/herdr-subagents/extensions/subagent-report.ts +21 -7
- package/packages/herdr-subagents/package.json +4 -3
- package/packages/herdr-subagents/src/batch-runner.ts +5 -3
- package/packages/herdr-subagents/src/herdr.ts +11 -0
- package/packages/herdr-subagents/src/live-agent.ts +49 -114
- package/packages/herdr-subagents/src/parameters.ts +2 -6
- package/packages/herdr-subagents/src/protocol.ts +4 -5
- package/packages/herdr-subagents/src/records.ts +2 -0
- package/packages/herdr-subagents/src/tool.ts +9 -51
- package/packages/herdr-subagents/src/validation.ts +0 -4
- package/packages/herdr-subagents/tests/core-state-machine.mjs +178 -0
- package/packages/herdr-subagents/tests/extension-sources-load.mjs +7 -3
- package/packages/openai-account-pool/CHANGELOG.md +11 -0
- package/packages/openai-account-pool/README.md +67 -0
- package/packages/openai-account-pool/TESTING.md +28 -0
- package/packages/openai-account-pool/docs/demo.gif +0 -0
- package/packages/openai-account-pool/docs/screenshot.png +0 -0
- package/packages/openai-account-pool/extensions/openai-account-pool.ts +368 -0
- package/packages/openai-account-pool/package.json +45 -0
- package/packages/openai-account-pool/src/auth.ts +418 -0
- package/packages/openai-account-pool/src/availability.ts +230 -0
- package/packages/openai-account-pool/src/command-completions.ts +18 -0
- package/packages/openai-account-pool/src/enrollment.ts +339 -0
- package/packages/openai-account-pool/src/lease.ts +128 -0
- package/packages/openai-account-pool/src/lock.ts +171 -0
- package/packages/openai-account-pool/src/login-slot.ts +158 -0
- package/packages/openai-account-pool/src/policy.ts +176 -0
- package/packages/openai-account-pool/src/provider.ts +511 -0
- package/packages/openai-account-pool/src/status-widget.ts +62 -0
- package/packages/openai-account-pool/src/store.ts +259 -0
- package/packages/openai-account-pool/src/usage.ts +291 -0
- package/packages/openai-account-pool/tests/command-completions.mjs +10 -0
- package/packages/openai-account-pool/tests/enrollment.mjs +322 -0
- package/packages/openai-account-pool/tests/failover-stream.mjs +554 -0
- package/packages/openai-account-pool/tests/helpers/fixtures.mjs +40 -0
- package/packages/openai-account-pool/tests/helpers/native-credential-store.mjs +58 -0
- package/packages/openai-account-pool/tests/helpers/pi-runtime.mjs +24 -0
- package/packages/openai-account-pool/tests/helpers/refresh-child.mjs +29 -0
- package/packages/openai-account-pool/tests/integration-login-ownership.mjs +299 -0
- package/packages/openai-account-pool/tests/login-slot.mjs +131 -0
- package/packages/openai-account-pool/tests/multiprocess.mjs +73 -0
- package/packages/openai-account-pool/tests/selection.mjs +286 -0
- package/packages/openai-account-pool/tests/store-ownership.mjs +369 -0
- package/packages/openai-account-pool/tests/usage.mjs +428 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
## 2026-10-14 - v0.11.8
|
|
2
|
+
|
|
3
|
+
- bundle openai-account-pool v0.1.0: add OpenAI Codex account pooling with safe quota failover and live usage status
|
|
4
|
+
- bundle the OpenAI Account Pool package
|
|
5
|
+
- Add `@maxiaochao/pi-openai-account-pool` with `/codex_pool`, which pools several ChatGPT Plus/Pro logins behind `openai-codex` and continues a request on the next usable account when one proves it is out of quota.
|
|
6
|
+
- Let `node scripts/capture-package-media.mjs <slug>` regenerate media for selected packages, and render Chinese output with a CJK font.
|
|
7
|
+
|
|
8
|
+
## 2026-10-13 - v0.11.7
|
|
9
|
+
|
|
10
|
+
- bundle herdr-subagents v0.5.0: simplify lifecycle to one report-first state machine with strict serial and bounded read-only parallel execution
|
|
11
|
+
|
|
1
12
|
## 2026-10-13 - v0.11.6
|
|
2
13
|
|
|
3
14
|
- add a Why column to the child package table in README
|
package/README.md
CHANGED
|
@@ -33,7 +33,8 @@ Restart Pi after updating. The `todo` tool and widget will no longer load. `pi u
|
|
|
33
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
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
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) |
|
|
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-openai-account-pool](packages/openai-account-pool/README.md) | Several ChatGPT Plus/Pro logins behind `openai-codex`, switching accounts on a proven quota limit | `pi install npm:@maxiaochao/pi-openai-account-pool` | `pi update npm:@maxiaochao/pi-openai-account-pool` | One `/login openai-codex` credential overwrites the previous one, so hitting the subscription limit meant logging in again by hand mid-task; this keeps the accounts I authorized side by side and continues the same request on the next usable one |
|
|
37
38
|
| [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
39
|
| [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
40
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maxiaochao/pi-toolkit",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.8",
|
|
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": [
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"packages/cache-export",
|
|
17
17
|
"packages/codex-edit",
|
|
18
18
|
"packages/herdr-subagents",
|
|
19
|
+
"packages/openai-account-pool",
|
|
19
20
|
"packages/scheduler",
|
|
20
21
|
"packages/worktree",
|
|
21
22
|
"themes",
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
"./extensions/btw/index.ts",
|
|
36
37
|
"./packages/codex-edit/extensions/codex-edit.ts",
|
|
37
38
|
"./packages/herdr-subagents/extensions/herdr-subagents.ts",
|
|
39
|
+
"./packages/openai-account-pool/extensions/openai-account-pool.ts",
|
|
38
40
|
"./packages/scheduler/extensions/scheduler.ts",
|
|
39
41
|
"./packages/worktree/extensions/worktree.ts"
|
|
40
42
|
],
|
|
@@ -59,8 +61,8 @@
|
|
|
59
61
|
"ws": "^8.19.0"
|
|
60
62
|
},
|
|
61
63
|
"scripts": {
|
|
62
|
-
"test": "node tests/package-layout.mjs && npm --prefix packages/todo test && npm --prefix packages/cache-export test && npm --prefix packages/codex-edit test && npm --prefix packages/herdr-subagents test && npm --prefix packages/scheduler test && npm --prefix packages/worktree test && node --experimental-strip-types extensions/btw/tests/history.mjs",
|
|
63
|
-
"load-test": "pi -ne -e ./packages/cache-export/extensions/cache-export.ts && pi -ne -e ./extensions/btw/index.ts && pi -ne -e ./packages/codex-edit/extensions/codex-edit.ts && pi -ne -e ./packages/herdr-subagents/extensions/herdr-subagents.ts && pi -ne -e ./packages/scheduler/extensions/scheduler.ts && pi -ne -e ./packages/worktree/extensions/worktree.ts",
|
|
64
|
+
"test": "node tests/package-layout.mjs && npm --prefix packages/todo test && npm --prefix packages/cache-export test && npm --prefix packages/codex-edit test && npm --prefix packages/herdr-subagents test && npm --prefix packages/openai-account-pool test && npm --prefix packages/scheduler test && npm --prefix packages/worktree test && node --experimental-strip-types extensions/btw/tests/history.mjs",
|
|
65
|
+
"load-test": "pi -ne -e ./packages/cache-export/extensions/cache-export.ts && pi -ne -e ./extensions/btw/index.ts && pi -ne -e ./packages/codex-edit/extensions/codex-edit.ts && pi -ne -e ./packages/herdr-subagents/extensions/herdr-subagents.ts && pi -ne -e ./packages/openai-account-pool/extensions/openai-account-pool.ts && pi -ne -e ./packages/scheduler/extensions/scheduler.ts && pi -ne -e ./packages/worktree/extensions/worktree.ts",
|
|
64
66
|
"eval:agents": "node evaluations/agents-md/run.mjs",
|
|
65
67
|
"eval:agents:test": "node evaluations/agents-md/tests/run-tests.mjs",
|
|
66
68
|
"postinstall": "node scripts/install-agents.mjs"
|
|
@@ -1,408 +1,112 @@
|
|
|
1
|
-
# Herdr Subagents architecture
|
|
1
|
+
# Herdr Subagents architecture
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Goal
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
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
|
-
|
|
9
|
+
## State machines
|
|
10
10
|
|
|
11
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
70
|
+
A run uses a bounded worker pool:
|
|
338
71
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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
|
-
|
|
79
|
+
There is no global dispatcher, persisted background queue, blocked response lane, historical resume, or early detach.
|
|
346
80
|
|
|
347
|
-
|
|
81
|
+
## Child boundary
|
|
348
82
|
|
|
349
|
-
-
|
|
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
|
-
|
|
85
|
+
The child writes:
|
|
355
86
|
|
|
356
|
-
|
|
87
|
+
- `results/<attempt-id>.md`
|
|
88
|
+
- `reports/<attempt-id>.json`
|
|
357
89
|
|
|
358
|
-
|
|
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
|
-
|
|
92
|
+
The orchestrator writes:
|
|
373
93
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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
|
-
##
|
|
98
|
+
## Completion arbitration
|
|
391
99
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
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
|
-
|
|
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
|
-
|
|
108
|
+
Writing the same report again is idempotent. A conflicting replacement is rejected.
|
|
402
109
|
|
|
403
|
-
|
|
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
|
-
|
|
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
|