immune-brain 3.2.0 → 3.2.2

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 CHANGED
@@ -46,7 +46,7 @@ This repo is a Pi package — Pi discovers Skills and extensions from `package.j
46
46
  }
47
47
  ```
48
48
 
49
- No extra server config is needed. Installing the package via Pi makes all 5 Skills available automatically. Verify with:
49
+ No extra server config is needed. Installing the package via Pi makes all 6 Skills available automatically. Verify with:
50
50
 
51
51
  ```bash
52
52
  bun test # run all tests
@@ -165,7 +165,7 @@ See [`docs/reference/immune-brain-config.md`](docs/reference/immune-brain-config
165
165
  package.json # Pi package manifest (skills + extensions)
166
166
  plugins/immune-brain/
167
167
  ├── .pi-extension/ # Pi TUI + Kernel authority extension
168
- ├── skills/ # 5 public Skills (trigger shims)
168
+ ├── skills/ # 6 public Skills (trigger shims)
169
169
  ├── dist/ # Built skill contracts & references
170
170
  ├── runtime/ # Bun + TypeScript runtime & Kernel
171
171
  └── bin/ # CLI wrappers (→ runtime/v4_runtime.ts)
@@ -183,7 +183,7 @@ docs/specs/ # Living specs (updated in place)
183
183
 
184
184
  ## FAQ
185
185
 
186
- **Do I need to learn all 5 skills?** No. Just describe what you want — Pi routes to the right skill. Learn `imm-planner` and `imm-loop` first; the other two are occasional.
186
+ **Do I need to learn all 6 skills?** No. Just describe what you want — Pi routes to the right skill. Learn `imm-planner` and `imm-loop` first; the other four are occasional.
187
187
 
188
188
  **What if I interrupt or close Pi mid-task?** State is on disk (`.imm/` + TaskIntent). Re-enter `imm-loop` to resume — the Kernel projection is authoritative.
189
189
 
@@ -202,8 +202,8 @@ This repo uses [Changesets](https://github.com/changesets/changesets) for versio
202
202
  | Task | Command |
203
203
  |------|---------|
204
204
  | Add a changeset | `bunx changeset` — pick bump (patch/minor/major) and write summary |
205
- | Bump version | `bun run changeset:version` — updates `package.json` + `CHANGELOG.md` |
206
- | Publish (local) | `bun run changeset:publish` — publishes to npm (needs `NPM_TOKEN` or `npm login`) |
205
+ | Bump version | `bun run changeset:version` — updates `package.json` + `CHANGELOG.md`, then syncs and validates the Claude plugin manifest |
206
+ | Publish (local) | `bun run changeset:publish` — validates manifest versions, then publishes to npm (needs `NPM_TOKEN` or `npm login`) |
207
207
 
208
208
  **Automated flow (recommended):**
209
209
  1. Push changesets to `main` → workflow opens a “Version Packages” PR.
package/README.zh-CN.md CHANGED
@@ -46,7 +46,7 @@ Pi 与 Claude Code 是支持的宿主。未声明的适配器仍不受支持。C
46
46
  }
47
47
  ```
48
48
 
49
- 无需额外 server 配置,通过 Pi 安装本 package 后 5 个 Skill 即自动可用。验证:
49
+ 无需额外 server 配置,通过 Pi 安装本 package 后 6 个 Skill 即自动可用。验证:
50
50
 
51
51
  ```bash
52
52
  bun test # 全量测试
@@ -165,7 +165,7 @@ Immune-Brain **没有独立配置文件**,偏好设置写在 `AGENTS.md`(仓
165
165
  package.json # Pi package manifest(skills + extensions)
166
166
  plugins/immune-brain/
167
167
  ├── .pi-extension/ # Pi TUI + Kernel 扩展
168
- ├── skills/ # 5 个公开 Skills(触发 shim)
168
+ ├── skills/ # 6 个公开 Skills(触发 shim)
169
169
  ├── dist/ # 构建后的 skill 契约与参考文档
170
170
  ├── runtime/ # Bun + TypeScript 运行时与 Kernel
171
171
  └── bin/ # CLI wrappers(→ runtime/v4_runtime.ts)
@@ -183,7 +183,7 @@ docs/specs/ # Living specs(原地更新)
183
183
 
184
184
  ## 常见问题
185
185
 
186
- **需要记住所有 Skill 吗?** 不需要,直接描述需求即可,Pi 会自动路由。先掌握 `imm-planner` 和 `imm-loop`,另外两个按需使用。
186
+ **需要记住所有 Skill 吗?** 不需要,直接描述需求即可,Pi 会自动路由。先掌握 `imm-planner` 和 `imm-loop`,另外四个按需使用。
187
187
 
188
188
  **中途关闭 Pi 会怎样?** 状态已落盘(`.imm/` + TaskIntent),重新进入 `imm-loop` 即可恢复,以 Kernel projection 为准。
189
189
 
@@ -202,8 +202,8 @@ docs/specs/ # Living specs(原地更新)
202
202
  | 任务 | 命令 |
203
203
  |------|------|
204
204
  | 创建 changeset | `bunx changeset` — 选择 bump 类型(patch/minor/major)并填写说明 |
205
- | 升级版本 | `bun run changeset:version` — 更新 `package.json` + `CHANGELOG.md` |
206
- | 本地发布 | `bun run changeset:publish` — 发布到 npm(需 `NPM_TOKEN` 或 `npm login`) |
205
+ | 升级版本 | `bun run changeset:version` — 更新 `package.json` + `CHANGELOG.md`,然后同步并校验 Claude plugin manifest |
206
+ | 本地发布 | `bun run changeset:publish` — 校验 manifest 版本后发布到 npm(需 `NPM_TOKEN` 或 `npm login`) |
207
207
 
208
208
  **自动化流程(推荐):**
209
209
  1. 推送 changeset 到 `main` → workflow 自动创建 “Version Packages” PR。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "immune-brain",
3
- "version": "3.2.0",
3
+ "version": "3.2.2",
4
4
  "description": "Immune-Brain agent skill system",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "scripts": {
31
31
  "changeset": "changeset",
32
- "changeset:version": "changeset version && bun scripts/plugin_versioning.ts stamp",
33
- "changeset:publish": "changeset publish",
32
+ "changeset:version": "changeset version && bun scripts/plugin_versioning.ts stamp && bun scripts/plugin_versioning.ts validate",
33
+ "changeset:publish": "bun scripts/plugin_versioning.ts validate && changeset publish",
34
34
  "release": "bun run changeset:publish"
35
35
  },
36
36
  "devDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "immune-brain",
3
- "version": "3.2.0",
3
+ "version": "3.2.2",
4
4
  "description": "Immune-Brain Claude Code Host: native Enrollment, QA, Review, and Kernel settlement.",
5
5
  "author": {
6
6
  "name": "Immune-Brain Team"
@@ -458,9 +458,7 @@ async function executeForegroundEnrollment(
458
458
  `Goal: ${taskIntent.intent.goal}`,
459
459
  `Risk: ${taskIntent.intent.risk}`,
460
460
  `Scope: ${taskIntent.intent.scope_hint.length > 0 ? taskIntent.intent.scope_hint.join(", ") : "(none)"}`,
461
- `Acceptance: ${taskIntent.intent.acceptance.length} descriptor(s); press d to expand`,
462
- `Intent digest: ${preparation.intent.content_hash}`,
463
- `Preparation digest: ${preparation.digest}`,
461
+ `Acceptance: ${taskIntent.intent.acceptance.length} descriptor(s)`,
464
462
  ].join("\n");
465
463
  const confirmationDetails = [
466
464
  `Acceptance descriptors:`,
@@ -477,7 +477,7 @@ export default function (
477
477
  presentTaskRail(ctx, {
478
478
  task_id: taskId,
479
479
  state: "Approval required",
480
- result: "Kernel authority repair requires literal-user approval",
480
+ result: "Authority repair needs your approval",
481
481
  next: "Decide whether to repair the stale claim",
482
482
  });
483
483
  const repairSelection = await requestAuthorityDialog(pi, ctx, {
@@ -854,7 +854,7 @@ export default function (
854
854
  presentTaskRail(ctx, {
855
855
  task_id: taskId,
856
856
  state: "Approval required",
857
- result: `${operation} requires literal-user approval`,
857
+ result: `${operation} requires your confirmation`,
858
858
  next: `Decide ${operation}`,
859
859
  });
860
860
  const attention = {
@@ -870,7 +870,7 @@ export default function (
870
870
  details: dialogDetails,
871
871
  signal: ctx.signal,
872
872
  actions: [
873
- { value: "authorize", label: "Authorize", description: `Apply ${operation} after freshness revalidation` },
873
+ { value: "authorize", label: "Authorize", description: `Apply ${operation} after re-checking state` },
874
874
  { value: "cancel", label: "Cancel", description: "Leave managed authority unchanged" },
875
875
  ],
876
876
  });
@@ -161,7 +161,14 @@ export async function requestAuthorityDialog<T extends string, R = T | undefined
161
161
 
162
162
  export function presentTaskRail(ctx: UiContext, view: TaskRailView): void {
163
163
  try {
164
- ctx.ui.setWidget(TASK_RAIL_KEY, renderTaskRail(view), { placement: "aboveEditor" });
164
+ ctx.ui.setWidget(TASK_RAIL_KEY, (_tui, theme) => {
165
+ return {
166
+ render(width: number): string[] {
167
+ return renderTaskRail(view, width, theme);
168
+ },
169
+ invalidate(): void {},
170
+ };
171
+ }, { placement: "aboveEditor" });
165
172
  if (view.state === "Completed" || view.state === "Stopped") terminalRailUis.add(ctx.ui);
166
173
  else terminalRailUis.delete(ctx.ui);
167
174
  } catch {
@@ -180,7 +187,7 @@ export function presentTaskRailResult(
180
187
  const operation = string(details.operation);
181
188
  const rawState = string(details.state);
182
189
  const result = string(details.result) ?? string(details.reason) ?? operation ?? rawState ?? "Task state updated";
183
- const next = string(details.next_action) ?? "Continue through the projected authority";
190
+ const next = string(details.next_action) ?? "Follow the projected Obligation";
184
191
  presentTaskRail(ctx, {
185
192
  task_id: taskId,
186
193
  state: railState({ lifecycle, obligation: string(taskState?.next_obligation), operation, state: rawState }),
@@ -286,11 +293,34 @@ function emitAttention(pi: EventPublisher, event: UserAttentionEventV1): void {
286
293
  }
287
294
  }
288
295
 
289
- function renderTaskRail(view: TaskRailView): string[] {
296
+ function formatTaskRailState(state: TaskRailState, theme?: Theme): string {
297
+ const symbolAndColor: Record<TaskRailState, { symbol: string; color: string }> = {
298
+ Planning: { symbol: "●", color: "muted" },
299
+ "Approval required": { symbol: "▲", color: "accent" },
300
+ Working: { symbol: "●", color: "accent" },
301
+ Verifying: { symbol: "●", color: "accent" },
302
+ Reviewing: { symbol: "●", color: "accent" },
303
+ Blocked: { symbol: "⚠", color: "warning" },
304
+ Completed: { symbol: "✓", color: "success" },
305
+ Stopped: { symbol: "■", color: "muted" },
306
+ };
307
+ const cfg = symbolAndColor[state] ?? { symbol: "●", color: "dim" };
308
+ if (!theme) return `${cfg.symbol} ${state}`;
309
+ return `${theme.fg(cfg.color, cfg.symbol)} ${theme.fg(cfg.color, state)}`;
310
+ }
311
+
312
+ function renderTaskRail(view: TaskRailView, width = 120, theme?: Theme): string[] {
313
+ const prefixWidth = 8; // "Result: " or "Next: "
314
+ const availableContentWidth = Math.max(20, width - prefixWidth);
315
+ const taskIdWidth = Math.max(16, Math.min(52, width - 26));
316
+ const stateFormatted = formatTaskRailState(view.state, theme);
317
+ const label = (text: string) => (theme ? theme.fg("muted", text) : text);
318
+ const body = (text: string) => (theme ? theme.fg("dim", text) : text);
319
+
290
320
  return [
291
- `Task ${boundedMiddle(view.task_id, 52)} · ${view.state}`,
292
- `Result: ${bounded(view.result, 112)}`,
293
- `Next: ${bounded(view.next, 112)}`,
321
+ `Task ${boundedMiddle(view.task_id, taskIdWidth)} · ${stateFormatted}`,
322
+ `${label("Result:")} ${body(bounded(view.result, availableContentWidth))}`,
323
+ `${label("Next:")} ${body(bounded(view.next, availableContentWidth))}`,
294
324
  ];
295
325
  }
296
326
 
@@ -338,12 +368,12 @@ function strings(value: unknown): string[] {
338
368
  }
339
369
 
340
370
  function bounded(value: string, max: number): string {
341
- return value.length <= max ? value : `${value.slice(0, max - 3)}...`;
371
+ return value.length <= max ? value : `${value.slice(0, max - 1)}…`;
342
372
  }
343
373
 
344
374
  function boundedMiddle(value: string, max: number): string {
345
375
  if (value.length <= max) return value;
346
- const visible = max - 3;
376
+ const visible = max - 1;
347
377
  const start = Math.ceil(visible / 2);
348
- return `${value.slice(0, start)}...${value.slice(-(visible - start))}`;
378
+ return `${value.slice(0, start)}…${value.slice(-(visible - start))}`;
349
379
  }
@@ -117,6 +117,6 @@ kept for historical reference only.
117
117
 
118
118
  ## Notes
119
119
 
120
- - `imm-work` owns HANDOFF.md writes (boundary exception documented in skill)
121
- - `.imm/memory/` is the source of truth; HANDOFF.md is a convenience artifact
120
+ - Historical: `imm-work` previously owned HANDOFF.md writes (v3 boundary exception); that writer was removed with the v3 State Ledger retirement and no current runtime code rewrites the generated block.
121
+ - Historical: `.imm/memory/` was the v3 source of truth; it is retired. The current durable source of truth is the TaskRecord v4 under `.imm/state/tasks/`, with HANDOFF.md as a convenience artifact only.
122
122
  - Priority files list is advisory (max 5) and exists only to make Pi session continuation faster
@@ -65,8 +65,8 @@ listed here while its program was in flight; when that program closed the
65
65
  justification expired, and the spec was archived rather than left protected by
66
66
  text that no longer described it.
67
67
 
68
- - `docs/specs/automatic-subagent-activation.spec.md` — pinned by live planning artifacts: `scripts/dist-sync-manifest.ts`, `tests/code-review-activation-contract.test.ts`, and packaged copy `plugins/immune-brain/dist/docs/specs/automatic-subagent-activation.spec.md`.
69
- - `docs/specs/opencode-native-plugin.spec.md` — dual-path pinned; `tests/python-reference-boundary.test.ts` resolves it at either `docs/specs/` or `docs/specs/archive/`.
68
+ - `docs/specs/automatic-subagent-activation.spec.md` — EXPIRED: this exemption lapsed when its program closed and the spec was archived to `docs/specs/archive/automatic-subagent-activation.spec.md` (the packaged copy pin in `tests/code-review-activation-contract.test.ts` remains in force).
69
+ - `docs/specs/opencode-native-plugin.spec.md` — EXPIRED: this exemption lapsed when its program closed and the spec was archived to `docs/specs/archive/opencode-native-plugin.spec.md` (the dual-path resolution in `tests/python-reference-boundary.test.ts` remains in force).
70
70
  - `docs/plans/archive/2026-06-29-001-feat-bun-typescript-runtime-migration-plan.md` — frozen plan: its `docs/specs/opencode-native-plugin.spec.md` reference is exempt from archive-path rewriting because it is part of `REFERENCE_SIGNATURE = "e89bf7809875d215c2ca0275c8f6e86e024dd451934fdc04d8e4a422bbd03a6c"` in `tests/plan-validation.test.ts`; rewriting it changes the cross-runtime signature.
71
71
 
72
72
  Non-terminal artifacts remain durable at their existing paths by default.
@@ -55,9 +55,12 @@ commit.
55
55
  routing owner or scope cannot be read reliably, fail closed for mutation.
56
56
 
57
57
  3. **Inventory instruction relationships.** Determine nesting, explicit
58
- precedence statements, inbound references, and existing authority pointers.
59
- Preserve each file's native organization. Do not normalize files to a shared
60
- template and do not infer unsupported cross-host inheritance semantics.
58
+ precedence statements, inbound references, existing authority pointers, and
59
+ semantic duplication within and across candidates. Preserve each file's
60
+ native organization. Do not normalize files to a shared template and do not
61
+ infer unsupported cross-host inheritance semantics. Resolve duplicate
62
+ ownership only from explicit precedence, authority, and inbound-reference
63
+ evidence; unresolved ownership remains `UNVERIFIED` or `BLOCKED`.
61
64
 
62
65
  4. **Build repository facts.** Resolve current truth in this order:
63
66
  executable/public registries, package exports, CLI/runtime entrypoints;
@@ -77,14 +80,25 @@ commit.
77
80
  6. **Classify exact actions.** Classify entries as `REMOVE`, `REWRITE`,
78
81
  `POINTER`, `KEEP`, `BLOCKED`, `BLOCKED_ACTIVE_SCOPE`, `UNVERIFIED`, or
79
82
  `MISSING_OWNER`. Every mutation entry identifies exact file/section bytes,
80
- preserved meaning, evidence, candidate hash, and resulting text. `POINTER`
81
- may target only an existing current authority and must include a concrete
82
- trigger condition. Missing reference ownership is `MISSING_OWNER`; this Skill
83
- does not create a reference document. Unknown or one-off-looking rules remain
84
- `UNVERIFIED` and are not deleted by default. Unresolved precedence or
85
- semantic conflicts that cannot be decided from explicit repository scope or
86
- declared precedence are `BLOCKED`. Filename convention, nesting, or guessed
87
- host behavior alone may not resolve a conflict.
83
+ preserved meaning, evidence, candidate hash, and resulting text. A retained
84
+ meaning has one instruction owner; duplicate copies are not all `KEEP` by
85
+ default. Rules already enforced deterministically by a formatter, linter,
86
+ schema, permission policy, Git hook, or runtime are `REMOVE` unless the agent
87
+ still needs a non-discoverable recovery action, in which case use the shortest
88
+ `REWRITE` or `POINTER`. Keep globally relevant retained rules inline. For a
89
+ branch-specific rule, prefer `POINTER` to an existing current authority with
90
+ a concrete trigger condition; when no owner exists, use `MISSING_OWNER`
91
+ rather than creating one. This Skill does not create a reference document.
92
+ Do not introduce host-specific conditional markup,
93
+ including `<important if>`, without an explicit current host contract and
94
+ repository evidence that the target file uses those semantics. Discoverable
95
+ code snippets, examples, and command tables are repository caches and are
96
+ removed or replaced with a stable pointer unless they encode a necessary
97
+ non-discoverable exception or recovery action. Unknown or one-off-looking
98
+ rules remain `UNVERIFIED` and are not deleted by default. Unresolved
99
+ precedence or semantic conflicts that cannot be decided from explicit
100
+ repository scope or declared precedence are `BLOCKED`. Filename convention,
101
+ nesting, or guessed host behavior alone may not resolve a conflict.
88
102
 
89
103
  7. **Produce one exact manifest.** `audit` mode stops after the manifest.
90
104
  Mutation mode also stops until the literal user approves exact manifest
@@ -103,8 +117,9 @@ commit.
103
117
  brevity.
104
118
 
105
119
  9. **Verify and report.** Re-scan modified instruction relationships, local
106
- pointer targets, unresolved conflicts, source/package public-surface parity,
107
- existing focused documentation contracts, and `git diff --check`. This Skill
120
+ pointer targets, duplicate retained meanings, unresolved conflicts,
121
+ source/package public-surface parity, existing focused documentation
122
+ contracts, and `git diff --check`. This Skill
108
123
  does not execute arbitrary documented commands, real-model success-rate
109
124
  benchmarks, or Token measurements unless the user literally requests a
110
125
  benchmark. This Skill does not commit. Report only `Removed`, `Rewritten`,
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: imm-loop
3
- description: Use when running validated Plans to completion.
3
+ description: Use to run an enrolled TaskIntent to completion through Kernel-governed execution, QA, and Review.
4
4
  ---
5
5
 
6
6
  # Immune-Brain: Loop
@@ -141,17 +141,22 @@ Default user-facing shape: checkpoint progress lines, then `Conclusion -> Eviden
141
141
  When the Kernel projection reports an active/draining backend claim, keep
142
142
  `imm-loop` as the user-facing entry and call the `imm_kernel_canary` Tool for
143
143
  that owned task. Enrollment uses the `imm_canary_enrollment` Tool and Review
144
- authorization remains a native TUI gate using the internal user-kind approval
145
- action `record-user-approval`. When the projection calls for
144
+ authorization remains a native TUI gate. When the projection calls for
146
145
  `request_authorization`, `approve_breaking_intent_revision`, or
147
146
  `repair_authority_state`, invoke the exact Tool operation directly without
148
147
  asking the user for chat pre-confirmation; the native host interaction is the
149
- single authority decision. This action is not a public Skill or CLI route. Do
150
- not invoke the removed `imm-canary-work` Skill as a separate entry point.
151
- Invalid or contradictory projections fail closed. After implementation and focused verification, freeze the artifacts and call
152
- `imm_kernel_canary` `advance_assurance`. If it returns `review_ready`, invoke
153
- the foreground reviewer and pass its structured verdict to `submit_review`;
154
- `request_authorization` remains the user authorization boundary. Foreground
155
- results replace background continuation and result polling. A terminal task leaves only an immutable task tombstone: it is
156
- never reactivated and never blocks unrelated v3 routing. The Kernel projection
157
- is advisory; every Kernel mutation re-enters Kernel store-lock validation.
148
+ single authority decision. Do not invoke the removed `imm-canary-work` Skill as
149
+ a separate entry point. Invalid or contradictory projections fail closed. After
150
+ implementation and focused verification, freeze the artifacts and call
151
+ `advance_assurance`. If it returns `review_ready`, invoke the foreground
152
+ reviewer and pass its structured verdict to `submit_review`;
153
+ `request_authorization` remains the critical-risk user authorization boundary.
154
+ Every QA/Review operation stays foreground and returns its next projected
155
+ obligation directly to the Parent. The host performs any opted-in GitHub Issue
156
+ projection only after the corresponding authority mutation: only a fresh
157
+ claimless `done`/`stopped` projection with its exact terminal tombstone projects
158
+ terminal closure (`completed`/`not planned`); Enrollment performs no GitHub
159
+ projection. Treat the attached tracker result as non-authoritative observation.
160
+ Report its failure separately, but never use it as evidence, a stop condition,
161
+ or a reason to repeat a Kernel mutation. A terminal tombstone alone never
162
+ blocks unrelated v3 routing.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: imm-planner
3
- description: Use when planning work.
3
+ description: Use to create or revise a spec and TaskIntent from requirements; owns scope and decomposition, not implementation or Enrollment.
4
4
  ---
5
5
 
6
6
  # Immune-Brain: Planner
@@ -1,51 +1,9 @@
1
1
  ---
2
2
  name: imm-loop
3
- description: Use to run a validated Plan to completion in the current conversation through checkpoints and isolated QA/review authorities.
3
+ description: Use to run an enrolled TaskIntent to completion through Kernel-governed execution, QA, and Review.
4
4
  ---
5
5
 
6
6
  # Immune-Brain: Loop
7
7
 
8
- Load [`../../dist/imm-loop.md`](../../dist/imm-loop.md), then run the checkpoint loop in the current Pi conversation. Keep active Step implementation in this conversation; use Pi native `Agent` subagents only when the runtime reports `awaiting_qa_decision` or a required review gate. Standard Plan Steps close from passing evidence without per-Step QA; Strict Plan Steps retain isolated QA. Return visible checkpoint progress and a final stop summary.
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
- Subagent Dispatch Protocol](../../dist/docs/reference/subagent-dispatch-protocol.md#authorization-authority).
19
- All internal Agent dispatch envelopes use `run_in_background: false` and
20
- return a direct result to the Parent before any workflow mutation.
21
-
22
- At `terminal_plan_complete`, stop with no next skill, authority, or action. At `awaiting_user_successor_decision`, stop with `recommended_authority: user`. This boundary follows the explicit internal Compounder handoff and runtime terminal settlement; it must not dispatch Planner, Compounder, transition, or a new Pi session/subagent. Only a literal user may approve a successor through the native authority gate; the internal runtime token is `--approve-successor`, never a public Skill or user-facing entry.
23
-
24
- Scope expansion always returns to `imm-planner`; Executor and repair roles must stop with the concrete missing scope and verification reason instead of widening execution.
25
-
26
- The loop always enters through `imm_loop_action`: the projected action's `next`
27
- authority is `executor`, `test-fixer`, `pr-fix`, `arch-explorer`,
28
- `advisory-reviewer`, `compounder`, `imm_kernel_canary`, `imm-planner`, or
29
- `none`.
30
-
31
- When the Kernel projection reports an active/draining backend claim, keep
32
- `imm-loop` as the user-facing entry and call the `imm_kernel_canary` Tool for
33
- that owned task. Enrollment uses the `imm_canary_enrollment` Tool and Review
34
- authorization remains a native TUI gate. When the projection calls for
35
- `request_authorization`, `approve_breaking_intent_revision`, or
36
- `repair_authority_state`, invoke the exact Tool operation directly without
37
- asking the user for chat pre-confirmation; the native host interaction is the
38
- single authority decision. Do not invoke the removed `imm-canary-work` Skill as
39
- a separate entry point. Invalid or contradictory projections fail closed. After
40
- implementation and focused verification, freeze the artifacts and call
41
- `advance_assurance`. If it returns `review_ready`, invoke the foreground
42
- reviewer and pass its structured verdict to `submit_review`; `request_authorization` remains the
43
- critical-risk user authorization boundary. Every QA/Review operation stays
44
- foreground and returns its next projected obligation directly to the Parent. The host performs any opted-in GitHub Issue projection only after the
45
- corresponding authority mutation: only a fresh claimless `done`/`stopped`
46
- projection with its exact terminal tombstone projects terminal closure
47
- (`completed`/`not planned`); Enrollment performs no GitHub projection. Treat the
48
- attached tracker result as non-authoritative observation. Report its failure
49
- separately, but never use it as evidence, a stop condition, or a reason to
50
- repeat a Kernel mutation. A terminal tombstone alone never blocks unrelated v3
51
- routing.
8
+ Load [`../../dist/imm-loop.md`](../../dist/imm-loop.md), then follow that
9
+ canonical contract in the current host conversation.
@@ -1,232 +1,9 @@
1
1
  ---
2
2
  name: imm-planner
3
- description: Use to create or revise a spec and iteration plan from requirements; owns scope and plan decomposition, not implementation or step activation.
3
+ description: Use to create or revise a spec and TaskIntent from requirements; owns scope and decomposition, not implementation or Enrollment.
4
4
  ---
5
5
 
6
6
  # Immune-Brain: Planner
7
7
 
8
- Load [`../../dist/imm-planner.md`](../../dist/imm-planner.md), then create or revise
9
- the executable plan. `mode: page_design` is the canonical pre-implementation
10
- design-contract mode formerly exposed as `imm-page-design`. Keep scope
11
- explicit, including the Devil's Advocate preplan audit and `Devil's Advocate Audit` output. Return plan path, decisions,
12
- first step, verification approach, and Next Action.
13
-
14
- ## Clarification supplement
15
-
16
- Planner consumes an upstream Brainstorm manifest as a closed-world input and
17
- must not repeat, reopen, or rewrite confirmed decisions. Direct Planner entry
18
- and Medium/High Design Risk work must inspect relevant ADRs and rejected
19
- Learnings. It resolves repository facts and owns ordinary technical choices: design and component boundaries, failure behavior, compatibility, migration, recovery and
20
- rollback, Verification, execution slices, dependencies, scope, and delivery
21
- risk. It then authors the candidate Spec, Plan, or TaskIntent.
22
-
23
- Planner may ask only when concrete new evidence exposes an omission, repository
24
- conflict, or invalidated assumption. Ask the focused decision delta, cite the
25
- upstream `BR-*` item and new evidence when available, and preserve every
26
- unaffected decision. Resolve a local delta here; if its answer reopens multiple
27
- product branches or changes the overall goal or Scope, stop and return to
28
- `imm-brainstorm`.
29
-
30
- Direct Planner entry remains valid for clear requests. Resolve facts and derive
31
- technical design without a Brainstorm pass; if an unresolved user-owned product
32
- decision appears, return to `imm-brainstorm` instead of silently choosing it or
33
- starting a second exhaustive interview. A zero-question fast path is valid when
34
- no supplement is required. Present an unchanged result summary as a
35
- non-blocking correction window and do not ask the user to reconfirm existing
36
- decisions. If the summary itself introduces or changes a user decision, confirm
37
- only that decision delta before finalizing.
38
-
39
- Settlement-class intents (terminal settlement, cancellation, timeout, race, or
40
- authority-lifecycle semantics) must embed the `Settlement-Design Contract`
41
- enumeration required by the loaded contract before they are execution-ready.
42
-
43
- ## Technical Design Views And Decomposition
44
-
45
- For Medium and High Design Risk, select every materially relevant technical-design view from architecture layers, service/component interfaces, data flow, state transitions, and temporal sequence. Record a short `Design views` statement naming the selected views and why any omitted view cannot affect the design. The Spec is the single Technical Design baseline. Persist those decisions there; do not copy them into a TaskIntent or revive prose Plan authority. Low risk remains concise and is not forced to produce empty architecture, interface, data-flow, state, or sequence sections.
46
-
47
- Use the selected design boundaries as one TaskIntent decomposition dimension alongside outcome, Verification, dependency, risk, rollback, compatibility, and authority. Keep one TaskIntent when the selected views describe one coherent executable slice with shared acceptance, risk treatment, rollback, and authority. Split a successor TaskIntent only when a service, state-machine owner, migration, independently promotable layer, or sequence dependency needs independent verification, rollback, authorization, or settlement. Do not split merely because the design names several layers, files, or services.
48
-
49
- Treat trust-boundary changes as the same kind of decomposition evidence. A TaskIntent should normally change one primary trust-boundary invariant; merely traversing several boundaries or updating both sides of one end-to-end authority chain does not require a split. Split separate trust invariants when they can be independently verified, rolled back, authorized, migrated, or settled. Keep multiple trust-boundary changes together only when they form one atomic security outcome and splitting would create an unsafe or unusable intermediate state; record that reason in the Spec. This is Planner judgment, not a TaskIntent schema field or an Enrollment counting rule.
50
-
51
- ## Reference Closure Preflight
52
-
53
- Before authoring a TaskIntent, trace each expected behavior from its public or
54
- runtime entry point through existing imports and callers to the highest focused
55
- behavioral tests. Include generated or packaged mirrors and every owner of the
56
- same state machine. Record the concrete paths in the Spec's discovery evidence;
57
- do not author while a referenced sibling is unresolved. Use the smallest
58
- coherent module directory for ordinary implementation scope. Keep Kernel,
59
- authority, migration, secret, and security-sensitive scope exact to the files
60
- proved necessary by the trace. Scope is closed by reference evidence, not by an
61
- exhaustive filename guess.
62
-
63
- ## Managed Request Routing
64
-
65
- `imm-planner` is entered explicitly by the user for a clear repository mutation.
66
- Ordinary host input does not invoke this Skill through natural-language routing.
67
- An active Assurance projection remains authoritative and is resumed only through an explicit `imm-loop` entry; explicit Planner entry owns planning and the later native Enrollment gate:
68
- - an active Assurance projection remains on its current owner until the user explicitly enters `imm-loop`;
69
- - read-only, explanation, review-only, Plan-only, and explicit no-modification
70
- requests do not enroll;
71
- - materially ambiguous mutations go to `imm-brainstorm` before planning; and
72
- - clear new mutations reach this Planner phase.
73
-
74
- Plan-only output remains non-authoritative. Planner creates or validates a
75
- candidate Spec/TaskIntent, but it never enrolls a task or enrolls generated
76
- artifacts unconditionally. Explicit Plan-only requests stop after returning the
77
- planning artifacts. A later literal-user request to start Enrollment is a non-authoritative
78
- execution trigger: invoke the native Enrollment gate directly, without asking
79
- for chat pre-confirmation. For a clear mutation request that already includes
80
- execution, invoke that gate as soon as the candidate is validated and Git-tracked.
81
- Literal-user confirmation in the native gate remains the authority boundary.
82
- Fast-Track may compress the same phases but cannot bypass that boundary, QA,
83
- Review, authorization, or completion.
84
-
85
- ## Kernel TaskIntent Routing
86
-
87
- Before producing a new managed planning artifact, resolve the canonical wrappers
88
- from the declared Skill location: `../../bin/imm-plan` and
89
- `../../bin/imm-kernel`. Invoke `imm-plan --routing-status --json` through that
90
- resolved wrapper and use the resolved `imm-kernel` wrapper for every Kernel
91
- command below. Do not assume either bare command is available on shell `PATH`.
92
- Then route deterministically:
93
-
94
- - an active Kernel claim routes to `imm-loop` for foreground Kernel Tool
95
- coordination, not new planning;
96
- - an active or otherwise nonterminal v3 Plan remains on its existing v3 route;
97
- - no routing policy preserves the legacy v3 Planner behavior;
98
- - a valid `kernel_task_intent` retirement policy produces one TaskIntent draft
99
- through Pi `imm-planner`;
100
- - an invalid, unreadable, untracked, or tracked-deleted policy rejects new
101
- planning authority with `routing_policy_invalid`;
102
- - no Planner path enrolls a task or falls back to v3 after retirement.
103
-
104
- Current owner, phase, completion, and authority facts are authoritative only
105
- when read from the Assurance projection and TaskRecord. `CONTEXT.md` is
106
- non-authoritative vocabulary and architecture navigation, not a workflow-status
107
- source. If its prose conflicts with those authority facts, report stale
108
- documentation, preserve projection-based routing, and do not automatically
109
- synchronize either representation.
110
-
111
- Pi host identity is implicit and never a planning input. The production boundary
112
- that turns a Git-tracked TaskIntent draft into managed execution authority is the
113
- native host TUI: the Planner's final `ctx.ui.custom` gate (via the
114
- `imm_canary_enrollment` foreground Tool) provides one literal-user confirmation
115
- bound to the TaskIntent content hash. Invoke the Tool directly when the route is
116
- ready; do not ask for a chat pre-confirmation. Enrollment validates the intent,
117
- Git ownership, scope, workspace claim, and final authority preconditions without
118
- executing acceptance descriptors. A routine task proceeds from that single
119
- confirmation through enrollment, execution and QA without a second human stop.
120
-
121
- The Planner never writes the `docs/plans/<task-id>.intent.json` artifact
122
- directly and never overwrites an existing TaskIntent. Under an active
123
- `kernel_task_intent` policy it supplies one complete candidate to the canonical
124
- `imm-kernel intent author <path> --stdin --json` command, which owns strict
125
- parsing, verification-descriptor canonicalization, path binding, and exclusive
126
- file creation; then it validates the created artifact with
127
- `imm-kernel intent validate <path> --json`. Revisions of an enrolled intent
128
- continue through Kernel `revise_intent` authority and are not a Planner
129
- overwrite path.
130
-
131
- ### Initiative Carrier Preference
132
-
133
- For a large proposal split across multiple TaskIntents, exactly one planning
134
- carrier is chosen per Initiative: a Local Markdown file at
135
- `docs/initiatives/<slug>.md` or one GitHub Parent Issue. This preference applies
136
- only to Initiatives; ordinary TaskIntents remain tracked by Kernel TaskRecords.
137
- Resolve the carrier in this order:
138
-
139
- 1. a literal user instruction for the current request;
140
- 2. `Initiative carrier default: local` or `Initiative carrier default: github`
141
- in the repository root `AGENTS.md`;
142
- 3. the same directive in `~/.pi/agent/AGENTS.md`; or
143
- 4. ask the user when no valid directive exists.
144
-
145
- A repository directive overrides the global directive. Report an invalid value
146
- and ask instead of guessing. After resolving it, display one non-blocking line
147
- with the selected carrier and its source. A configured `github` default is
148
- standing opt-in for GitHub projection, but the literal user must still confirm
149
- the named Initiative, its immutable slug, and the complete Parent/Child
150
- decomposition before the first remote mutation. A prior bulk approval cannot
151
- confirm a name, slug, Child, or dependency that had not yet been shown.
152
-
153
- Once decomposition is complete, present one review table containing the Parent
154
- result and every Child's stable Slice ID, result, scope boundary, risk, blockers,
155
- and proposed execution order. Ask one focused question: whether the coverage,
156
- granularity, and dependencies are correct. Recommend the complete current
157
- frontier so the user can approve it in one response. Before that approval,
158
- perform zero GitHub mutations. A partial or progressively disclosed issue set is
159
- not eligible for publication.
160
-
161
- After approval, author, stage, and validate every TaskIntent in the decomposition
162
- with `valid: true` and `enrollment_ready: true`. Resolve `../../bin/imm-tracker` from this Skill location; do not assume a bare command is on `PATH`. Submit the entire approved set once through
163
- `imm-tracker publish-initiative --stdin --json`. Its input contains the confirmed
164
- Initiative slug and goal, Parent projection, and every Child's `slice_id`,
165
- canonical TaskIntent path, and public projection. The Parent projection requires
166
- `problem`, `result`, and `design`, and may include `decisions`,
167
- `testing_strategy`, and `out_of_scope`. `design` records Initiative-level
168
- invariants, Slice boundaries and ordering, shared interfaces or state flow, and
169
- material compatibility decisions. Every Parent Slice must correspond to one
170
- published Child; future checklist-only Slices are not allowed in the batch.
171
-
172
- Each Child projection may contain `result`, `current_behavior`,
173
- `desired_behavior`, `key_interfaces`, `verification`, `blocked_by` Task IDs,
174
- `out_of_scope`, and `agent_handoff`. The tracker rereads every canonical
175
- TaskIntent for identity, risk, and acceptance; projection fields never widen
176
- TaskIntent scope or authority. It validates the complete dependency graph before
177
- remote writes, creates the Parent once, creates all Children, attaches every
178
- Child as a native Sub-issue, creates native `blocked_by` relations, and rereads
179
- the complete topology. The Child Agent Brief includes a direct Parent Issue link.
180
- Internal role prompts, tool policies, review gates, model reservations, and
181
- prompt digests never belong in this external handoff. If
182
- `docs/initiatives/<slug>.md` exists, publication fails with a carrier conflict;
183
- Local mode performs zero GitHub operations.
184
-
185
- The batch result includes an execution recommendation: the first unblocked Task,
186
- a stable dependency order, and parallel groups. For a plan-only request, report
187
- that recommendation and stop. For a request that includes execution, invoke the
188
- native Enrollment gate for the recommended first TaskIntent after successful
189
- publication; do not ask for another chat confirmation. GitHub selection never
190
- bypasses Enrollment.
191
-
192
- Tracker output is observation, never authority. Before the Planner returns, its
193
- GitHub carrier outcome must be exactly one of: `tracker_associated` after the
194
- complete batch returns `created`, `updated`, or `already_current`;
195
- `awaiting_user_initiative_confirmation` with the single pending name, slug, and
196
- complete-decomposition decision; or `tracker_projection_failed` with the returned
197
- failure and exact retry action. A candidate Initiative or partial Issue set
198
- recorded only in the Spec or final summary is neither user confirmation nor a
199
- completed carrier outcome. Report `retryable_failure`, `permanent_failure`, or
200
- `ambiguous_remote_state` and the exact batch retry action. This does not invalidate
201
- already-authored planning files, but it blocks `tracker_associated` and every
202
- Enrollment or execution handoff for that Initiative until the same complete
203
- batch succeeds. Do not infer opt-in from tracker output or Issue state, auto-close the Parent,
204
- import Issue state, create a TaskIntent from an Issue, or store Issue identity in
205
- TaskIntent or TaskRecord. Existing Issue markers grant permission only for
206
- idempotent retry of that same approved Initiative; they never grant execution
207
- authority.
208
-
209
- ### Verification Descriptor Discipline
210
-
211
- Every acceptance verification descriptor must be a focused, deterministic,
212
- repository-local check that exercises only its acceptance assertion. Prefer one
213
- small `bun test <focused-file>` or `bun run <focused-script>` per acceptance;
214
- never use the full test suite, a build, package installation, network access, or
215
- redundant heavyweight checks. Prefer the highest existing observable behavioral
216
- test seam and the fewest sufficient seams. Cite relevant test prior art and
217
- explain how the selected seam catches the intended regression. This is a
218
- planning heuristic: it must not weaken acceptance-specific focused verification
219
- descriptors or add a mandatory user confirmation. Use the smallest `timeout_ms` and
220
- `max_output_bytes` that cover deterministic post-implementation QA.
221
-
222
- ## Retirement Completion Contract
223
-
224
- For retirement-class work, deletion of source and contract text is a completion condition. A retirement that routes the command to a retirement wall, pins the absence with test assertions, and leaves the source in the tree is not complete. A retirement is not complete until the source and its contract text are deleted.
225
-
226
- An absence test is transitional scaffolding proving an in-progress deletion rather than a substitute for one. An absence test is transitional evidence of an in-progress deletion and may not stand in place of one. It proves a deletion in progress, not a completed result. Distinguish an absence assertion that guards something already gone, which is durable and correct, from one that stands in for a deletion still owed, which is a promise recorded as if it were a result.
227
- Architecture exploration and advisory review use the internal Loop bridge's
228
- read-only `arch-explorer` and `advisory-reviewer` roles. They can supply
229
- candidates, evidence, and decision criteria, but cannot write this Spec/Plan or
230
- activate execution.
231
- Agreement becomes evidence, Disagreement becomes decision criteria, and
232
- strong-model blockers become risks or verification requirements.
8
+ Load [`../../dist/imm-planner.md`](../../dist/imm-planner.md), then follow that
9
+ canonical contract. `mode: page_design` selects its page-design branch.