immune-brain 5.2.0 → 5.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +4 -4
  2. package/README.zh-CN.md +4 -4
  3. package/package.json +2 -1
  4. package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
  5. package/plugins/immune-brain/.pi-extension/imm-canary-enroll.ts +54 -70
  6. package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +163 -28
  7. package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +71 -10
  8. package/plugins/immune-brain/.pi-extension/pi-canary-tool-failure.ts +1 -1
  9. package/plugins/immune-brain/.pi-extension/pi-run-continuation.ts +161 -0
  10. package/plugins/immune-brain/agents/immune-brain-reviewer.md +26 -2
  11. package/plugins/immune-brain/dist/BASELINE.md +17 -1
  12. package/plugins/immune-brain/dist/claude/mcp-server.mjs +16145 -12745
  13. package/plugins/immune-brain/dist/docs/reference/code-quality-guard.md +3 -1
  14. package/plugins/immune-brain/dist/docs/reference/immune-brain-config.md +41 -1
  15. package/plugins/immune-brain/dist/docs/reference/planning-quality-gate.md +1 -1
  16. package/plugins/immune-brain/dist/imm-brainstorm.md +1 -1
  17. package/plugins/immune-brain/dist/imm-planner.md +63 -19
  18. package/plugins/immune-brain/dist/imm-run-batch.md +398 -0
  19. package/plugins/immune-brain/dist/imm-run.md +89 -344
  20. package/plugins/immune-brain/dist/role-prompts/code-review.md +26 -2
  21. package/plugins/immune-brain/dist/role-prompts/executor.md +35 -10
  22. package/plugins/immune-brain/hooks/hooks.json +22 -2
  23. package/plugins/immune-brain/runtime/assurance/coordinator.ts +203 -13
  24. package/plugins/immune-brain/runtime/assurance/delivery_workspace.ts +2 -1
  25. package/plugins/immune-brain/runtime/assurance/enrollment_git_base.ts +99 -14
  26. package/plugins/immune-brain/runtime/assurance/phase_entry.ts +10 -26
  27. package/plugins/immune-brain/runtime/assurance/qa.ts +126 -43
  28. package/plugins/immune-brain/runtime/assurance/qa_findings.ts +8 -0
  29. package/plugins/immune-brain/runtime/assurance/review_evidence.ts +48 -0
  30. package/plugins/immune-brain/runtime/assurance/run_continuation.ts +284 -0
  31. package/plugins/immune-brain/runtime/assurance/verdict_authority.ts +46 -4
  32. package/plugins/immune-brain/runtime/assurance/verification.ts +83 -35
  33. package/plugins/immune-brain/runtime/assurance/workflow_autocommit.ts +222 -0
  34. package/plugins/immune-brain/runtime/claude/interaction.ts +11 -2
  35. package/plugins/immune-brain/runtime/claude/kernel_ports.ts +199 -48
  36. package/plugins/immune-brain/runtime/claude/lane_guard.ts +30 -20
  37. package/plugins/immune-brain/runtime/claude/mcp_server.ts +105 -9
  38. package/plugins/immune-brain/runtime/claude/run_continuation.ts +274 -0
  39. package/plugins/immune-brain/runtime/commands/kernel.ts +41 -103
  40. package/plugins/immune-brain/runtime/github_issue_tracker.ts +60 -2
  41. package/plugins/immune-brain/runtime/kernel/application.ts +4 -1
  42. package/plugins/immune-brain/runtime/kernel/assurance_projection.ts +103 -20
  43. package/plugins/immune-brain/runtime/kernel/canary_application.ts +57 -7
  44. package/plugins/immune-brain/runtime/kernel/completion.ts +28 -4
  45. package/plugins/immune-brain/runtime/kernel/enrollment.ts +48 -8
  46. package/plugins/immune-brain/runtime/kernel/intent.ts +169 -104
  47. package/plugins/immune-brain/runtime/kernel/reducer.ts +136 -6
  48. package/plugins/immune-brain/runtime/kernel/risk_floor.ts +286 -0
  49. package/plugins/immune-brain/runtime/kernel/storage_layout_migration.ts +83 -1
  50. package/plugins/immune-brain/runtime/kernel/storage_paths.ts +1 -1
  51. package/plugins/immune-brain/runtime/kernel/types.ts +49 -3
  52. package/plugins/immune-brain/runtime/kernel/validation.ts +147 -7
  53. package/plugins/immune-brain/runtime/loop_contract.ts +5 -0
  54. package/plugins/immune-brain/runtime/plan_core.ts +15 -8
  55. package/plugins/immune-brain/runtime/plugin_source_skew.ts +58 -0
  56. package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
  57. package/plugins/immune-brain/runtime/prompts/code-review.md +26 -2
  58. package/plugins/immune-brain/runtime/prompts/executor.md +35 -10
  59. package/plugins/immune-brain/runtime/unattended/batch_delegation.ts +5 -3
  60. package/plugins/immune-brain/runtime/unattended/batch_disposition.ts +40 -10
  61. package/plugins/immune-brain/runtime/unattended/batch_final_verification.ts +57 -3
  62. package/plugins/immune-brain/runtime/unattended/batch_git.ts +424 -66
  63. package/plugins/immune-brain/runtime/unattended/batch_integration.ts +2 -1
  64. package/plugins/immune-brain/runtime/unattended/batch_kernel_port.ts +13 -0
  65. package/plugins/immune-brain/runtime/unattended/batch_lanes.ts +43 -24
  66. package/plugins/immune-brain/runtime/unattended/batch_plan.ts +6 -2
  67. package/plugins/immune-brain/runtime/unattended/batch_preflight.ts +102 -41
  68. package/plugins/immune-brain/runtime/unattended/batch_reasons.ts +9 -3
  69. package/plugins/immune-brain/runtime/unattended/batch_reconfirmation.ts +9 -9
  70. package/plugins/immune-brain/runtime/unattended/batch_runner.ts +90 -32
  71. package/plugins/immune-brain/runtime/unattended/batch_state.ts +102 -4
  72. package/plugins/immune-brain/runtime/unattended/parent_delivery_consolidation.ts +248 -0
  73. package/plugins/immune-brain/runtime/workspace_scope.ts +126 -18
  74. package/plugins/immune-brain/skills/BASELINE.md +17 -1
  75. package/plugins/immune-brain/skills/imm-brainstorm/SKILL.md +4 -3
  76. package/plugins/immune-brain/skills/imm-planner/SKILL.md +8 -2
  77. package/plugins/immune-brain/skills/imm-run/SKILL.md +12 -8
@@ -0,0 +1,398 @@
1
+ # Immune-Brain: Batch, Lane and Herdr Contract
2
+
3
+ Loaded by the `imm-run` Skill only on its batch, Lane or Herdr route. The main
4
+ Loop contract in [`imm-run.md`](imm-run.md) owns every other branch.
5
+
6
+ ## Unattended Batch Opt-In
7
+
8
+ The privileged Host tool `start_unattended_batch` executes a confirmed Initiative.
9
+ An explicit `imm-run <Parent Issue>` selects that Parent's complete published plan:
10
+ resolve its `<!-- immune-brain:initiative-id=<slug> -->` marker and call the tool
11
+ with `initiative_slug`, directly opening native Batch Authorization. Parent
12
+ selection is the batch opt-in; it needs no separate chat question. An explicit
13
+ `imm-run <Slice/Child Issue>` executes only that TaskIntent after its entrypoint
14
+ verifies predecessor settlement and Git integration. Reading Parent context
15
+ grants no authority to start predecessors or siblings. A standalone task id uses
16
+ single-task Enrollment.
17
+
18
+ Before confirmation, choose execution mode from dependency readiness, scope
19
+ conflicts, configured Lane capacity and available supervised Executor capability.
20
+ Use Lane mode up to the project limit when supervision is available; otherwise
21
+ choose Managed serial execution in this Host. Both modes record and execute the
22
+ same `final_verification` commands. A mode change after confirmation needs a fresh
23
+ native authorization. See [Parallel Batch Opt-In](#parallel-batch-opt-in).
24
+
25
+ The Initiative's carrier decides where the children are read from. When
26
+ `docs/initiatives/<initiative_slug>.md` exists, the Host reads that Local carrier
27
+ and performs no GitHub operation for the plan; otherwise it reads the GitHub
28
+ Parent Issue's native Sub-issues. A Local carrier yields one child per Slice:
29
+ each `## <slice-id>: <result>` section names exactly one Task under `Tasks:` and
30
+ may add one `Blocked by: <task-id>, <task-id>` line. A Slice that names no Task or
31
+ several, or a dependency outside the Initiative, refuses the plan before any
32
+ confirmation.
33
+
34
+ Invoking it authorizes only a user-confirmed batch of already-planned child
35
+ TaskIntents. The Host projects the batch plan from the Initiative's published
36
+ children, lists every `critical` child as a native-confirmation exception, renders
37
+ the ordinary ordered child list, final commands, budget and plan digest through
38
+ its native confirmation, and issues one Kernel Batch Authorization for ordinary
39
+ Slices. Normal successors of a critical Slice retain ordinary authorization;
40
+ the complete Parent dependency graph still prevents their execution until the
41
+ critical delivery is settled and integrated. Critical Slices consume no batch slot:
42
+ when ready, invoke single-task native Enrollment, drive their Loop, then re-enter
43
+ the Parent tool to scope-bound commit their settled delivery and resume ordinary
44
+ work. Independent branches keep progressing while one branch is blocked. The extension mints no capability and owns no
45
+ batch state transition: the shared `startBatch` driver in
46
+ `runtime/unattended/` owns every batch transition, and each child is still
47
+ enrolled, assured, and settled by the Kernel under an ordinary TaskRecord.
48
+
49
+ A `batch_lane_unreadable` observation means unknown state, not lost ownership or
50
+ completion. Read contract mismatches and escaped scope/flag details as causes,
51
+ not permission to widen scope. Revalidate the original task/run and use existing
52
+ fresh-authorization recovery before considering retirement. For provider or
53
+ Review interruptions follow [Decisions and Recovery](imm-run.md#decisions-and-recovery);
54
+ Herdr idle/done is only a session signal, never terminal Kernel proof.
55
+
56
+ A successful child Enrollment returns a `running` report with `handoff.role`
57
+ `executor`; the child remains `enrolled`. The Parent implements that TaskIntent
58
+ in the current foreground conversation, stages only its scoped changes, and
59
+ runs focused diagnostics before Kernel Assurance. Re-entering the batch before
60
+ implementation returns the same handoff without QA or another confirmation.
61
+ The runtime owns no model invocation and adds no persisted execution lifecycle.
62
+ Keep the Parent binding across child settlement, handoffs and status questions.
63
+ Continue filling dependency-ready, non-conflicting capacity; below-limit QA/Review
64
+ failures return to bounded repair in this Loop. Repeated failures use the existing
65
+ coordinator correction limits, retaining failure history and counters.
66
+
67
+ A batch `completed` flag proves only the ordinary child driver finished. Parent
68
+ success requires all necessary Slices settled with current Intent evidence,
69
+ commits integrated into the final branch, recorded final commands passing on that
70
+ exact HEAD, and all separately enrolled repairs integrated. The integration Slice
71
+ owns cross-Slice verification and repair scope before its settlement. On a later
72
+ final failure, restore a recoverable local environment and retry the recorded
73
+ commands; otherwise diagnose, author and validate the smallest repair TaskIntent
74
+ for the original goal, then open a fresh single-task native Enrollment without
75
+ chat pre-confirmation. Settled Slices retain their evidence. Track only an observed
76
+ repair run, integrate its settled delivery, and rerun final verification. Parent
77
+ Issue closure waits for this whole-plan proof; a tracker failure reports the local
78
+ proof and one synchronization recovery action.
79
+
80
+ A critical-only or delivered-only Parent starts no batch, but its first run of
81
+ caller-supplied final commands executes outside Host permission. Before any
82
+ settled-delivery commit or command runs, the current Host opens its native
83
+ confirmation listing those exact commands; a decline, cancellation or missing
84
+ gate leaves no Git or command effect. Recorded commands rerun under that earlier
85
+ confirmation, and changed commands need a fresh explicit Parent entry.
86
+
87
+ ### Consolidating settled deliveries
88
+
89
+ When several settled deliveries remain in one checkout and share generated files,
90
+ prepare one material/critical consolidation TaskIntent covering the complete final
91
+ composition, source Intent/audit inputs, and its own implementation. Preserve the
92
+ source audits and give the combined bytes fresh QA and independent Review.
93
+ After that task settles, pass `delivery_consolidation` to the same Parent tool:
94
+ `{ task_id, run_id, source_runs: [{ task_id, run_id }, ...] }`. Select exact original
95
+ Parent contributions and any standalone repair explicitly; task-name similarity
96
+ is not association. This route is for native Parents, not active ordinary batches.
97
+
98
+ The native gate discloses all selected runs, proof hashes, final delivery digest,
99
+ branch/HEAD, path/blob manifest and final commands. Acceptance authorizes one
100
+ scope-bounded final-task commit. Sources retain historical approvals; the new
101
+ Review approves the final combination. An interrupted commit leaves a pending
102
+ receipt: recover with the same selection and fresh native confirmation, verifying
103
+ the exact commit before recording contributions. Re-entry after integration uses
104
+ the verified receipt; final verification must bind that composition and current
105
+ HEAD before Parent closure. A mismatch preserves evidence and stops, not a scope
106
+ widening or permission bypass.
107
+
108
+ After diagnostics pass, the Parent advances Kernel QA and dispatches any reserved
109
+ foreground Review once using the exact returned `agent_params`, then submits its
110
+ structured verdict. An open Review reservation stays with that Host invocation;
111
+ batch re-entry waits for it rather than redispatching. When a batch child's
112
+ foreground terminal mutation reaches Kernel `done`, the same tool call stages
113
+ only that child's generated terminal audit evidence and re-enters the batch under
114
+ the still-valid authorization, opening no gate. The driver reconciles settlement,
115
+ adopts or creates the one scope-bound commit, then enrolls the next ready child
116
+ or settles the batch as `completed`; the result carries the batch report as
117
+ `batch`. A reserved Review, a parked child and a stopped child end where they do
118
+ today and are never committed automatically. If the re-entry fails, the Kernel
119
+ result is unchanged and `batch` carries one recovery action: call
120
+ `start_unattended_batch` with the same slug, which is also how to continue by
121
+ hand. A commit that fast-forwards the batch branch outside the runner is adopted,
122
+ not attributed to a child; any other HEAD movement still fails closed. Ordinary Executor handoff and below-limit
123
+ QA repair do not park the batch; genuine budget/authority stops remain fail-closed.
124
+
125
+ Batch execution never pushes a ref, opens or updates a pull request, resolves a
126
+ user decision, or creates, switches, or deletes a Git worktree. Its sole Git
127
+ effect is the batch branch `imm/<initiative-slug>` plus scope-bounded delivery
128
+ commits: one per child, or one explicitly confirmed final composition on the native
129
+ Parent consolidation route.
130
+
131
+ ### Parallel Batch Opt-In
132
+
133
+ Lane mode uses the optional `max_parallel` parameter of `start_unattended_batch`,
134
+ selected by the Parent before native confirmation; without Lane supervision the
135
+ confirmed run stays Managed serial on this Host. `max_parallel` is a positive integer; the
136
+ Standalone Hosts expose the same optional `lane_offers` list, each entry naming a
137
+ `task_id` and an absolute `path` of an already existing Git worktree. The runner
138
+ admits an offered Lane only when it shares the coordinator repository, is not the
139
+ coordinator worktree, is on the branch `imm-lane/<initiative-slug>/<task-id>` at the
140
+ named base, is clean and has no active run; otherwise it refuses the offer with a
141
+ stable reason and writes nothing. A call that passes `lane_offers` without
142
+ `max_parallel` resumes the recorded lane batch with its recorded `max_parallel`;
143
+ without a recorded active lane batch it is refused before any gate opens. The runner still never creates, switches or
144
+ deletes a Git worktree: when a child needs a Lane the report carries a
145
+ `lane-steward` handoff and the Lane is provisioned outside the runner.
146
+
147
+ In a Lane the child is enrolled, assured and settled exactly as in a serial batch.
148
+ The runner then commits the settled delivery on the Lane branch and fast-forwards
149
+ the batch branch only to a candidate whose changed paths and per-path content equal
150
+ that commit; a mismatch or conflict moves nothing and parks the child.
151
+ With `max_parallel` above 1 the reconcile tick keeps up to that many Lanes in
152
+ flight and reports one `provision` or `executor` handoff per child in `handoffs[]`.
153
+ Only children whose scopes are provably disjoint run together; a child whose scope
154
+ overlaps an in-flight Lane waits until that Lane is integrated. Settled children
155
+ integrate serially, and a parked child ends only itself and its dependents while a
156
+ disjoint sibling keeps moving. A lost Lane parks as `batch_lane_lost`, and
157
+ `qa_failure_limit` counts each child separately. A completed settlement inside a
158
+ Lane changes Kernel state only and writes nothing to the tracker: the coordinator
159
+ closes the child's Issue after it integrates that child's commit, exactly once,
160
+ and reports the attempt in `tracker_observations`. A parked or lost child is
161
+ never integrated, so its Issue stays open; an explicit stop inside a Lane still
162
+ projects `not planned` at once.
163
+
164
+ The lane batch confirmation offers one opt-in choice, off by default: delegate
165
+ to the coordinator the approval of each Lane child's breaking Intent revisions
166
+ that stay inside that child's TaskIntent as authorized for the batch (ADR 0018).
167
+ The answer is recorded on the batch record as `revision_delegation`; a batch
168
+ confirmed without it behaves exactly as before, and the grant ends with that
169
+ batch — a terminal, retired or later batch never uses it. When an integrated
170
+ child's TaskIntent equals the last revision applied under that grant, the runner
171
+ reseals `plan_digest` and records both digests in `reseals`, so later children
172
+ continue without retiring the batch. Any other Intent change still fails closed
173
+ as `plan_changed` and takes the ADR 0016 retirement path.
174
+
175
+ Before a new lane batch provisions any Lane, the runner compares the Kernel
176
+ contract identifiers (TaskRecord, tombstone, projection, store schema) of the
177
+ coordinator's runtime with those of the runtime a Lane Executor loads — never the
178
+ plugin version number — and refuses with `batch_runtime_contract_mismatch`,
179
+ naming both sources, when they differ; a match adds no confirmation. A Lane whose
180
+ state exists but whose contract the coordinator refuses to read parks as
181
+ `batch_lane_contract_mismatch` with the original parse error, distinct from a
182
+ missing Lane's `batch_lane_lost`.
183
+
184
+ Inside a Lane, the Pi extension and the Claude Code `PreToolUse` hook refuse an
185
+ `edit`/`write` (Claude: `Edit`, `Write`, `MultiEdit`, `NotebookEdit`) whose
186
+ resolved target lies outside the Lane, naming the Lane path. A shell command is
187
+ not intercepted; this is no bash sandbox. When a lane batch is re-entered with a
188
+ dirty coordinator checkout, each dirty path is restored to HEAD only if every one
189
+ of them is an unstaged modification or untracked file that a Lane of this batch
190
+ changed (its bytes differ from that Lane's base) and whose bytes equal the Lane's,
191
+ in its worktree or a Lane-branch commit. The read-only preflight only attributes;
192
+ the runner restores after the batch is authorized. The bytes are
193
+ backed up first under `.imm/state/batches/restores/`, and the backup is recorded
194
+ in the batch record and report as `restores`. If any change has another origin,
195
+ or is staged or deleted, no file is touched and the refusal names it; never
196
+ stage such changes to get past the refusal. A resume with a different
197
+ `max_parallel` is refused with `batch_parallel_mismatch`. A Lane holds no batch
198
+ state and its Host session never re-enters the batch.
199
+
200
+ #### Lane Preferences
201
+
202
+ A repository can keep standing lane-mode choices next to its other Immune-Brain
203
+ preferences. Before the first `start_unattended_batch` call for an Initiative,
204
+ the Parent resolves each of the four directives below in this order, reading the
205
+ source directly rather than assuming the Host injected it into context:
206
+
207
+ 1. a literal user instruction for the current request;
208
+ 2. the directive in the repository root agent instruction file, whichever this
209
+ repository tracks: `AGENTS.md` or `CLAUDE.md`;
210
+ 3. the same directive in the Host's user-level agent instruction file; or
211
+ 4. the behavior without a directive, given in the table.
212
+
213
+ | Directive | Value | Effect | Without it |
214
+ | --- | --- | --- | --- |
215
+ | `Lane max parallel: <n>` | positive integer | The Parent passes it as `max_parallel` when it starts a batch, which selects lane mode. The native confirmation still shows it. | No `max_parallel`: the batch is serial unless the user asks otherwise |
216
+ | `Lane Executor Host: <host>` | `claude-code` or `pi` | Every Lane's Executor Host is that Host. When the `lane-steward` did not report it available in a Lane, that Lane has no Executor Host; the Parent does not fall back to the other one. | The Parent's own Host type, else the other allowlisted Host |
217
+ | `Lane Executor model: <model>` | a model identifier of the configured Executor Host | Passed to the Executor Host as `--model <model>` | The Executor Host's own default |
218
+ | `Lane Executor effort: <level>` | a level the configured Executor Host accepts | Passed as `--effort <level>` to `claude-code` and as `--thinking <level>` to `pi` | The Executor Host's own default |
219
+ | `Batch final verification: <command>; <command>` | plain commands without shell syntax or quoting, at most 8 | Passed as `final_verification` when a new lane batch starts and shown in its native confirmation; the runner runs them on the batch branch once every child is integrated and writes each command's exit status and timing into the completion report as `final_verification`. A failing command reports the batch as not passed; integrated commits are never rolled back | The commands the repository instruction file names for its full test suite and type check, else none and the completion report says nothing was run |
220
+
221
+ A model identifier and an effort level mean something only to one Host, so
222
+ `Lane Executor model` and `Lane Executor effort` apply only together with
223
+ `Lane Executor Host` from the same or a higher source; without it they are
224
+ reported and not applied. A repository directive overrides the user-level one.
225
+ Report an invalid value and ask instead of guessing or clamping. After resolving
226
+ them, display one non-blocking line with each selected value and its source. On
227
+ a resume the recorded `max_parallel` stands and the directive is not passed
228
+ again. The directives configure how the Parent starts sessions; the runner reads
229
+ none of them, and they grant no permission or trust option.
230
+
231
+ A repository that names its full test and type-check commands in prose (for
232
+ example "uses `bun test`; type checking is `bun run typecheck`") supplies them as
233
+ the final verification without a directive; the Parent never invents a command
234
+ the repository does not name.
235
+
236
+ #### Lane Executor Supervision
237
+
238
+ The Parent launches and supervises every Lane's Executor Host; no other role
239
+ starts one. This is the one case in which the Parent starts another Loop
240
+ process, and it starts it only in an admitted Lane. For each `executor` handoff
241
+ whose Lane has no live session of its own, the Parent starts exactly one
242
+ **supervised session** and keeps its handle. Handoffs of one report start
243
+ together; a Lane never has two sessions.
244
+
245
+ A supervised session is defined by what it guarantees, not by a Host's name:
246
+
247
+ - It is a separate Host process whose working directory is the Lane, so its
248
+ Kernel root is the Lane's own Authority Store. A subagent that runs inside the
249
+ Parent's process shares the Parent's root and is never a Lane Executor.
250
+ - It is given one explicit `imm-run` entry for that `task_id`, and nothing else.
251
+ - When it stops working — it exits, or it settles waiting for input — control
252
+ returns to the Parent without the Parent polling or sleeping.
253
+ - The Parent can stop it.
254
+
255
+ The Parent Host and the Executor Host are chosen independently. The Executor
256
+ Host is any allowlisted Host (`claude-code` or `pi`) that the `lane-steward`
257
+ reported available in that Lane. A `Lane Executor Host` directive under
258
+ [Lane Preferences](#lane-preferences) decides it; without one, prefer the
259
+ Parent's own Host type, and use the other when only it is available. The child's QA and Review then run under that
260
+ Executor Host's own Assurance adapter in the Lane. The Executor Host loads the
261
+ same Immune-Brain plugin or package the Parent runs: a Parent started from a
262
+ local plugin directory passes that same directory to the Executor Host. The
263
+ Parent adds no permission or trust option of its own; the Executor Host runs
264
+ under the user's own settings, with the model and effort of its own defaults
265
+ unless Lane Preferences name them. How the Parent obtains a supervised session
266
+ depends on where the Parent runs; the first matching row applies, and the user
267
+ is not asked to choose:
268
+
269
+ | Parent Host | Supervised session | Stop |
270
+ | --- | --- | --- |
271
+ | Either Host, inside Herdr (`HERDR_ENV=1`) | One Herdr tab per Lane holding an interactive Executor Host, under [Herdr Lane Tabs](#herdr-lane-tabs) | Close the tab the Parent created |
272
+ | Claude Code | The Host's background command execution, running the Executor Host's non-interactive entry in the Lane; its completion notice re-invokes the Parent. The `Agent` tool does not qualify. | The Host's own stop for that background task |
273
+ | Pi | A background process facility from the Pi user's own configuration that notifies the Parent on exit. Pi ships none that Immune-Brain may assume. | That facility's own stop |
274
+ | Any Host without one | None. The Parent launches nothing. | — |
275
+
276
+ When the Parent Host offers no supervised session, or no allowlisted Executor
277
+ Host is available in the Lane, the Parent does not substitute a detached job, an
278
+ in-process subagent or serial in-place work. It reports each `executor` handoff
279
+ to the user with the Lane path, `task_id` and the `imm-run` entry to start
280
+ there, and calls `start_unattended_batch` again when the user says a Lane has
281
+ finished. Supervision is per Lane: Lanes that can be supervised are, and the
282
+ rest are reported.
283
+
284
+ ##### Herdr Lane Tabs
285
+
286
+ Inside Herdr the Parent drives the `herdr` CLI itself; the runtime and the
287
+ `lane-steward` never do. Each Lane gets a tab of its own, so its Executor Host
288
+ has a full-size terminal the user can read. For each `executor` handoff without
289
+ a live tab:
290
+
291
+ 1. Take the Lane from the handoff's `lane_path`. Pick the Executor Host as above;
292
+ `claude-code` is Herdr kind `claude` and `pi` is kind `pi`.
293
+ 2. Create the tab without taking focus, in the Parent's own workspace and rooted
294
+ in the Lane:
295
+ `herdr tab create --workspace "$HERDR_WORKSPACE_ID" --cwd <lane_path> --label <name> --no-focus`.
296
+ Without `--workspace` the tab lands in whichever workspace has focus. `<name>`
297
+ is a label of at most 32 characters such as the Slice ID; a `task_id` is
298
+ usually too long. Read `tab.tab_id` and `root_pane.pane_id` from the JSON
299
+ result and keep `task_id → tab_id, pane_id`: the pane ID addresses the
300
+ session, the tab ID closes it.
301
+ 3. Start the Host in that tab's root pane:
302
+ `herdr agent start <name> --kind <kind> --pane <pane_id> -- <host arguments>`.
303
+ Host arguments are only those that load the Parent's plugin and those that
304
+ [Lane Preferences](#lane-preferences) resolved for model and effort.
305
+ 4. Submit the entry and nothing else (later text follows only the instruction
306
+ rule below), and confirm the turn began:
307
+ `herdr agent prompt <pane_id> "<imm-run entry> <task_id>" --wait --until working --until blocked --timeout 30000`.
308
+ The entry is the Executor Host's own `imm-run` invocation as that Host names
309
+ it: a Claude Code Host that loaded the plugin from a directory names it
310
+ `/immune-brain:imm-run`.
311
+ 5. Supervise with `herdr agent wait <pane_id>` as a Host background command, so
312
+ its return re-invokes the Parent. Start it only after step 4 reported
313
+ `working`: a wait attached to a still-`idle` session returns at once. Do not
314
+ loop on `herdr agent get` or read the pane to judge progress.
315
+
316
+ `agent_not_ready` from step 3, or a `blocked` state at any time, means the tab
317
+ shows a dialog only the user may answer: workspace trust, sign-in, a permission
318
+ request, a question, or a native confirmation such as an Intent revision gate.
319
+ The Parent sends that tab no keys and no prompt, and never answers such a dialog
320
+ for the user. As soon as the wait returns `blocked` it tells the user which tab
321
+ and `task_id` is waiting and what the dialog asks, without waiting to be asked,
322
+ leaves the tab open, and continues the other Lanes; once the user has answered, step 3's tab is resumed
323
+ from step 4 if the entry was never submitted, otherwise from step 5. `idle` or
324
+ `done` is a session end for the rules below, although the tab stays open: the
325
+ Parent calls `start_unattended_batch`, and a relaunch submits the entry again in
326
+ the same tab instead of creating another. When that report shows the child
327
+ neither settled nor waiting on a user decision, the Parent tells the user which
328
+ tab and `task_id` went idle and what the Kernel projection still requires.
329
+
330
+ The Parent may send one text instruction to a Lane session, and only while it is
331
+ `idle` and its child is still running in the Lane: a correction to the
332
+ Executor's approach, never an answer to a dialog. It first calls
333
+ `start_unattended_batch` with `lane_instruction` (`task_id`, `text`, `kind`
334
+ `instruction` or `correction`, and the `session_state` it just observed with
335
+ `herdr agent get`). The runner records the text in the batch record and report
336
+ as `interventions` and answers `lane_instruction.accepted`; only when accepted
337
+ does the Parent submit it with `herdr agent prompt <pane_id> "<text>" --wait
338
+ --until working --until blocked --timeout 30000` and re-arm step 5. A `blocked`
339
+ or `working` session is refused and receives nothing. Every instruction the
340
+ coordinator sent is therefore in the report, so Executor-initiated behavior and
341
+ coordinator intervention can be told apart afterwards. This never applies to a
342
+ Review agent: a dispatched reviewer is still never continued or re-prompted.
343
+
344
+ When a Lane child exhausts its rework budget (the per-child `qa_failure_limit`)
345
+ it does not park for the user at once: the report carries a
346
+ `{ role: "coordinator", action: "correct" }` handoff and the runner makes no
347
+ further attempt for that child. The Parent reads the findings of every round
348
+ from that Lane's Kernel state, decides whether they point at one root cause, and
349
+ writes one design-level correction — the invariant to hold and the shared seam to
350
+ fix — never a patch of its own. It starts a new Executor session in the Lane
351
+ (the old context is not reused; the new session resumes from the Kernel
352
+ projection and the Lane workspace alone) and sends the correction as
353
+ `lane_instruction` kind `correction`; the runner counts it. At most two
354
+ corrections are spent per child: the third exhaustion parks the child as
355
+ `batch_correction_limit_reached`, its dependents are skipped, siblings that do not
356
+ depend on it keep executing and integrating, and the batch reports it at the end.
357
+ Single tasks outside a batch keep their existing budget behavior, and Review
358
+ independence is unchanged. A Review rework budget that the Kernel turns into a
359
+ `replan_required` decision still needs the user's own native decision.
360
+
361
+ Every live Lane session keeps exactly one `herdr agent wait` armed, so `blocked`
362
+ and idle-without-settlement wake the Parent on their own; a Parent that has
363
+ nothing else to do still ends its turn with those waits armed. A failed or timed-out `herdr` command
364
+ proves nothing about delivery; inspect the session's state before repeating it.
365
+
366
+ The Parent only creates: it closes no tab, including the tabs it created, and
367
+ every tab stays open for the user to read and close. It splits no pane and
368
+ creates no workspace. Outside Herdr the Parent never invokes `herdr`.
369
+
370
+ Supervision is event-driven. Each session end is the cue to call
371
+ `start_unattended_batch` again with the same Initiative, and that report is the
372
+ only progress signal: a child's state and `next_obligation` come from its Lane's
373
+ Kernel projection, never from the session's output or exit status. When the
374
+ report still carries an `executor` handoff for a child whose session has ended,
375
+ the Parent starts it once more; after a second end without Kernel progress, or
376
+ when the report shows the child waiting on a user decision or an open Review
377
+ reservation, it stops relaunching and reports that child to the user while its
378
+ siblings continue. The Parent stops no session: when the report shows a child
379
+ parked or settled while its session is still working, the Parent tells the user
380
+ which tab and `task_id` to close. A session that stays open changes no Kernel
381
+ or batch state, so the next report states what remains. Handles are not
382
+ authority: after an interruption
383
+ the Parent calls `start_unattended_batch` first and launches only for the
384
+ handoffs it returns.
385
+
386
+ After a child is integrated, its Lane is clean and its `.imm/audit/<task-id>/`
387
+ pair is reachable from the batch branch, the report carries a
388
+ `{ role: "lane-steward", action: "release" }` handoff for that Lane. A parked,
389
+ failed, dirty or unintegrated Lane, or one whose audit pair is not on the batch
390
+ branch, is never offered for release. The runner removes no worktree and deletes
391
+ no branch: it records the child `released` only when a later tick observes the
392
+ Lane path gone, and a Lane that is still present stays `integrated` while the
393
+ batch still completes. The `lane-steward` internal role handles a `provision`
394
+ handoff; it follows the project's own instructions to prepare a Lane, starts no
395
+ Host session, and reports "cannot supply" rather than improvising. A `release`
396
+ handoff is the user's to carry out: the Parent removes no Lane and dispatches no
397
+ one to remove it. It reports each such Lane once, with its `task_id`, Lane path
398
+ and tab, as ready for the user to close and remove.