immune-brain 4.0.1 → 4.2.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 CHANGED
@@ -198,29 +198,55 @@ The three repair/maintenance skills are host-native: they never create a managed
198
198
 
199
199
  ## Lifecycle
200
200
 
201
+ ```mermaid
202
+ flowchart TD
203
+ subgraph Planning ["1. Planning Phase"]
204
+ B["imm-brainstorm<br/>Clarify Requirements & Constraints"] --> P["imm-planner<br/>Author Spec & TaskIntent"]
205
+ P --> TI["TaskIntent (.intent.json)<br/>• goal / scope_hint<br/>• risk tier<br/>• acceptance descriptors"]
206
+ end
207
+
208
+ subgraph Enrollment ["2. Enrollment Gate"]
209
+ TI --> EG{"Native User Gate<br/>Host Modal Confirmation"}
210
+ EG -->|Confirm| KS[(".imm/state/kernel.sqlite<br/>Atomic TaskRecord<br/>Exclusive Workspace Claim")]
211
+ end
212
+
213
+ subgraph Loop ["3. Execution & Assurance Loop (imm-loop)"]
214
+ KS --> EX["Executor Role<br/>Edit code strictly inside scope_hint"]
215
+ EX --> FRZ["advance_assurance<br/>Artifacts frozen (active:frozen)"]
216
+ FRZ --> QA["Deterministic QA Engine<br/>Run acceptance verification commands<br/>Generate QA Attestation"]
217
+
218
+ QA -->|Fail| RW1["Rework / Fix"]
219
+ RW1 --> EX
220
+
221
+ QA -->|Pass| RK{"Risk Tier?"}
222
+ RK -->|routine| ST["Settlement"]
223
+ RK -->|material / critical| RV["Review Role<br/>Structured verdict (Pass / Rework)"]
224
+
225
+ RV -->|Rework| RW2["Rework"]
226
+ RW2 --> EX
227
+ RV -->|Pass| ST
228
+ end
229
+
230
+ subgraph Settlement ["4. Settlement & Learnings"]
231
+ ST --> CLS["Atomic Closure<br/>• Lifecycle: done<br/>• Audit evidence in .imm/audit/<br/>• Release Workspace Claim"]
232
+ CLS -.-> CP["Compounder Role<br/>Extract Learnings to docs/solutions/"]
233
+ end
201
234
  ```
202
- Ordinary request: normal coding / Q&A (Host-native, zero overhead)
203
- │
204
- Explicit skill call (/imm-brainstorm or /imm-planner)
205
- │
206
- ┌──────────────┴──────────────┐
207
- ▼ ▼
208
- imm-brainstorm imm-planner
209
- (clarify requirements, (author Spec + TaskIntent,
210
- read-only framing) define acceptance checks)
211
- │ │
212
- └──────────────┬──────────────┘
213
- ▼
214
- Native Host Confirmation
215
- (Pi TUI dialog / Claude MCP elicitation)
216
- │
217
- ▼
218
- imm-loop
219
- ├── Executor (edits strictly inside scope)
220
- ├── Deterministic QA (runs all acceptance checks)
221
- ├── Isolated Review (independent subagent audit)
222
- └── Settled (.imm/audit/<task-id>/)
223
- ```
235
+
236
+ ### Core Logic: Three Pillars
237
+
238
+ 1. **Two Paths**
239
+ - **Host-native Path**: Daily conversation, code inspections, and ad-hoc fixes stay 100% native with zero workflow overhead.
240
+ - **Managed Path**: Explicitly entered via `imm-brainstorm`, `imm-planner`, or `imm-loop`, strictly governed by the Assurance Kernel.
241
+
242
+ 2. **Authority & Contract**
243
+ - **TaskIntent (`.intent.json`)**: Machine-readable behavioral contract locking `scope_hint` (file boundaries), `risk` tier, and `acceptance` descriptors.
244
+ - **Native Gate (Enrollment)**: The single human-authority confirmation gate; Kernel atomically acquires exclusive workspace ownership (`.imm/state/kernel.sqlite` CAS) to prevent concurrency conflicts and scope drift.
245
+
246
+ 3. **Deterministic Assurance**
247
+ - **QA-First**: The Kernel directly runs verification commands and checks exit codes/byte bounds; never relies on conversational claims.
248
+ - **Risk-Tiered Gates**: `routine` tasks complete upon QA pass; `material` and `critical` tasks require an isolated Review subagent to issue a structured verdict.
249
+ - **Unattended Batch**: Serial execution driven by GitHub Issues and bound by `plan_digest`, where each child independently completes its own Enrollment → QA → Review → Commit cycle.
224
250
 
225
251
  Key invariants:
226
252
 
package/README.zh-CN.md CHANGED
@@ -198,29 +198,55 @@ Executor、QA、Review、Compounder 等为 `imm-loop` 内部调度的角色,
198
198
 
199
199
  ## 生命周期
200
200
 
201
+ ```mermaid
202
+ flowchart TD
203
+ subgraph Planning ["1. 规划阶段"]
204
+ B["imm-brainstorm<br/>需求澄清/约束"] --> P["imm-planner<br/>编写 Spec & TaskIntent"]
205
+ P --> TI["TaskIntent (.intent.json)<br/>• goal / scope_hint<br/>• risk tier<br/>• acceptance descriptors"]
206
+ end
207
+
208
+ subgraph Enrollment ["2. 准入登记"]
209
+ TI --> EG{"Native User Gate<br/>当前 Host 弹窗确认"}
210
+ EG -->|确认| KS[(".imm/state/kernel.sqlite<br/>原子生成 TaskRecord<br/>独占 Workspace Claim")]
211
+ end
212
+
213
+ subgraph Loop ["3. 执行与验证循环 (imm-loop)"]
214
+ KS --> EX["Executor 角色<br/>在 scope_hint 范围内修改代码"]
215
+ EX --> FRZ["advance_assurance<br/>制品冻结 (active:frozen)"]
216
+ FRZ --> QA["确定性 QA 引擎<br/>原子运行 acceptance 校验命令<br/>生成 QA Attestation"]
217
+
218
+ QA -->|失败| RW1["Rework 返工修正"]
219
+ RW1 --> EX
220
+
221
+ QA -->|通过| RK{"Risk 等级?"}
222
+ RK -->|routine| ST["Settlement 结算"]
223
+ RK -->|material / critical| RV["Review 审查角色<br/>结构化裁决 (Pass / Rework)"]
224
+
225
+ RV -->|Rework| RW2["Rework 驳回"]
226
+ RW2 --> EX
227
+ RV -->|Pass| ST
228
+ end
229
+
230
+ subgraph Settlement ["4. 结算与沉淀"]
231
+ ST --> CLS["原子结项<br/>• Lifecycle: done<br/>• 写入审计日志 .imm/audit/<br/>• 释放 Workspace Claim"]
232
+ CLS -.-> CP["Compounder 角色<br/>提取经验至 docs/solutions/"]
233
+ end
201
234
  ```
202
- 普通请求:日常编程 / 问答(Host-native,零流程开销)
203
- │
204
- 显式调用 Skill(/imm-brainstorm 或 /imm-planner)
205
- │
206
- ┌──────────────┴──────────────┐
207
- ▼ ▼
208
- imm-brainstorm imm-planner
209
- (澄清需求、约束与风险, (编写 Spec + TaskIntent,
210
- 只读输出 framing) 定义可自动化验证的验收条件)
211
- │ │
212
- └──────────────┬──────────────┘
213
- ▼
214
- 当前 Host 原生确认
215
- (Pi TUI 弹窗 / Claude MCP elicitation)
216
- │
217
- ▼
218
- imm-loop
219
- ├── Executor(严格在 scope 内修改代码)
220
- ├── 确定性 QA(前台逐项执行验收命令)
221
- ├── 隔离式 Review(独立 subagent 审查代码)
222
- └── 落盘结算(.imm/audit/<task-id>/)
223
- ```
235
+
236
+ ### 核心逻辑三要素
237
+
238
+ 1. **双轨制 (Two Paths)**
239
+ - **Host-native Path**:日常对话、代码检视、单点修改,不触碰 Kernel 权限,零流程开销。
240
+ - **Managed Path**:由 `imm-brainstorm` / `imm-planner` / `imm-loop` 显式驱动,全程受 Kernel 约束。
241
+
242
+ 2. **权限与契约 (Authority & Contract)**
243
+ - **TaskIntent (`.intent.json`)**:机器契约本体,严格锁定 `scope_hint`(文件修改范围)、`risk`(风险层级)与 `acceptance`(确定性断言)。
244
+ - **Native Gate (Enrollment)**:唯一一次人工介入确认,Kernel 原子抢占工作区所有权(SQLite CAS),防止多任务并发冲突与范围漂移。
245
+
246
+ 3. **客观验证 (Deterministic Assurance)**
247
+ - **QA 优先**:由 Kernel 直接前台执行命令并校验退出码/输出,不依赖 LLM 口头汇报。
248
+ - **按险定级**:`routine` 仅需 QA;`material`/`critical` 必须追加独立只读 Reviewer 产出结构化裁决。
249
+ - **批处理 (Unattended Batch)**:基于 GitHub Issue / `plan_digest` 串行推进,每个子任务独立走完 Enrollment → QA → Review → Commit 闭环。
224
250
 
225
251
  核心不变量:
226
252
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "immune-brain",
3
- "version": "4.0.1",
3
+ "version": "4.2.0",
4
4
  "description": "Immune-Brain agent skill system",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "immune-brain",
3
- "version": "4.0.1",
3
+ "version": "4.2.0",
4
4
  "description": "Immune-Brain Claude Code Host: native Enrollment, QA, Review, and Kernel settlement.",
5
5
  "author": {
6
6
  "name": "Immune-Brain Team"
@@ -37,6 +37,10 @@ import {
37
37
  type UserAttentionReason,
38
38
  } from "./pi-canary-interaction";
39
39
  import { isToolFailureState, throwToolFailure } from "./pi-canary-tool-failure";
40
+ import { resolveUxLanguage, uxText } from "./ux-language";
41
+
42
+ /** Host-native UI language; see ux-language.ts. Resolved once per process. */
43
+ const UX_LANG = resolveUxLanguage();
40
44
 
41
45
  const TASK_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
42
46
 
@@ -62,7 +66,7 @@ async function requestEnrollmentConfirmation(
62
66
  task_id: taskId,
63
67
  state: "Approval required",
64
68
  result: title,
65
- next: "Review enrollment evidence",
69
+ next: uxText(UX_LANG, "Review enrollment evidence", "请审查 Enrollment 证据"),
66
70
  });
67
71
  const selected = await requestAuthorityDialog(pi, ctx, {
68
72
  attention_id: randomUUID(),
@@ -75,8 +79,8 @@ async function requestEnrollmentConfirmation(
75
79
  details,
76
80
  signal,
77
81
  actions: [
78
- { value: "confirm", label: "Confirm enrollment", description: "Create the Kernel-managed task" },
79
- { value: "cancel", label: "Cancel", description: "Leave planning artifacts and authority unchanged" },
82
+ { value: "confirm", label: uxText(UX_LANG, "Confirm enrollment", "确认 Enrollment"), description: uxText(UX_LANG, "Create the Kernel-managed task", "创建 Kernel 托管任务") },
83
+ { value: "cancel", label: uxText(UX_LANG, "Cancel", "取消"), description: uxText(UX_LANG, "Leave planning artifacts and authority unchanged", "不改动规划产物与权限状态") },
80
84
  ],
81
85
  });
82
86
  return selected === "confirm";
@@ -305,7 +309,7 @@ async function executeForegroundEnrollment(
305
309
 
306
310
  try {
307
311
  signal.throwIfAborted();
308
- progress("preparing", `Preparing immutable Kernel owners for ${taskId}`);
312
+ progress("preparing", uxText(UX_LANG, `Preparing immutable Kernel owners for ${taskId}`, `正在为 ${taskId} 准备不可变 Kernel 所有者`));
309
313
  const now = new Date().toISOString();
310
314
  let taskIntent: Awaited<ReturnType<typeof readTaskIntent>>;
311
315
 
@@ -489,13 +493,13 @@ async function executeForegroundEnrollment(
489
493
  `Owners: intent+workspace+claim+record checked`,
490
494
  `Route: Kernel enrollment`,
491
495
  ].join("\n");
492
- progress("awaiting_confirmation", "Waiting for exact literal-user confirmation");
496
+ progress("awaiting_confirmation", uxText(UX_LANG, "Waiting for exact literal-user confirmation", "等待本人确认"));
493
497
  const confirmed = await requestEnrollmentConfirmation(
494
498
  pi,
495
499
  ctx,
496
500
  taskId,
497
501
  "enrollment",
498
- "Create Kernel-managed task?",
502
+ uxText(UX_LANG, "Create Kernel-managed task?", "创建 Kernel 托管任务?"),
499
503
  confirmationSummary,
500
504
  confirmationDetails,
501
505
  signal,
@@ -526,7 +530,7 @@ async function executeForegroundEnrollment(
526
530
  return terminal(action, taskId, "blocked", stage, "Intent changed after confirmation; enrollment aborted before authority", "restore the intended snapshot and rerun enrollment");
527
531
  }
528
532
 
529
- progress("revalidating", "Revalidating immutable owners and the confirmed TaskIntent");
533
+ progress("revalidating", uxText(UX_LANG, "Revalidating immutable owners and the confirmed TaskIntent", "正在重新校验不可变所有者与已确认的 TaskIntent"));
530
534
  const { unchanged } = await revalidatePiCanary(root, { task_id: taskId, now }, preparation);
531
535
  if (!unchanged)
532
536
  return terminal(action, taskId, "blocked", stage, "Workspace changed after confirmation; enrollment aborted before authority", "restore the intended snapshot and rerun enrollment");
@@ -555,7 +559,7 @@ async function executeForegroundEnrollment(
555
559
  now,
556
560
  };
557
561
 
558
- progress("rehearsing", "Running the zero-write Kernel owner rehearsal");
562
+ progress("rehearsing", uxText(UX_LANG, "Running the zero-write Kernel owner rehearsal", "正在执行 Kernel 所有者零写入预演"));
559
563
  const rehearsal = await runEnrollmentRehearsal(root, input, capability, registry);
560
564
  if (!rehearsal.rehearsed || rehearsal.evidence.outcome !== "ready")
561
565
  return terminal(action, taskId, "failed", stage, `Kernel enrollment rehearsal failed: ${rehearsal.evidence.blockers.join("; ")}`, "resolve the final-lock preconditions and retry");
@@ -65,6 +65,10 @@ import {
65
65
  type UserAttentionReason,
66
66
  } from "./pi-canary-interaction";
67
67
  import { isToolFailureState, throwToolFailure, type ToolFailureV1 } from "./pi-canary-tool-failure";
68
+ import { resolveUxLanguage, uxText } from "./ux-language";
69
+
70
+ /** Host-native UI language; see ux-language.ts. Resolved once per process. */
71
+ const UX_LANG = resolveUxLanguage();
68
72
  import { taskDiffIdentity, taskRevisionIdentity, captureGitTaskSnapshot } from "../runtime/workspace_scope";
69
73
  import { reviewAdvisoryRecords, reviewReworkFindings } from "../runtime/assurance/coordinator";
70
74
  import {
@@ -323,7 +327,7 @@ export default function (
323
327
  task_id: claim.task_id,
324
328
  state: "Blocked",
325
329
  result: projection.error,
326
- next: "Inspect authority state",
330
+ next: uxText(UX_LANG, "Inspect authority state", "检查权限状态"),
327
331
  });
328
332
  return;
329
333
  }
@@ -395,8 +399,8 @@ export default function (
395
399
  if (input?.task_id) presentTaskRail(ctx, {
396
400
  task_id: input.task_id,
397
401
  state: "Planning",
398
- result: "Preparing enrollment",
399
- next: "Review the native enrollment decision",
402
+ result: uxText(UX_LANG, "Preparing enrollment", "正在准备 Enrollment"),
403
+ next: uxText(UX_LANG, "Review the native enrollment decision", "请审查原生 Enrollment 决策"),
400
404
  });
401
405
  }
402
406
  });
@@ -584,11 +588,12 @@ export default function (
584
588
  }
585
589
  const projection = await projectAssuranceState(ctx.cwd, taskId);
586
590
  if (projection.error) {
591
+ const nextAction = recoveryActionForAssuranceFailure(projection.error) ?? "inspect authority state";
587
592
  const details = {
588
593
  state: "blocked",
589
594
  operation: action.op,
590
595
  result: projection.error,
591
- next_action: "inspect authority state",
596
+ next_action: nextAction,
592
597
  };
593
598
  presentTaskRailResult(ctx, taskId, details);
594
599
  return failCanaryTool(taskId, action.op, "blocked", "projection_unavailable", projection.error, details.next_action);
@@ -871,24 +876,24 @@ export default function (
871
876
  presentTaskRail(ctx, {
872
877
  task_id: taskId,
873
878
  state: "Approval required",
874
- result: `${operation} requires your confirmation`,
875
- next: `Decide ${operation}`,
879
+ result: uxText(UX_LANG, `${operation} requires your confirmation`, `${operation} 需要您的确认`),
880
+ next: uxText(UX_LANG, `Decide ${operation}`, `请决策 ${operation}`),
876
881
  });
877
882
  const attention = {
878
883
  attention_id: randomUUID(),
879
884
  task_id: taskId,
880
885
  reason: attentionReason,
881
- label: `${operation} approval required`,
886
+ label: uxText(UX_LANG, `${operation} approval required`, `${operation} 待您批准`),
882
887
  };
883
888
  try {
884
889
  const selected = await requestAuthorityDialog(pi, ctx, attention, {
885
- title: `Authorize ${operation}?`,
890
+ title: uxText(UX_LANG, `Authorize ${operation}?`, `是否批准 ${operation}?`),
886
891
  summary: dialogSummary,
887
892
  details: dialogDetails,
888
893
  signal: ctx.signal,
889
894
  actions: [
890
- { value: "authorize", label: "Authorize", description: `Apply ${operation} after re-checking state` },
891
- { value: "cancel", label: "Cancel", description: "Leave managed authority unchanged" },
895
+ { value: "authorize", label: uxText(UX_LANG, "Authorize", "批准"), description: uxText(UX_LANG, `Apply ${operation} after re-checking state`, `重新校验状态后应用 ${operation}`) },
896
+ { value: "cancel", label: uxText(UX_LANG, "Cancel", "取消"), description: uxText(UX_LANG, "Leave managed authority unchanged", "保持托管权限状态不变") },
892
897
  ],
893
898
  });
894
899
  confirmed = selected === "authorize";
@@ -1532,7 +1537,7 @@ async function buildAssuranceSnapshot(
1532
1537
  })
1533
1538
  : null;
1534
1539
  const taskSnapshot = !reviewBundle && !reviewManifest
1535
- ? captureGitTaskSnapshot(root, intent.scope_hint)
1540
+ ? captureGitTaskSnapshot(root, intent.scope_hint, taskId)
1536
1541
  : null;
1537
1542
  const dirtyFiles = reviewManifest
1538
1543
  ? Object.keys(reviewManifest.changed_paths)
@@ -1756,6 +1761,10 @@ async function enrichAssuranceResult(
1756
1761
  }
1757
1762
 
1758
1763
  function nextActionForAssuranceResult(result: Record<string, unknown>, taskState: AssuranceTaskState): string {
1764
+ const recovery = recoveryActionForAssuranceFailure(
1765
+ "error" in taskState ? taskState.error : result.reason,
1766
+ );
1767
+ if (recovery) return recovery;
1759
1768
  if ("error" in taskState) return "inspect authority state";
1760
1769
  if (result.state === "review_preparation_failed") return "repair Review preparation, then retry advance_assurance; QA is already committed";
1761
1770
  if (result.code === "verdict_invalid") return "fix the verdict payload and resubmit submit_review; the Review reservation remains active; do not re-dispatch the reviewer";
@@ -1775,6 +1784,17 @@ function nextActionForAssuranceResult(result: Record<string, unknown>, taskState
1775
1784
  }
1776
1785
  }
1777
1786
 
1787
+ function recoveryActionForAssuranceFailure(reason: unknown): string | null {
1788
+ if (typeof reason !== "string") return null;
1789
+ if (reason.includes("task scope contains unstaged or untracked changes:"))
1790
+ return "stage only the listed task-owned paths, then retry the blocked operation";
1791
+ if (reason.includes("QA resolution failed ("))
1792
+ return "repair the verification command or delivery environment, then retry advance_assurance";
1793
+ if (reason.includes("task delivery contains paths outside the authorization envelope:"))
1794
+ return "reconcile the listed paths: unstage unrelated paths or revise TaskIntent scope for task-owned paths, then retry advance_assurance";
1795
+ return null;
1796
+ }
1797
+
1778
1798
  function toolResult(text: string, details?: Record<string, unknown>) {
1779
1799
  return { content: [{ type: "text" as const, text }], details };
1780
1800
  }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Host-native UI language for Immune-Brain TUI text (Task Rail sentences,
3
+ * authority dialog titles/actions, progress summaries). This layer is
4
+ * deterministic extension code, so conversational AGENTS.md reply-language
5
+ * rules cannot reach it; users opt in with IMM_UX_LANGUAGE (for example
6
+ * `zh`). Anything unrecognized keeps English, the published default.
7
+ *
8
+ * Boundary: only sentence-level interaction text follows this setting.
9
+ * Machine contracts and domain terms (state enums, operation ids, Task /
10
+ * Intent / Claim / Acceptance field labels, hashes, paths, CLI commands)
11
+ * always stay literal, as do agent-facing Tool result reasons and
12
+ * diagnostic notifications.
13
+ */
14
+ export type UxLanguage = "en" | "zh";
15
+
16
+ export function resolveUxLanguage(
17
+ env: Readonly<Record<string, string | undefined>> = process.env,
18
+ ): UxLanguage {
19
+ const raw = env.IMM_UX_LANGUAGE?.trim().toLowerCase();
20
+ if (raw === "zh" || raw === "zh-cn" || raw === "zh-tw" || raw === "chinese" || raw === "中文")
21
+ return "zh";
22
+ return "en";
23
+ }
24
+
25
+ /** Pick the interaction sentence for the resolved language. */
26
+ export function uxText(lang: UxLanguage, en: string, zh: string): string {
27
+ return lang === "zh" ? zh : en;
28
+ }
@@ -6,7 +6,9 @@
6
6
  from `dist/`; nested modes, examples, recovery, and references load on demand.
7
7
  - Ask only when missing information would change the goal, scope, observable behavior, compatibility, risk acceptance, a protected effect, or a fact only the user can supply. Resolve repository facts and delegated technical choices with bounded evidence instead of asking.
8
8
  - Keep edits inside the user-requested Direct scope or the enrolled TaskIntent acceptance and `scope_hint`.
9
- - Stage only explicit task-owned paths. Never use `git add .` or `git add -A` in a dirty worktree.
9
+ - Stage only explicit task-owned paths. This staging authority does not grant
10
+ commit, push, broad staging, or authority over pre-existing user changes.
11
+ Never use `git add .` or `git add -A` in a dirty worktree.
10
12
  - Do not create, switch, or delete Git worktrees; operate only in the Host launch directory.
11
13
  - Record reproducible evidence before reporting closure.
12
14
  - Required verification must pass before reporting completion; disclosing a gap is not a substitute. Autonomously diagnose, repair, and rerun failing conventional local checks within the authorized scope; never delete, skip, or weaken a valid check to manufacture a pass. If a required check remains failing or cannot run, report the work as incomplete with the concrete blocker.
@@ -46,7 +48,9 @@ routing. A new Managed workflow starts only from explicit `imm-brainstorm`,
46
48
  Managed owner remains authoritative; the user resumes it with `imm-loop`.
47
49
  2. **Start explicitly**: the selected Immune-Brain Skill owns its planning or
48
50
  coordination work. It creates only requested artifacts and their required
49
- parent directories; it does not install project-wide contract files.
51
+ parent directories. Explicit Planner entry also owns absent routing-policy
52
+ activation under Planner's Kernel TaskIntent Routing section;
53
+ it does not otherwise install project-wide contract files.
50
54
  3. **Preserve authority**: Planner output is a candidate for later literal-user
51
55
  Enrollment, and Fast-Track preserves TaskIntent scope, Enrollment, QA,
52
56
  Review, authorization, and completion boundaries.
@@ -124,6 +128,17 @@ always run sequentially.
124
128
  - Do not translate or rename machine contracts: schema fields, enum values,
125
129
  CLI flags, JSON keys, file paths, tool names, API names,
126
130
  and code identifiers stay literal.
131
+ - Host-native UI text (Task Rail sentences, authority dialog titles and
132
+ actions, enrollment progress summaries) is deterministic extension code and
133
+ cannot follow conversational rules; users localize it with the
134
+ `IMM_UX_LANGUAGE` environment variable (for example `IMM_UX_LANGUAGE=zh`).
135
+ Only sentence-level interaction text follows it; machine contracts, domain
136
+ field labels, and agent-facing Tool result reasons stay literal English.
137
+ - Internal role dispatches (`dispatch_role` and routed role contexts) carry
138
+ the user-facing interaction language as `interaction_language` in the
139
+ delegation context, so QA/Review/Explorer roles report in the user's
140
+ language while keeping machine contracts literal. Omit it to keep English
141
+ role output.
127
142
  - Preserve `CONTEXT.md` canonical terms such as `Step`, `Plan`, `Spec`,
128
143
  `Skill`, `Brainstorm`, `Executor`, `QA`, `Compounder`, `Learning`, and `ADR`;
129
144
  add local-language explanations around them when helpful.
@@ -39,7 +39,7 @@ function probeHost(env = process.env, platform = process.platform, hostVersion)
39
39
  }
40
40
 
41
41
  // plugins/immune-brain/runtime/plugin_version.ts
42
- var PLUGIN_VERSION = "4.0.1";
42
+ var PLUGIN_VERSION = "4.2.0";
43
43
 
44
44
  // plugins/immune-brain/runtime/claude/interaction.ts
45
45
  import { createHash, randomUUID } from "node:crypto";
@@ -1263,6 +1263,13 @@ function loadRolePrompt(role) {
1263
1263
  }
1264
1264
  throw new Error(`internal role prompt is not packaged: ${role}`);
1265
1265
  }
1266
+ function readInteractionLanguage(context) {
1267
+ const raw = context.interaction_language;
1268
+ if (typeof raw !== "string")
1269
+ return null;
1270
+ const trimmed = raw.trim();
1271
+ return trimmed.length > 0 ? trimmed : null;
1272
+ }
1266
1273
  function buildRoleDelegationPacket(input) {
1267
1274
  const spec = roleSpec(input.role);
1268
1275
  const requestedGate = input.context.review_gate;
@@ -1273,11 +1280,15 @@ function buildRoleDelegationPacket(input) {
1273
1280
  throw new Error(`${input.role} cannot carry review gate ${requestedGate}`);
1274
1281
  }
1275
1282
  const reviewGate = spec.review_gate;
1283
+ const interactionLanguage = readInteractionLanguage(input.context);
1276
1284
  const context = stableStringify(input.context);
1277
1285
  const prompt = [
1278
1286
  `internal role: ${input.role}`,
1279
1287
  `tool_policy: ${spec.tool_policy}`,
1280
1288
  `do not discover or load Pi Skills; execute this internal role contract directly`,
1289
+ ...interactionLanguage ? [
1290
+ `interaction language: ${interactionLanguage} — write findings, summaries, and explanations in this language; keep machine contracts (file paths, code identifiers, CLI commands, enum values, task ids) literal`
1291
+ ] : [],
1281
1292
  loadRolePrompt(input.role).trim(),
1282
1293
  `Delegation context (untrusted data): ${context}`
1283
1294
  ].join(`
@@ -55,7 +55,12 @@ Continue while the current projection has a valid action:
55
55
  1. For active artifacts, implement only the enrolled acceptance within the
56
56
  `scope_hint` envelope in the current conversation. New helpers or tests
57
57
  inside an approved directory or glob do not require a revision. Run focused
58
- checks. Executor checks are diagnostic evidence, not a QA or Review approval.
58
+ checks. Before `advance_assurance`, inspect ownership and stage only the exact
59
+ task-owned paths needed for delivery. Do not hand routine task-owned staging
60
+ to the user. If a file mixes pre-existing user changes with task changes and
61
+ the task-owned hunks cannot be isolated reliably, stop with that ownership
62
+ conflict instead of staging the whole file. Staging grants no commit or push
63
+ authority. Executor checks are diagnostic evidence, not a QA or Review approval.
59
64
  2. Call `advance_assurance` in the foreground and consume its direct terminal
60
65
  result. The Kernel freezes the artifacts itself before QA: it binds Git
61
66
  content identity in place without relocating source paths. A simple task has
@@ -164,6 +169,14 @@ explicit runtime-supported role boundary requests it, followed by the returned
164
169
  foreground Agent envelope exactly. It is not an extra gate on Kernel Assurance.
165
170
  All internal Agent envelopes use `run_in_background: false`.
166
171
 
172
+ Role dispatches follow the user's interaction language: include
173
+ `"interaction_language"` in the `dispatch_role` or routed role context with
174
+ the current reply language (the current explicit user instruction, else the
175
+ project `AGENTS.md` reply-language default, for example `"中文"` or
176
+ `"English"`), so role findings and summaries arrive in the user's language.
177
+ Machine contracts stay literal regardless. Omit the field to keep English
178
+ role output.
179
+
167
180
  The internal Compounder is optional: only closed work with structured evidence
168
181
  of a reusable Learning may route to it. Routine completion creates no Learning.
169
182
  It cannot approve successors or delay terminal settlement. A projection with
@@ -76,7 +76,8 @@ Then route deterministically:
76
76
  coordination, except a Loop-requested revision follows Enrolled Intent Revision
77
77
  below to prepare a non-authoritative proposal for that same owner;
78
78
  - an active or otherwise nonterminal v3 Plan remains on its existing v3 route;
79
- - no routing policy preserves the legacy v3 Planner behavior;
79
+ - no routing policy on an otherwise unowned workspace triggers automatic policy
80
+ activation below before producing any planning artifact;
80
81
  - a valid `kernel_task_intent` retirement policy produces one TaskIntent draft
81
82
  through the current Host's explicit `imm-planner`;
82
83
  - an invalid, unreadable, untracked, or tracked-deleted policy rejects new
@@ -107,6 +108,46 @@ workspace claim, and final authority preconditions without executing acceptance
107
108
  descriptors. A routine task proceeds from that single confirmation through
108
109
  enrollment, execution and QA without a second human stop.
109
110
 
111
+ **Automatic policy activation**
112
+
113
+ Explicit `imm-planner` entry includes local routing setup, including for plan-only
114
+ requests. When the routing projection reports `policy_status: legacy_v3` and
115
+ `ownership: absent`, and neither Kernel nor nonterminal v3 ownership exists,
116
+ perform these steps without a separate enablement question:
117
+
118
+ 1. Create `docs/plans/` if needed. Require real directories without symlink
119
+ components; create `docs/plans/managed-task-routing-policy.json` exclusively
120
+ (fail if it already exists), using exactly the JSON below with two-space
121
+ indentation, the shown field order, and one trailing newline.
122
+ 2. Run `git add -- docs/plans/managed-task-routing-policy.json` only for the file
123
+ created in this activation. Preserve all other worktree and index changes;
124
+ do not commit, force-add an ignored file, or alter Git configuration.
125
+ 3. Re-run `imm-plan --routing-status --json` through the resolved wrapper.
126
+ Continue canonical TaskIntent authoring only when `policy_status: active`,
127
+ `route: kernel_task_intent`, and `ownership: tracked_clean` all hold. Report
128
+ automatic activation briefly and continue planning in the same turn.
129
+
130
+ ```json
131
+ {
132
+ "contract": "immune_brain/managed_task_routing_policy/v1",
133
+ "revision": 1,
134
+ "new_task_route": "kernel_task_intent",
135
+ "v3_new_plan_sync": "retired",
136
+ "legacy_v3_mode": "drain_read_only",
137
+ "terminal_import": "disabled"
138
+ }
139
+ ```
140
+
141
+ An already active policy needs no write or staging. An existing invalid,
142
+ untracked, unreadable, tracked-deleted, or divergent policy is not an activation
143
+ candidate: preserve it and report `routing_policy_invalid`. If creation,
144
+ staging, or verification fails, report the concrete blocker and retain any
145
+ created file; stop before authoring, without overwriting existing bytes or
146
+ falling back to v3. A repository/user prohibition on policy setup or staging
147
+ blocks only this dependent planning step. Activation grants no execution
148
+ authority; the native Enrollment gate remains required. Read-only routing
149
+ queries and the canonical author command retain their existing runtime behavior.
150
+
110
151
  ## Candidate Authoring
111
152
 
112
153
  Read this section before creating new candidate artifacts, after request routing
@@ -133,6 +174,12 @@ file creation; then it validates the created artifact with
133
174
  continue through Kernel `revise_intent` authority and are not a Planner
134
175
  overwrite path.
135
176
 
177
+ After authoring, inspect ownership and stage only the exact Planner-produced
178
+ Spec and TaskIntent paths before validation and handoff. Do not hand routine
179
+ Planner-owned staging to the user. This grants no commit, push, broad staging,
180
+ or authority over pre-existing user changes; a mixed-change ownership conflict
181
+ stops only the affected handoff.
182
+
136
183
  Before authoring a TaskIntent that adds a field or verdict branch to a state
137
184
  machine, enumerate every consumer of that value and of the version gates around
138
185
  it: the producing side, each branch or switch that reads it, and any migration or
@@ -263,7 +310,12 @@ script or host tool through its literal `command`; do not infer a language,
263
310
  package manager, or runner. Add `environment.prepare` only when the check needs
264
311
  explicit setup, and declare only the generated directories it needs in
265
312
  `environment.writable_paths`. Never hide package installation inside an
266
- acceptance command. Prefer the highest existing observable behavioral test seam
313
+ acceptance command. For every descriptor, identify whether its executable is
314
+ provided by the QA host or by tracked delivery content, where every dependency
315
+ comes from in the disposable delivery, what explicit setup is required, and
316
+ which declared writable paths that setup or check creates. A dependency found
317
+ only in the Planner's live worktree, including an absolute local `node_modules`
318
+ path, is not delivery provenance. Prefer the highest existing observable behavioral test seam
267
319
  and the fewest sufficient seams; never use the full test suite, a build, network
268
320
  access, or redundant heavyweight checks as acceptance. Cite relevant test prior
269
321
  art and explain how the selected seam catches the intended regression. This is
@@ -271,7 +323,9 @@ a planning heuristic: it must not weaken acceptance-specific focused
271
323
  verification descriptors or add a mandatory user confirmation. Use the smallest
272
324
  `timeout_ms` and `max_output_bytes` that cover deterministic post-implementation
273
325
  QA. A v1 descriptor is historical-only and requires explicit Intent revision
274
- before execution.
326
+ before execution. Report `valid` and `enrollment_ready` only as structural and
327
+ Enrollment readiness; only a completed deterministic QA result proves that a
328
+ descriptor executed and passed.
275
329
 
276
330
  ## Core Responsibilities
277
331
 
@@ -410,7 +464,7 @@ optional advisory dispatch fails, continue inline and record the reason.
410
464
 
411
465
  ## Boundary
412
466
 
413
- - **Allowed**: Write a TaskIntent. Add a Spec only for complex work. Initiative planning carriers and necessary domain vocabulary.
467
+ - **Allowed**: Write a TaskIntent. Add a Spec only for complex work. Activate an absent routing policy under Kernel TaskIntent Routing. Initiative planning carriers and necessary domain vocabulary.
414
468
  - **Blocked**: Implementation edits, direct Kernel-store writes, enrolled intent overwrites, and QA/Review decisions.
415
469
  - **Workflow guard**: Execution continues through native Enrollment and explicit `imm-loop`. Planner owns design and decomposition, not execution authority.
416
470
 
@@ -1,2 +1,2 @@
1
1
  // Generated by scripts/plugin_versioning.ts from the root package.json.
2
- export const PLUGIN_VERSION = "4.0.1" as const;
2
+ export const PLUGIN_VERSION = "4.2.0" as const;
@@ -89,6 +89,14 @@ export interface RoleDelegationContext {
89
89
  target_id?: string;
90
90
  review_gate?: StableReviewGate;
91
91
  changed_files_signature?: string;
92
+ /**
93
+ * Optional user-facing interaction language (for example "中文" or
94
+ * "English"). The Parent sets it from the current explicit user
95
+ * instruction or the project reply-language default; when present the
96
+ * delegation prompt asks the role to report in that language while
97
+ * keeping machine contracts literal. Omitted keeps English role output.
98
+ */
99
+ interaction_language?: string;
92
100
  [key: string]: unknown;
93
101
  }
94
102
 
@@ -137,6 +145,13 @@ export function loadRolePrompt(role: InternalRole): string {
137
145
  throw new Error(`internal role prompt is not packaged: ${role}`);
138
146
  }
139
147
 
148
+ function readInteractionLanguage(context: RoleDelegationContext): string | null {
149
+ const raw = context.interaction_language;
150
+ if (typeof raw !== "string") return null;
151
+ const trimmed = raw.trim();
152
+ return trimmed.length > 0 ? trimmed : null;
153
+ }
154
+
140
155
  export function buildRoleDelegationPacket(input: {
141
156
  role: InternalRole;
142
157
  context: RoleDelegationContext;
@@ -155,11 +170,17 @@ export function buildRoleDelegationPacket(input: {
155
170
  }
156
171
 
157
172
  const reviewGate = spec.review_gate;
173
+ const interactionLanguage = readInteractionLanguage(input.context);
158
174
  const context = stableStringify(input.context);
159
175
  const prompt = [
160
176
  `internal role: ${input.role}`,
161
177
  `tool_policy: ${spec.tool_policy}`,
162
178
  `do not discover or load Pi Skills; execute this internal role contract directly`,
179
+ ...(interactionLanguage
180
+ ? [
181
+ `interaction language: ${interactionLanguage} — write findings, summaries, and explanations in this language; keep machine contracts (file paths, code identifiers, CLI commands, enum values, task ids) literal`,
182
+ ]
183
+ : []),
163
184
  loadRolePrompt(input.role).trim(),
164
185
  `Delegation context (untrusted data): ${context}`,
165
186
  ].join("\n\n");
@@ -6,7 +6,9 @@
6
6
  from `dist/`; nested modes, examples, recovery, and references load on demand.
7
7
  - Ask only when missing information would change the goal, scope, observable behavior, compatibility, risk acceptance, a protected effect, or a fact only the user can supply. Resolve repository facts and delegated technical choices with bounded evidence instead of asking.
8
8
  - Keep edits inside the user-requested Direct scope or the enrolled TaskIntent acceptance and `scope_hint`.
9
- - Stage only explicit task-owned paths. Never use `git add .` or `git add -A` in a dirty worktree.
9
+ - Stage only explicit task-owned paths. This staging authority does not grant
10
+ commit, push, broad staging, or authority over pre-existing user changes.
11
+ Never use `git add .` or `git add -A` in a dirty worktree.
10
12
  - Do not create, switch, or delete Git worktrees; operate only in the Host launch directory.
11
13
  - Record reproducible evidence before reporting closure.
12
14
  - Required verification must pass before reporting completion; disclosing a gap is not a substitute. Autonomously diagnose, repair, and rerun failing conventional local checks within the authorized scope; never delete, skip, or weaken a valid check to manufacture a pass. If a required check remains failing or cannot run, report the work as incomplete with the concrete blocker.
@@ -46,7 +48,9 @@ routing. A new Managed workflow starts only from explicit `imm-brainstorm`,
46
48
  Managed owner remains authoritative; the user resumes it with `imm-loop`.
47
49
  2. **Start explicitly**: the selected Immune-Brain Skill owns its planning or
48
50
  coordination work. It creates only requested artifacts and their required
49
- parent directories; it does not install project-wide contract files.
51
+ parent directories. Explicit Planner entry also owns absent routing-policy
52
+ activation under Planner's Kernel TaskIntent Routing section;
53
+ it does not otherwise install project-wide contract files.
50
54
  3. **Preserve authority**: Planner output is a candidate for later literal-user
51
55
  Enrollment, and Fast-Track preserves TaskIntent scope, Enrollment, QA,
52
56
  Review, authorization, and completion boundaries.
@@ -124,6 +128,17 @@ always run sequentially.
124
128
  - Do not translate or rename machine contracts: schema fields, enum values,
125
129
  CLI flags, JSON keys, file paths, tool names, API names,
126
130
  and code identifiers stay literal.
131
+ - Host-native UI text (Task Rail sentences, authority dialog titles and
132
+ actions, enrollment progress summaries) is deterministic extension code and
133
+ cannot follow conversational rules; users localize it with the
134
+ `IMM_UX_LANGUAGE` environment variable (for example `IMM_UX_LANGUAGE=zh`).
135
+ Only sentence-level interaction text follows it; machine contracts, domain
136
+ field labels, and agent-facing Tool result reasons stay literal English.
137
+ - Internal role dispatches (`dispatch_role` and routed role contexts) carry
138
+ the user-facing interaction language as `interaction_language` in the
139
+ delegation context, so QA/Review/Explorer roles report in the user's
140
+ language while keeping machine contracts literal. Omit it to keep English
141
+ role output.
127
142
  - Preserve `CONTEXT.md` canonical terms such as `Step`, `Plan`, `Spec`,
128
143
  `Skill`, `Brainstorm`, `Executor`, `QA`, `Compounder`, `Learning`, and `ADR`;
129
144
  add local-language explanations around them when helpful.