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.
- package/README.md +4 -4
- package/README.zh-CN.md +4 -4
- package/package.json +2 -1
- package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
- package/plugins/immune-brain/.pi-extension/imm-canary-enroll.ts +54 -70
- package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +163 -28
- package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +71 -10
- package/plugins/immune-brain/.pi-extension/pi-canary-tool-failure.ts +1 -1
- package/plugins/immune-brain/.pi-extension/pi-run-continuation.ts +161 -0
- package/plugins/immune-brain/agents/immune-brain-reviewer.md +26 -2
- package/plugins/immune-brain/dist/BASELINE.md +17 -1
- package/plugins/immune-brain/dist/claude/mcp-server.mjs +16145 -12745
- package/plugins/immune-brain/dist/docs/reference/code-quality-guard.md +3 -1
- package/plugins/immune-brain/dist/docs/reference/immune-brain-config.md +41 -1
- package/plugins/immune-brain/dist/docs/reference/planning-quality-gate.md +1 -1
- package/plugins/immune-brain/dist/imm-brainstorm.md +1 -1
- package/plugins/immune-brain/dist/imm-planner.md +63 -19
- package/plugins/immune-brain/dist/imm-run-batch.md +398 -0
- package/plugins/immune-brain/dist/imm-run.md +89 -344
- package/plugins/immune-brain/dist/role-prompts/code-review.md +26 -2
- package/plugins/immune-brain/dist/role-prompts/executor.md +35 -10
- package/plugins/immune-brain/hooks/hooks.json +22 -2
- package/plugins/immune-brain/runtime/assurance/coordinator.ts +203 -13
- package/plugins/immune-brain/runtime/assurance/delivery_workspace.ts +2 -1
- package/plugins/immune-brain/runtime/assurance/enrollment_git_base.ts +99 -14
- package/plugins/immune-brain/runtime/assurance/phase_entry.ts +10 -26
- package/plugins/immune-brain/runtime/assurance/qa.ts +126 -43
- package/plugins/immune-brain/runtime/assurance/qa_findings.ts +8 -0
- package/plugins/immune-brain/runtime/assurance/review_evidence.ts +48 -0
- package/plugins/immune-brain/runtime/assurance/run_continuation.ts +284 -0
- package/plugins/immune-brain/runtime/assurance/verdict_authority.ts +46 -4
- package/plugins/immune-brain/runtime/assurance/verification.ts +83 -35
- package/plugins/immune-brain/runtime/assurance/workflow_autocommit.ts +222 -0
- package/plugins/immune-brain/runtime/claude/interaction.ts +11 -2
- package/plugins/immune-brain/runtime/claude/kernel_ports.ts +199 -48
- package/plugins/immune-brain/runtime/claude/lane_guard.ts +30 -20
- package/plugins/immune-brain/runtime/claude/mcp_server.ts +105 -9
- package/plugins/immune-brain/runtime/claude/run_continuation.ts +274 -0
- package/plugins/immune-brain/runtime/commands/kernel.ts +41 -103
- package/plugins/immune-brain/runtime/github_issue_tracker.ts +60 -2
- package/plugins/immune-brain/runtime/kernel/application.ts +4 -1
- package/plugins/immune-brain/runtime/kernel/assurance_projection.ts +103 -20
- package/plugins/immune-brain/runtime/kernel/canary_application.ts +57 -7
- package/plugins/immune-brain/runtime/kernel/completion.ts +28 -4
- package/plugins/immune-brain/runtime/kernel/enrollment.ts +48 -8
- package/plugins/immune-brain/runtime/kernel/intent.ts +169 -104
- package/plugins/immune-brain/runtime/kernel/reducer.ts +136 -6
- package/plugins/immune-brain/runtime/kernel/risk_floor.ts +286 -0
- package/plugins/immune-brain/runtime/kernel/storage_layout_migration.ts +83 -1
- package/plugins/immune-brain/runtime/kernel/storage_paths.ts +1 -1
- package/plugins/immune-brain/runtime/kernel/types.ts +49 -3
- package/plugins/immune-brain/runtime/kernel/validation.ts +147 -7
- package/plugins/immune-brain/runtime/loop_contract.ts +5 -0
- package/plugins/immune-brain/runtime/plan_core.ts +15 -8
- package/plugins/immune-brain/runtime/plugin_source_skew.ts +58 -0
- package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
- package/plugins/immune-brain/runtime/prompts/code-review.md +26 -2
- package/plugins/immune-brain/runtime/prompts/executor.md +35 -10
- package/plugins/immune-brain/runtime/unattended/batch_delegation.ts +5 -3
- package/plugins/immune-brain/runtime/unattended/batch_disposition.ts +40 -10
- package/plugins/immune-brain/runtime/unattended/batch_final_verification.ts +57 -3
- package/plugins/immune-brain/runtime/unattended/batch_git.ts +424 -66
- package/plugins/immune-brain/runtime/unattended/batch_integration.ts +2 -1
- package/plugins/immune-brain/runtime/unattended/batch_kernel_port.ts +13 -0
- package/plugins/immune-brain/runtime/unattended/batch_lanes.ts +43 -24
- package/plugins/immune-brain/runtime/unattended/batch_plan.ts +6 -2
- package/plugins/immune-brain/runtime/unattended/batch_preflight.ts +102 -41
- package/plugins/immune-brain/runtime/unattended/batch_reasons.ts +9 -3
- package/plugins/immune-brain/runtime/unattended/batch_reconfirmation.ts +9 -9
- package/plugins/immune-brain/runtime/unattended/batch_runner.ts +90 -32
- package/plugins/immune-brain/runtime/unattended/batch_state.ts +102 -4
- package/plugins/immune-brain/runtime/unattended/parent_delivery_consolidation.ts +248 -0
- package/plugins/immune-brain/runtime/workspace_scope.ts +126 -18
- package/plugins/immune-brain/skills/BASELINE.md +17 -1
- package/plugins/immune-brain/skills/imm-brainstorm/SKILL.md +4 -3
- package/plugins/immune-brain/skills/imm-planner/SKILL.md +8 -2
- 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.
|