immune-brain 3.4.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/README.zh-CN.md +3 -3
- package/package.json +1 -1
- package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
- package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +87 -97
- package/plugins/immune-brain/.pi-extension/pi-canary-interaction.ts +144 -11
- package/plugins/immune-brain/.pi-extension/pi-canary-native-review.ts +2 -2
- package/plugins/immune-brain/dist/claude/mcp-server.mjs +102 -53
- package/plugins/immune-brain/dist/docs/reference/immune-brain-config.md +17 -8
- package/plugins/immune-brain/dist/imm-loop.md +134 -150
- package/plugins/immune-brain/dist/imm-planner.md +71 -77
- package/plugins/immune-brain/runtime/assurance/coordinator.ts +26 -6
- package/plugins/immune-brain/runtime/assurance/qa.ts +85 -0
- package/plugins/immune-brain/runtime/claude/kernel_ports.ts +1 -45
- package/plugins/immune-brain/runtime/kernel/intent.ts +7 -2
- package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
|
@@ -42,7 +42,7 @@ function probeHost(env = process.env, platform = process.platform, hostVersion)
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// plugins/immune-brain/runtime/plugin_version.ts
|
|
45
|
-
var PLUGIN_VERSION = "3.
|
|
45
|
+
var PLUGIN_VERSION = "3.6.0";
|
|
46
46
|
|
|
47
47
|
// plugins/immune-brain/runtime/claude/interaction.ts
|
|
48
48
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -1275,8 +1275,6 @@ class AssuranceCoordinator {
|
|
|
1275
1275
|
this.rejectedReviewOperations.delete(taskId);
|
|
1276
1276
|
}
|
|
1277
1277
|
const refreshed = this.active(taskId);
|
|
1278
|
-
if (refreshed?.state === "settlement_unknown")
|
|
1279
|
-
return refreshed;
|
|
1280
1278
|
if (refreshed?.state === "running")
|
|
1281
1279
|
return { state: "blocked", reason: `assurance operation ${refreshed.operation_id} is already running` };
|
|
1282
1280
|
const operationId = randomUUID2();
|
|
@@ -1308,18 +1306,30 @@ class AssuranceCoordinator {
|
|
|
1308
1306
|
progress(phase, `Preparing deterministic QA for ${taskId}`);
|
|
1309
1307
|
await this.ports.advanceBeforeProjection?.();
|
|
1310
1308
|
ensureOperationLive();
|
|
1311
|
-
let projection
|
|
1309
|
+
let projection;
|
|
1310
|
+
try {
|
|
1311
|
+
projection = await this.ports.projectTask(ctx.cwd, taskId);
|
|
1312
|
+
} catch (error) {
|
|
1313
|
+
if (!(error instanceof Error) || !("code" in error) || !["EINTR", "EAGAIN"].includes(String(error.code)))
|
|
1314
|
+
throw error;
|
|
1315
|
+
ensureOperationLive();
|
|
1316
|
+
progress("retrying_projection", "Retrying the initial authority read once; no writes replayed", { retry_attempt: 1 });
|
|
1317
|
+
ensureOperationLive();
|
|
1318
|
+
projection = await this.ports.projectTask(ctx.cwd, taskId);
|
|
1319
|
+
}
|
|
1312
1320
|
ensureOperationLive();
|
|
1313
1321
|
if (projection.error)
|
|
1314
1322
|
return { state: "blocked", reason: projection.error };
|
|
1315
|
-
if (projection.projection.lifecycle === "done")
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1323
|
+
if (projection.projection.lifecycle === "done" || projection.projection.lifecycle === "stopped") {
|
|
1324
|
+
this.unknownOperations.delete(taskId);
|
|
1325
|
+
return { state: projection.projection.lifecycle === "done" ? "completed" : "stopped" };
|
|
1326
|
+
}
|
|
1319
1327
|
if (!projection.claim)
|
|
1320
1328
|
return { state: "blocked", reason: "no active backend claim" };
|
|
1321
1329
|
if (projection.claim.task_id !== taskId)
|
|
1322
1330
|
return { state: "blocked", reason: `backend claim belongs to ${projection.claim.task_id}, not ${taskId}` };
|
|
1331
|
+
if (projection.projection.lifecycle === "active")
|
|
1332
|
+
this.unknownOperations.delete(taskId);
|
|
1323
1333
|
const parked = await this.ports.readTaskRecord(ctx.cwd, taskId);
|
|
1324
1334
|
ensureOperationLive();
|
|
1325
1335
|
if (parked.record?.findings.some((finding) => finding.kind === "replan_required" && finding.status === "open"))
|
|
@@ -1380,7 +1390,13 @@ class AssuranceCoordinator {
|
|
|
1380
1390
|
ensureOperationLive();
|
|
1381
1391
|
qaVerdict = await this.ports.runQa(assurance.snapshot, assurance.descriptors, runner, {
|
|
1382
1392
|
signal: operationController.signal,
|
|
1383
|
-
onProgress: (item) => progress("verifying", `QA ${item.index}/${item.total} ${item.acceptance_id} ${item.phase}`, {
|
|
1393
|
+
onProgress: (item) => progress("verifying", `QA ${item.index}/${item.total} ${item.acceptance_id} ${item.phase}`, {
|
|
1394
|
+
current: item.index,
|
|
1395
|
+
total: item.total,
|
|
1396
|
+
acceptance_id: item.acceptance_id,
|
|
1397
|
+
acceptance_phase: item.phase,
|
|
1398
|
+
elapsed_ms: item.elapsed_ms
|
|
1399
|
+
})
|
|
1384
1400
|
});
|
|
1385
1401
|
ensureOperationLive();
|
|
1386
1402
|
const invocation = this.openInvocation(taskId);
|
|
@@ -1527,10 +1543,8 @@ class AssuranceCoordinator {
|
|
|
1527
1543
|
}
|
|
1528
1544
|
async submitReview(taskId, ctx, verdictInput) {
|
|
1529
1545
|
const unknown = this.unknownOperations.get(taskId);
|
|
1530
|
-
if (unknown)
|
|
1531
|
-
this.unknownOperations.delete(taskId);
|
|
1546
|
+
if (unknown)
|
|
1532
1547
|
return { state: "settlement_unknown", operation: unknown.operation, operation_id: unknown.operationId, reason: unknown.reason };
|
|
1533
|
-
}
|
|
1534
1548
|
const rejected = this.rejectedReviewOperations.get(taskId);
|
|
1535
1549
|
if (rejected)
|
|
1536
1550
|
return { state: "blocked", reason: rejected.reason };
|
|
@@ -2657,11 +2671,16 @@ var INTENT_SIDECAR_RELATIVE_PREFIX = "docs/plans/";
|
|
|
2657
2671
|
var RISK_FLOOR_SCOPE_PREFIXES = [
|
|
2658
2672
|
"plugins/immune-brain/runtime/kernel",
|
|
2659
2673
|
"plugins/immune-brain/runtime/authority_commit_receipts.ts",
|
|
2674
|
+
"plugins/immune-brain/runtime/assurance",
|
|
2675
|
+
"plugins/immune-brain/runtime/claude/interaction.ts",
|
|
2676
|
+
"plugins/immune-brain/runtime/claude/capability.ts",
|
|
2677
|
+
"plugins/immune-brain/runtime/claude/review_host.ts",
|
|
2678
|
+
"plugins/immune-brain/runtime/claude/kernel_ports.ts",
|
|
2679
|
+
"plugins/immune-brain/runtime/claude/mcp_server.ts",
|
|
2660
2680
|
"plugins/immune-brain/.pi-extension"
|
|
2661
2681
|
];
|
|
2662
2682
|
var CHANGED_PATH_RISK_FLOOR_PREFIXES = [
|
|
2663
|
-
|
|
2664
|
-
"plugins/immune-brain/.pi-extension",
|
|
2683
|
+
...RISK_FLOOR_SCOPE_PREFIXES,
|
|
2665
2684
|
"docs/specs",
|
|
2666
2685
|
"docs/plans"
|
|
2667
2686
|
];
|
|
@@ -6372,6 +6391,75 @@ function attemptRef(snapshotDigest2) {
|
|
|
6372
6391
|
return `${digest8}-${randomUUID4().slice(0, 6)}`;
|
|
6373
6392
|
}
|
|
6374
6393
|
|
|
6394
|
+
// plugins/immune-brain/runtime/assurance/qa.ts
|
|
6395
|
+
async function runDeterministicQa(snapshot, descriptors, runner, options = {}) {
|
|
6396
|
+
if (snapshot.role !== "qa")
|
|
6397
|
+
throw new Error("deterministic QA requires qa role");
|
|
6398
|
+
if (options.signal?.aborted)
|
|
6399
|
+
throw new VerificationAbortedError;
|
|
6400
|
+
const findings = [];
|
|
6401
|
+
const runVerification = options.runVerification ?? runFixedVerification;
|
|
6402
|
+
for (const [offset, item] of snapshot.acceptance.entries()) {
|
|
6403
|
+
if (options.signal?.aborted)
|
|
6404
|
+
throw new VerificationAbortedError;
|
|
6405
|
+
const descriptor = descriptors.get(item.id);
|
|
6406
|
+
if (!descriptor)
|
|
6407
|
+
throw new Error(`verification descriptor missing for ${item.id}`);
|
|
6408
|
+
const startedAt = Date.now();
|
|
6409
|
+
options.onProgress?.({
|
|
6410
|
+
index: offset + 1,
|
|
6411
|
+
total: snapshot.acceptance.length,
|
|
6412
|
+
acceptance_id: item.id,
|
|
6413
|
+
phase: "running",
|
|
6414
|
+
elapsed_ms: 0
|
|
6415
|
+
});
|
|
6416
|
+
const result = await runVerification(snapshot.root, descriptor, runner, {
|
|
6417
|
+
signal: options.signal
|
|
6418
|
+
});
|
|
6419
|
+
if (options.signal?.aborted)
|
|
6420
|
+
throw new VerificationAbortedError;
|
|
6421
|
+
const failed = result.exit_code !== 0 || result.timed_out;
|
|
6422
|
+
options.onProgress?.({
|
|
6423
|
+
index: offset + 1,
|
|
6424
|
+
total: snapshot.acceptance.length,
|
|
6425
|
+
acceptance_id: item.id,
|
|
6426
|
+
phase: failed ? "failed" : "passed",
|
|
6427
|
+
elapsed_ms: Date.now() - startedAt
|
|
6428
|
+
});
|
|
6429
|
+
if (failed) {
|
|
6430
|
+
findings.push({
|
|
6431
|
+
id: qaFindingId(item.id, snapshotDigest(snapshot)),
|
|
6432
|
+
kind: "blocking",
|
|
6433
|
+
acceptance_id: item.id,
|
|
6434
|
+
summary: `verification failed (exit ${result.exit_code}${result.timed_out ? ", timed out" : ""}) stdout=${Buffer.byteLength(result.stdout)}B stderr=${Buffer.byteLength(result.stderr)}B`,
|
|
6435
|
+
findings_digest: ""
|
|
6436
|
+
});
|
|
6437
|
+
}
|
|
6438
|
+
}
|
|
6439
|
+
if (findings.length > 0) {
|
|
6440
|
+
return {
|
|
6441
|
+
contract: "assurance_kernel/assurance_verdict/v2",
|
|
6442
|
+
role: "qa",
|
|
6443
|
+
task_id: snapshot.task_id,
|
|
6444
|
+
snapshot_digest: snapshotDigest(snapshot),
|
|
6445
|
+
decision: "rework",
|
|
6446
|
+
findings
|
|
6447
|
+
};
|
|
6448
|
+
}
|
|
6449
|
+
return {
|
|
6450
|
+
contract: "assurance_kernel/assurance_verdict/v2",
|
|
6451
|
+
role: "qa",
|
|
6452
|
+
task_id: snapshot.task_id,
|
|
6453
|
+
snapshot_digest: snapshotDigest(snapshot),
|
|
6454
|
+
decision: "pass",
|
|
6455
|
+
approval: {
|
|
6456
|
+
kind: "qa",
|
|
6457
|
+
authority_role: "qa",
|
|
6458
|
+
summary: `all ${snapshot.acceptance.length} fixed verification descriptor(s) passed`
|
|
6459
|
+
}
|
|
6460
|
+
};
|
|
6461
|
+
}
|
|
6462
|
+
|
|
6375
6463
|
// plugins/immune-brain/runtime/claude/kernel_ports.ts
|
|
6376
6464
|
function diffSnapshotOf(root, record) {
|
|
6377
6465
|
if (record.contract === "assurance_kernel/task_record/v4") {
|
|
@@ -6436,45 +6524,6 @@ function assertProjectionBinding(before, after, allowDiffChange = false) {
|
|
|
6436
6524
|
throw new Error("Task changed after native confirmation; authority aborted before capability issuance");
|
|
6437
6525
|
}
|
|
6438
6526
|
}
|
|
6439
|
-
async function runDeterministicQa(snapshot, descriptors, runner, options = {}) {
|
|
6440
|
-
if (snapshot.role !== "qa")
|
|
6441
|
-
throw new Error("deterministic QA requires qa role");
|
|
6442
|
-
if (options.signal?.aborted)
|
|
6443
|
-
throw new VerificationAbortedError;
|
|
6444
|
-
const findings = [];
|
|
6445
|
-
for (const [offset, item] of snapshot.acceptance.entries()) {
|
|
6446
|
-
if (options.signal?.aborted)
|
|
6447
|
-
throw new VerificationAbortedError;
|
|
6448
|
-
const descriptor = descriptors.get(item.id);
|
|
6449
|
-
if (!descriptor)
|
|
6450
|
-
throw new Error(`verification descriptor missing for ${item.id}`);
|
|
6451
|
-
const startedAt = Date.now();
|
|
6452
|
-
options.onProgress?.({ index: offset + 1, total: snapshot.acceptance.length, acceptance_id: item.id, phase: "running", elapsed_ms: 0 });
|
|
6453
|
-
const result = await runFixedVerification(snapshot.root, descriptor, runner, { signal: options.signal });
|
|
6454
|
-
const failed = result.exit_code !== 0 || result.timed_out;
|
|
6455
|
-
options.onProgress?.({ index: offset + 1, total: snapshot.acceptance.length, acceptance_id: item.id, phase: failed ? "failed" : "passed", elapsed_ms: Date.now() - startedAt });
|
|
6456
|
-
if (failed) {
|
|
6457
|
-
findings.push({
|
|
6458
|
-
id: qaFindingId(item.id, snapshotDigest(snapshot)),
|
|
6459
|
-
kind: "blocking",
|
|
6460
|
-
acceptance_id: item.id,
|
|
6461
|
-
summary: `verification failed (exit ${result.exit_code}${result.timed_out ? ", timed out" : ""})`,
|
|
6462
|
-
findings_digest: ""
|
|
6463
|
-
});
|
|
6464
|
-
}
|
|
6465
|
-
}
|
|
6466
|
-
if (findings.length > 0) {
|
|
6467
|
-
return { contract: "assurance_kernel/assurance_verdict/v2", role: "qa", task_id: snapshot.task_id, snapshot_digest: snapshotDigest(snapshot), decision: "rework", findings };
|
|
6468
|
-
}
|
|
6469
|
-
return {
|
|
6470
|
-
contract: "assurance_kernel/assurance_verdict/v2",
|
|
6471
|
-
role: "qa",
|
|
6472
|
-
task_id: snapshot.task_id,
|
|
6473
|
-
snapshot_digest: snapshotDigest(snapshot),
|
|
6474
|
-
decision: "pass",
|
|
6475
|
-
approval: { kind: "qa", authority_role: "qa", summary: `all ${snapshot.acceptance.length} fixed verification descriptor(s) passed` }
|
|
6476
|
-
};
|
|
6477
|
-
}
|
|
6478
6527
|
function qaOutcomes(record) {
|
|
6479
6528
|
return Object.fromEntries(record.attestations.filter((item) => item.kind === "qa").flatMap((item) => item.acceptance_results).map((result) => [result.acceptance_id, { status: result.status, summary: result.summary }]));
|
|
6480
6529
|
}
|
|
@@ -1,25 +1,34 @@
|
|
|
1
|
-
# Immune-Brain
|
|
1
|
+
# Immune-Brain Host Preferences
|
|
2
2
|
|
|
3
3
|
Pi and Claude Code are supported code-agent hosts. Immune-Brain does not load an
|
|
4
4
|
agent-local TOML file or Immune-Brain-specific environment overrides. User and
|
|
5
|
-
project preferences belong in
|
|
5
|
+
project preferences belong in the Host's agent instruction files.
|
|
6
6
|
|
|
7
7
|
## Precedence
|
|
8
8
|
|
|
9
9
|
Planner preferences resolve in this order:
|
|
10
10
|
|
|
11
11
|
1. a literal instruction in the current request;
|
|
12
|
-
2. the repository root
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
2. the repository root agent instruction file, whichever the repository tracks:
|
|
13
|
+
`AGENTS.md` or `CLAUDE.md`;
|
|
14
|
+
3. the Host's user-level agent instruction file; or
|
|
15
|
+
4. an explicit user question.
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
Hosts differ in which files they auto-load: Pi injects `AGENTS.md`, while Claude
|
|
18
|
+
Code auto-loads `CLAUDE.md` and does not read `~/.pi/agent/AGENTS.md` at all. A
|
|
19
|
+
Skill therefore reads sources 2 and 3 directly instead of assuming the Host
|
|
20
|
+
placed them in context, and reports which sources it checked.
|
|
21
|
+
|
|
22
|
+
Invalid values are reported rather than guessed. A preference with no documented
|
|
23
|
+
default resolves to a user question, never to a silently chosen value.
|
|
17
24
|
|
|
18
25
|
## Initiative Carrier
|
|
19
26
|
|
|
20
27
|
The Initiative carrier preference applies only to proposals split across
|
|
21
28
|
multiple TaskIntents. Ordinary TaskIntents remain tracked by Kernel
|
|
22
|
-
TaskRecords.
|
|
29
|
+
TaskRecords. There is no built-in carrier default; when no directive is found,
|
|
30
|
+
Planner asks. Set one of these fixed directives in the repository root
|
|
31
|
+
`AGENTS.md` or `CLAUDE.md`:
|
|
23
32
|
|
|
24
33
|
```md
|
|
25
34
|
## Immune-Brain Preferences
|
|
@@ -33,7 +42,7 @@ TaskRecords. Set one of these fixed directives in `AGENTS.md`:
|
|
|
33
42
|
- Initiative carrier default: github
|
|
34
43
|
```
|
|
35
44
|
|
|
36
|
-
A repository directive overrides the
|
|
45
|
+
A repository directive overrides the user-level directive. A configured `github`
|
|
37
46
|
default is standing opt-in for GitHub projection, but the literal user still
|
|
38
47
|
confirms the Initiative name, immutable slug, complete Parent/Child decomposition,
|
|
39
48
|
granularity, and dependencies before the first remote mutation. Planner reports
|
|
@@ -6,162 +6,146 @@ description: Use to run an enrolled TaskIntent to completion through Kernel-gove
|
|
|
6
6
|
# Immune-Brain: Loop
|
|
7
7
|
|
|
8
8
|
This skill adheres to the **[BASELINE.md](BASELINE.md)**.
|
|
9
|
-
At every runtime role boundary, call the read-only `imm_loop_action` Tool. Use
|
|
10
|
-
`route` for active Steps, bounded repair, architecture exploration, advisory
|
|
11
|
-
review, Compounder, Kernel ownership, or scope expansion. Use `dispatch_role`
|
|
12
|
-
for `qa`, `code-review`, and `ui-review`, then invoke the returned foreground
|
|
13
|
-
Agent envelope exactly. Brainstorm and Planner use the same Tool for bounded
|
|
14
|
-
`arch-explorer` and explicit-lens `advisory-reviewer` dispatches. Loop may
|
|
15
|
-
dispatch `compounder` only when a closed Step supplies structured evidence for
|
|
16
|
-
a reusable Learning; routine work without that evidence returns `next: none`
|
|
17
|
-
and creates no Learning. Do not discover or load a Pi Skill for these roles. The Managed Path public entries remain `imm-brainstorm`, `imm-planner`, and `imm-loop`; standalone `imm-pr-fix`, `imm-doc-prune`, and `imm-agent-doc-maintain` are host-native and are never dispatched as the Loop role.
|
|
18
|
-
Dispatch authorization follows the [shared Subagent Dispatch
|
|
19
|
-
Protocol](docs/reference/subagent-dispatch-protocol.md#authorization-authority).
|
|
20
|
-
Same-boundary `follow_up` is not a Plan mutation; it repeats the current
|
|
21
|
-
execution, QA, and originating review gate. All internal Agent dispatch
|
|
22
|
-
envelopes use `run_in_background: false` and return a direct result to the Parent
|
|
23
|
-
before any workflow mutation.
|
|
24
|
-
|
|
25
|
-
## Workflow Profiles
|
|
26
|
-
|
|
27
|
-
- `direct` has no Plan or Ledger and never invokes this skill.
|
|
28
|
-
- `standard` keeps execution in the main context, closes a Plan Step when the runtime accepts passing evidence, and therefore does not dispatch the internal QA role per Step. It still dispatches every runtime-required final code/UI review gate. The last gate pass atomically performs internal terminal settlement when `compounder_requirement.required` is false.
|
|
29
|
-
- `strict` preserves the full internal loop: each Step reaches isolated QA before final review, internal Compounder handoff, and terminal settlement. A missing profile is strict.
|
|
30
|
-
- Reviewer `follow_up` targets always retain isolated QA. Standard Plans allow at
|
|
31
|
-
most two completed/open rounds; `review_budget_state.budget_stop` is a hard
|
|
32
|
-
stop. Never attempt a third Loop runtime action.
|
|
33
|
-
- `workflow_profile`, `compounder_requirement`, and `review_budget_state` from
|
|
34
|
-
the live Kernel / Loop projection are authoritative. Do not infer or override
|
|
35
|
-
them in the host.
|
|
36
|
-
|
|
37
|
-
## Core Responsibilities
|
|
38
|
-
|
|
39
|
-
- **Main-context completion loop**: Drive the enrolled Kernel task in the current Host conversation until completion or a safe stop.
|
|
40
|
-
- **Context-preserving execution**: Call `imm_loop_action` with `op: route`, then follow the returned `executor` context in the current Parent conversation. Implement only the active Step or pending same-boundary `follow_up`, then record structured execution evidence through the Loop runtime action. A bounded test failure uses the returned internal `test-fixer` dispatch with its explicit delegated test-file list; PR feedback or CI repair uses the returned internal `pr-fix` dispatch inside the current Plan boundary.
|
|
41
|
-
- **Independent authority isolation**: Use the host `Agent` subagent primitive for `awaiting_qa_decision` and for the exact runtime-reported review gate. Standard Plan Steps close from accepted passing evidence before an internal QA boundary exists; Strict Steps and all follow-ups retain isolated QA. The parent records accepted child decisions through the Loop runtime action.
|
|
42
|
-
- **Observable progress**: Update only at major phase changes: Step start, execution evidence recorded, QA/review result, or terminal stop. Always emit a terminal summary.
|
|
43
|
-
- **Kernel projection authority**: Re-read `imm_kernel_canary` `status` after every persisted action. Conversation memory never overrides the Kernel projection.
|
|
44
|
-
- **External tracker boundary**: The host may attach one opted-in GitHub Issue projection after terminal settlement. Only a fresh claimless `done`/`stopped` projection plus its exact terminal tombstone projects `completed`/`not planned`; Enrollment performs no GitHub projection. Report tracker failures separately, but never treat them as evidence, stop the Loop, repeat a Kernel mutation, or import Issue state.
|
|
45
|
-
- **Scope boundary**: Scope expansion always returns to `imm-planner`; Executor, test repair, and PR/CI repair stop with the concrete missing scope and verification reason instead of widening execution.
|
|
46
|
-
- **Action authority**: The loop always enters through `imm_loop_action`; its projected `next` authority is `executor`, `test-fixer`, `pr-fix`, `arch-explorer`, `advisory-reviewer`, `compounder`, `imm_kernel_canary`, `imm-planner`, or `none`.
|
|
47
|
-
|
|
48
|
-
## Kernel Loop
|
|
49
|
-
|
|
50
|
-
Repeat this sequence; do not silently stop while a valid action remains:
|
|
51
|
-
|
|
52
|
-
1. Call `imm_loop_action` with `op: route` (or `dispatch_role` at a QA/review boundary) and follow the projected `next` authority.
|
|
53
|
-
2. Emit one progress line: `[target][phase] result | next: action`.
|
|
54
|
-
3. Execute exactly one allowed action:
|
|
55
|
-
- Kernel ownership: call `imm_kernel_canary` for that owned task. Freeze the completed artifacts, then call `advance_assurance`; when it returns `review_ready`, invoke the foreground reviewer and pass its structured verdict to `submit_review`. When the projection calls for `request_authorization` or `approve_breaking_intent_revision`, invoke the exact Tool operation directly without asking the user for chat pre-confirmation; the native host interaction is the single authority decision. Invoke `repair_authority_state` directly for a proven stale claim; Kernel revalidation removes only the redundant claim without user interaction.
|
|
56
|
-
- Active Step / `rework_needed`: follow the returned `executor` context in the current conversation, implement only the active Step or pending same-boundary `follow_up`, verify, record structured execution evidence through the Loop runtime action, and continue. A bounded test-only repair may request internal `test-fixer` with `focus_delta.specific_changes`; PR review or CI repair may request internal `pr-fix` with the current `plan_id`, changed-file boundary, and verification. Both return child evidence to the Parent and cannot widen scope.
|
|
57
|
-
- `awaiting_qa_decision`: call `imm_loop_action` with `op: dispatch_role`, role `qa`, the current projection, Plan verification, recorded evidence, and current target identity. Invoke the returned foreground Agent envelope exactly. A `rework` or `replan` must carry validated `notes`.
|
|
58
|
-
- `review_required`: map the exact `pending_review_gate` (`imm-code-review` or `imm-ui-review`) to the internal `code-review` or `ui-review` role and call `imm_loop_action` with `op: dispatch_role`, passing `pending_review_gate`, `review_changed_files`, and `review_changed_files_signature`. Invoke the returned foreground Agent envelope exactly. Record a validated pass, or open a same-boundary follow-up through the Loop runtime action.
|
|
59
|
-
- `awaiting_user_successor_decision`: stop immediately with `recommended_authority: user`, no next skill, and no runtime action. This boundary must not dispatch Planner, transition, Compounder, or a new Pi session/subagent. Only a literal user may supply a concrete validated successor Plan through the native authority gate; the internal runtime token is `--approve-successor`, never a public Skill or user-facing entry.
|
|
60
|
-
4. After every accepted runtime write, discard the old snapshot and read a fresh Kernel / Loop projection. Emit a result line only when the write completes a major phase or a subagent round.
|
|
61
|
-
|
|
62
|
-
Use Pi native `Agent` subagents. Do not spawn Pi child processes or invoke a separate `imm-loop` CLI.
|
|
63
|
-
|
|
64
|
-
## Authority and Failure Guards
|
|
65
|
-
|
|
66
|
-
- Implementation requires a validated Plan and active Step or accepted pending `follow_up`.
|
|
67
|
-
- The parent may implement but must not issue its own QA or review pass.
|
|
68
|
-
- QA and reviewer children must not edit files, write Plans, mutate Kernel state, or close decisions directly.
|
|
69
|
-
- Missing `Agent` support, failed or malformed child output, stale child target, runtime write failure, invalid projection, missing credentials, unclear verification, repeated unchanged failure, or user cancellation stops fail-closed with an explicit reason and no decision write.
|
|
70
|
-
- A Managed native authority failure reports its stable reason and exactly one same-Host recovery action. Never recommend another Host, worktree, Direct Path, unmanaged implementation, or automatic retry as a fallback.
|
|
71
|
-
- `replan_needed` stops at `imm-planner`; do not widen scope or rewrite the active Plan. A replacement must use a new sequential Plan path after the current Plan reaches `completed`, or after a literal user explicitly marks it `cancelled` or `superseded`.
|
|
72
|
-
- Plans never suspend, resume, queue, or execute in parallel. Do not insert a repair Plan ahead of the current Plan.
|
|
73
|
-
- Same-boundary review `follow_up` repeats execution, independent QA, and the originating review gate.
|
|
74
|
-
- Runtime `review_required` is the single review-gate authority. Do not invent hidden gates.
|
|
75
|
-
- `imm-compounder` is an internal role and is never invoked as a public Skill. A `complete` projection carries an explicit internal Compounder handoff because the runtime determined it is required. A Standard Plan with optional Compounder is atomically finished by the last review gate and does not emit that handoff. Strict Plans preserve the successful order: current Steps and QA, required reviews, internal Compounder handoff, terminal settlement, then `awaiting_user_successor_decision` for a non-terminal Roadmap slice.
|
|
76
|
-
- Successor approval is non-delegable. QA, review, Planner, Compounder, and the loop cannot approve or activate a successor, and the loop must not turn a command template into an executable successor invocation.
|
|
77
|
-
|
|
78
|
-
## Stop Conditions
|
|
79
|
-
|
|
80
|
-
Stop only for:
|
|
81
|
-
|
|
82
|
-
- `complete` with an explicit internal Compounder handoff before terminal settlement
|
|
83
|
-
- `terminal_plan_complete` after a contracted terminal Plan or a legacy Plan without successor metadata has passed internal Compounder handoff and terminal settlement; stop with no next skill, authority, or action
|
|
84
|
-
- `awaiting_user_successor_decision` after finish, with literal user authority and no automatic action
|
|
85
|
-
- `replan_needed`
|
|
86
|
-
- blocker or required user input
|
|
87
|
-
- runtime, tool, subagent, or output-contract failure
|
|
88
|
-
- user cancellation (no decision write; Plan termination is a separate explicit user-confirmed runtime action)
|
|
89
|
-
- repeated unchanged failure
|
|
90
|
-
- explicit Step, rework, review, follow-up, or elapsed-time budget exhaustion
|
|
91
|
-
|
|
92
|
-
Session-local budgets are advisory. Persisted Step, QA, review, and follow-up state controls recovery. After interruption, re-enter only by reading a fresh projection: a completed runtime write is honored once; an interrupted pre-write action is not claimed; cancellation performs no decision write; repeated unchanged failure stops unless the next attempt names a strategy change; explicit budgets stop before another action.
|
|
93
|
-
|
|
94
|
-
## Observable Output Contract
|
|
95
|
-
|
|
96
|
-
Do not narrate projection reads or routine runtime writes. Emit compact progress only for Step start, completed execution evidence, QA/review decisions, failures that change the plan, and terminal stop. Every subagent round still emits exactly one dispatch line and exactly one collection/result line:
|
|
97
9
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
10
|
+
## Kernel Canary Routing and Authority
|
|
11
|
+
|
|
12
|
+
Only explicit `imm-loop` entry starts or resumes this loop. Ordinary host input
|
|
13
|
+
stays host-native; it never resumes a Managed owner implicitly. Read the current
|
|
14
|
+
Host's `imm_kernel_canary` `status` first and verify the exact active backend
|
|
15
|
+
claim, TaskIntent, and TaskRecord. Invalid or contradictory projections fail
|
|
16
|
+
closed. A candidate TaskIntent is not Enrollment authority.
|
|
17
|
+
|
|
18
|
+
TaskIntent defines the goal, acceptance, and `scope_hint`; TaskRecord and the
|
|
19
|
+
Kernel projection own lifecycle, artifact state, freshness, and next obligation.
|
|
20
|
+
Conversation memory, GitHub Issues, and `CONTEXT.md` never override them.
|
|
21
|
+
Historical prose Plans and State Ledgers are read-only history, not execution
|
|
22
|
+
instructions. Do not create Steps, workflow profiles, follow-up ledgers, or
|
|
23
|
+
successor Plans to drive a Kernel task.
|
|
24
|
+
|
|
25
|
+
At every internal role boundary call the read-only `imm_loop_action` Tool. Use
|
|
26
|
+
`route` for current-context Executor work, bounded repair, architecture
|
|
27
|
+
exploration, advisory review, Compounder, Kernel ownership, or scope expansion.
|
|
28
|
+
Use Kernel ownership for an enrolled task. This Tool projects authority; it does
|
|
29
|
+
not record execution evidence, mutate task state, or replace Kernel operations.
|
|
30
|
+
Follow the [Subagent Dispatch Protocol](docs/reference/subagent-dispatch-protocol.md#authorization-authority).
|
|
31
|
+
Never load an internal role as a public Skill or spawn another loop process.
|
|
32
|
+
The standalone `imm-pr-fix`, `imm-doc-prune`, and `imm-agent-doc-maintain` are host-native
|
|
33
|
+
maintenance entries, never dispatched as the Loop role. Internal `test-fixer`
|
|
34
|
+
and `pr-fix` repairs remain bounded by the enrolled TaskIntent.
|
|
35
|
+
|
|
36
|
+
## Execution Loop
|
|
37
|
+
|
|
38
|
+
Continue while the current projection has a valid action:
|
|
39
|
+
|
|
40
|
+
1. For active artifacts, implement only the enrolled acceptance within
|
|
41
|
+
`scope_hint` in the current conversation. Run focused checks. Executor checks
|
|
42
|
+
are diagnostic evidence, not a QA or Review approval.
|
|
43
|
+
2. Before Assurance, call `freeze_artifacts` while TaskRecord is `active:active`.
|
|
44
|
+
A bound active Spec and its archive path must both be inside `scope_hint`.
|
|
45
|
+
The Kernel owns byte-preserving archival and the frozen snapshot.
|
|
46
|
+
3. Call `advance_assurance` in the foreground and consume its direct terminal
|
|
47
|
+
result. Deterministic QA runs fixed acceptance descriptors atomically inside
|
|
48
|
+
the Host integration. Do not dispatch a separate per-Step QA Agent.
|
|
49
|
+
4. On `review_ready`, invoke the returned `agent_params` as one exact foreground
|
|
50
|
+
Agent call, then pass its structured verdict to `submit_review`. Do not
|
|
51
|
+
replace this snapshot-bound reviewer with a generic role dispatch. The Parent
|
|
52
|
+
cannot issue its own QA or Review pass.
|
|
53
|
+
5. Follow the returned Kernel obligation. Fresh QA suffices for routine work;
|
|
54
|
+
material and critical work additionally require fresh independent Review.
|
|
55
|
+
Normal completion does not require a second user confirmation.
|
|
56
|
+
6. For rework, follow the projected artifact state before editing. Resolve
|
|
57
|
+
findings only after fixing and verifying their cause. Changed snapshots
|
|
58
|
+
invalidate old evidence; freeze and run the newly required obligations.
|
|
59
|
+
7. Stop on terminal `done` or `stopped`, unresolved user decisions, explicit
|
|
60
|
+
cancellation, or a failure without a safe projected action.
|
|
61
|
+
|
|
62
|
+
Use the fresh projection returned by a successful operation when supplied. Read
|
|
63
|
+
`status` after interruption, ambiguous mutation results, absent projections, or
|
|
64
|
+
suspected external changes. Never repeat a mutation merely to obtain its result.
|
|
65
|
+
Kernel CAS and freshness checks remain mandatory; reducing Parent reads does
|
|
66
|
+
not bypass them. Do not poll or create detached jobs.
|
|
67
|
+
|
|
68
|
+
## Decisions and Recovery
|
|
69
|
+
|
|
70
|
+
- Scope expansion always returns to `imm-planner`. Collect all currently known missing
|
|
71
|
+
paths, caller/test/generated mirrors, and verification reasons in one request.
|
|
72
|
+
Do not edit outside scope while waiting or widen it piecemeal without new
|
|
73
|
+
evidence. Bounded test or PR repair stays inside the same TaskIntent.
|
|
74
|
+
- Invoke `approve_breaking_intent_revision` with the complete next intent
|
|
75
|
+
directly; the native Host gate is the single user decision. Do not overwrite
|
|
76
|
+
enrolled intent sidecars or ask for chat pre-confirmation.
|
|
77
|
+
- On `awaiting_user`, invoke `request_authorization` directly. It is reserved
|
|
78
|
+
for a concrete unresolved decision or explicit stop, not risk tier alone.
|
|
79
|
+
- Invoke `repair_authority_state` directly for a proven stale claim. Kernel
|
|
80
|
+
revalidation removes only the redundant claim without user interaction.
|
|
81
|
+
- A Managed native authority failure stays fail-closed. Report its stable reason
|
|
82
|
+
and exactly one same-Host recovery action. Never recommend another Host,
|
|
83
|
+
worktree, Direct Path, unmanaged implementation, or automatic retry.
|
|
84
|
+
- After interruption, read a fresh projection and run only the pending obligation.
|
|
85
|
+
A committed QA result is honored; an interrupted precommit QA run produces no
|
|
86
|
+
approval. Do not rerun fresh QA simply because Review was interrupted.
|
|
87
|
+
- Malformed or stale reviewer output is not a verdict. Keep the existing
|
|
88
|
+
reservation only if the Host reports it valid; use its exact recovery action.
|
|
89
|
+
Do not fabricate a pass or blindly redispatch Review.
|
|
90
|
+
- Missing tools, credentials, invalid projections, or repeated unchanged failures
|
|
91
|
+
stop with a concrete cause. Cancellation performs no decision write and is not
|
|
92
|
+
task termination. Explicit task stop uses its native authority gate.
|
|
93
|
+
|
|
94
|
+
## Review and Learning
|
|
95
|
+
|
|
96
|
+
Reviewers are read-only and bound to the frozen snapshot. They cannot edit files,
|
|
97
|
+
write planning artifacts, mutate Kernel state, or settle decisions. Report all
|
|
98
|
+
substantiated blockers in one round, tied to acceptance or a concrete regression;
|
|
99
|
+
separate optional advice from blockers. Suggestions alone do not justify rework.
|
|
100
|
+
Use the returned verdict schema exactly, including omission of unsupported fields.
|
|
101
|
+
|
|
102
|
+
`dispatch_role` for `qa`, `code-review`, or `ui-review` is used only when an
|
|
103
|
+
explicit runtime-supported role boundary requests it, followed by the returned
|
|
104
|
+
foreground Agent envelope exactly. It is not an extra gate on Kernel Assurance.
|
|
105
|
+
All internal Agent envelopes use `run_in_background: false`.
|
|
106
|
+
|
|
107
|
+
The internal Compounder is optional: only closed work with structured evidence
|
|
108
|
+
of a reusable Learning may route to it. Routine completion creates no Learning.
|
|
109
|
+
It cannot approve successors or delay terminal settlement. A projection with
|
|
110
|
+
`recommended_authority: user` must not dispatch successor work automatically.
|
|
111
|
+
Do not create, switch,
|
|
112
|
+
or delete Git worktrees; operate only in the Host launch directory.
|
|
113
|
+
|
|
114
|
+
The Host may attach an opted-in GitHub projection after settlement. Only a fresh claimless
|
|
115
|
+
`done`/`stopped` projection plus its exact terminal tombstone projects
|
|
116
|
+
`completed`/`not planned`; Enrollment performs no GitHub projection. Report a
|
|
117
|
+
tracker failure separately; never use it as evidence, a Loop blocker, or a reason to
|
|
118
|
+
repeat a Kernel mutation.
|
|
119
|
+
|
|
120
|
+
## Observable Output
|
|
121
|
+
|
|
122
|
+
Emit progress at execution start, QA/Review phase changes, failures, and terminal
|
|
123
|
+
stop. Every Agent round has one dispatch line and one result line; never claim a
|
|
124
|
+
successful collection on timeout, cancellation, malformed output, or stale identity.
|
|
125
|
+
Normal conversation and visible Tool calls are the observation surface. Do not
|
|
126
|
+
narrate routine projection reads or add Footer status content.
|
|
127
|
+
|
|
128
|
+
Every exit includes a concise summary:
|
|
107
129
|
|
|
108
130
|
```text
|
|
109
|
-
|
|
110
|
-
Completed
|
|
131
|
+
Task:
|
|
132
|
+
Completed work:
|
|
111
133
|
QA:
|
|
112
134
|
Review:
|
|
113
135
|
Stop reason:
|
|
114
136
|
Next action:
|
|
115
137
|
```
|
|
116
138
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
- If no validated Plan exists: stop and route to `imm-planner`.
|
|
132
|
-
- If an allowed Loop action exists: continue the loop without another user command.
|
|
133
|
-
- If work is fully closed but not finished: report the explicit internal Compounder handoff and wait for terminal settlement.
|
|
134
|
-
- If the projection is `awaiting_user_successor_decision`: report the candidate and preconditions, ask for the user's decision, and stop without dispatch.
|
|
135
|
-
|
|
136
|
-
## Output style
|
|
137
|
-
|
|
138
|
-
Default user-facing shape: checkpoint progress lines, then `Conclusion -> Evidence -> Next action` at the terminal boundary.
|
|
139
|
-
|
|
140
|
-
## Kernel Canary Routing
|
|
141
|
-
|
|
142
|
-
When the Kernel projection reports an active/draining backend claim, keep
|
|
143
|
-
`imm-loop` as the user-facing entry and call the current Host's Kernel integration
|
|
144
|
-
for that owned task. Enrollment and Review authorization use the current Host's
|
|
145
|
-
native gates. When the projection calls for `request_authorization` or
|
|
146
|
-
`approve_breaking_intent_revision`, invoke the exact Tool operation directly
|
|
147
|
-
without asking the user for chat pre-confirmation; the native Host interaction is
|
|
148
|
-
the single authority decision. Invoke
|
|
149
|
-
`repair_authority_state` directly for a proven stale claim; Kernel revalidation
|
|
150
|
-
removes only the redundant claim without user interaction. Do not invoke the
|
|
151
|
-
removed `imm-canary-work` Skill as
|
|
152
|
-
a separate entry point. Invalid or contradictory projections fail closed. After
|
|
153
|
-
implementation and focused verification, freeze the artifacts and call
|
|
154
|
-
`advance_assurance`. If it returns `review_ready`, invoke the foreground
|
|
155
|
-
reviewer and pass its structured verdict to `submit_review`;
|
|
156
|
-
`request_authorization` is reserved for an unresolved user decision or an
|
|
157
|
-
explicit stop. Critical work completes after fresh QA and Review without a
|
|
158
|
-
second user confirmation.
|
|
159
|
-
Every QA/Review operation stays foreground and returns its next projected
|
|
160
|
-
obligation directly to the Parent. The host performs any opted-in GitHub Issue
|
|
161
|
-
projection only after the corresponding authority mutation: only a fresh
|
|
162
|
-
claimless `done`/`stopped` projection with its exact terminal tombstone projects
|
|
163
|
-
terminal closure (`completed`/`not planned`); Enrollment performs no GitHub
|
|
164
|
-
projection. Treat the attached tracker result as non-authoritative observation.
|
|
165
|
-
Report its failure separately, but never use it as evidence, a stop condition,
|
|
166
|
-
or a reason to repeat a Kernel mutation. A terminal tombstone alone never
|
|
167
|
-
blocks unrelated v3 routing.
|
|
139
|
+
For `settlement_unknown`, call `advance_assurance` once to reconcile the Kernel
|
|
140
|
+
projection before resuming; never replay the uncertain write directly. The runtime
|
|
141
|
+
retries only explicit `EINTR`/`EAGAIN` failures of its initial projection read, once,
|
|
142
|
+
with cancellation checks. Semantic authority errors and mutation failures are not
|
|
143
|
+
retryable reads. For `review_preparation_failed`, repair the reported transport or
|
|
144
|
+
environment cause before advancing; committed QA remains valid. For
|
|
145
|
+
`verdict_invalid`, correct the existing payload once and resubmit without another
|
|
146
|
+
reviewer dispatch. If correction fails, report the schema failure and stop the
|
|
147
|
+
correction loop.
|
|
148
|
+
|
|
149
|
+
For failures, name the cause, stages already committed, the safe retry boundary,
|
|
150
|
+
and exactly one next action. Distinguish user approval from environment repair
|
|
151
|
+
and runtime failure. Do not ask the user to manually switch internal roles.
|