immune-brain 5.0.0 → 5.1.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.
Files changed (29) hide show
  1. package/README.md +223 -12
  2. package/README.zh-CN.md +228 -11
  3. package/package.json +2 -1
  4. package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
  5. package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +1 -0
  6. package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +24 -3
  7. package/plugins/immune-brain/dist/claude/mcp-server.mjs +1339 -66
  8. package/plugins/immune-brain/dist/docs/reference/immune-brain-config.md +27 -0
  9. package/plugins/immune-brain/dist/imm-run.md +198 -3
  10. package/plugins/immune-brain/dist/role-prompts/lane-steward.md +44 -0
  11. package/plugins/immune-brain/runtime/claude/interaction.ts +6 -0
  12. package/plugins/immune-brain/runtime/claude/kernel_ports.ts +16 -4
  13. package/plugins/immune-brain/runtime/claude/mcp_server.ts +24 -2
  14. package/plugins/immune-brain/runtime/claude/role_agents.ts +4 -3
  15. package/plugins/immune-brain/runtime/local_initiative.ts +94 -0
  16. package/plugins/immune-brain/runtime/loop_contract.ts +55 -2
  17. package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
  18. package/plugins/immune-brain/runtime/prompts/lane-steward.md +44 -0
  19. package/plugins/immune-brain/runtime/role_prompt_bridge.ts +15 -2
  20. package/plugins/immune-brain/runtime/unattended/batch_integration.ts +387 -0
  21. package/plugins/immune-brain/runtime/unattended/batch_kernel_port.ts +2 -2
  22. package/plugins/immune-brain/runtime/unattended/batch_lanes.ts +909 -0
  23. package/plugins/immune-brain/runtime/unattended/batch_plan.ts +36 -11
  24. package/plugins/immune-brain/runtime/unattended/batch_preflight.ts +41 -22
  25. package/plugins/immune-brain/runtime/unattended/batch_runner.ts +20 -1
  26. package/plugins/immune-brain/runtime/unattended/batch_schedule.ts +162 -0
  27. package/plugins/immune-brain/runtime/unattended/batch_state.ts +356 -8
  28. package/plugins/immune-brain/runtime/unattended/types.ts +21 -2
  29. package/plugins/immune-brain/skills/imm-run/SKILL.md +4 -0
package/README.zh-CN.md CHANGED
@@ -14,7 +14,7 @@ Immune-Brain 为 AI 编程工具(**Pi** 与 **Claude Code**)提供结构化
14
14
  - **需要严谨时显式启用** — 遇到复杂功能开发或高保证任务时,显式调用 `imm-brainstorm`、`imm-planner` 或 `imm-run`。
15
15
  - **计划变为可追踪的任务**(`TaskIntent` + `TaskRecord`) — 进度落盘持久化(Git + `.imm/`),会话重启或上下文清理后仍可无缝恢复。
16
16
  - **质量由代码强制保障** — 自动化 QA 验收与隔离式 Reviewer 审查必须通过,任务才会结算完成。
17
- - **已就绪的 Initiative 可以整批运行** — 一次确认的 Batch Authorization 让 `imm-run` 串行推进已发布 Initiative 的各个 child,而每个 child 仍然独立 Enrollment、独立 QA/Review、独立结算。
17
+ - **已就绪的 Initiative 可以整批运行(串行或多 Lane 并行)** — 一次确认的 Batch Authorization 即可无人值守推进整批子任务;支持默认单工作区串行推进,或显式开启多 Lane 并行(按 Scope 互斥拓扑调度独立 Git worktree 并发执行,辅以集成守卫与强故障隔离),每个 child 依然保持独立的 Enrollment、QA、Review 与结算。
18
18
 
19
19
  Pi 与 Claude Code 是支持的宿主。未声明的适配器仍不受支持。Claude Code 最低版本为 `2.1.236`,这是已通过交互式 server-initiated MCP elicitation 验证的最低版本。当前真实 Host 证据见 `docs/verification/claude-native-elicitation-authority-conformance.md`;历史报告归档于 `docs/verification/archive/`。
20
20
 
@@ -25,6 +25,8 @@ Pi 与 Claude Code 是支持的宿主。未声明的适配器仍不受支持。C
25
25
  - [安装](#安装)
26
26
  - [快速开始](#快速开始)
27
27
  - [如何使用](#如何使用)
28
+ - [推荐工作流:与 mattpocock/skills 组合使用](#推荐工作流与-mattpocockskills-组合使用)
29
+ - [实战案例](#实战案例)
28
30
  - [核心设计哲学:把“判断”变成“查表”](#核心设计哲学把判断变成查表用确定性工程驾驭多模型)
29
31
  - [7 个 Skills](#7-个-skills)
30
32
  - [生命周期](#生命周期)
@@ -84,7 +86,7 @@ mise run check-dist-sync # 校验生成文档同步
84
86
  Immune-Brain 遵循 **显式 Skill 触发(Skill-explicit)** 模型:日常对话就是轻量自然的 AI 编程,只有显式调用对应 Skill 时才会开启严格工程管理。
85
87
 
86
88
  **1. 当你需要严谨工程流程时,显式调用 Skill:**
87
- - 需求模糊想先梳理?输入 `/imm-brainstorm`(或对 Agent 说 "用 imm-brainstorm 梳理需求")。
89
+ - 需求模糊、重大架构设计或高保证任务想先敲定方案?输入 `/grill-me`(来自 `mattpocock/skills`,强烈推荐)进行苏格拉底式高压追问与决策确认,或输入 `/imm-brainstorm`(内置极简梳理)。
88
90
  - 目标明确准备制定方案?输入 `/imm-planner`(或对 Agent 说 "用 imm-planner 规划深色模式功能")。
89
91
 
90
92
  *(日常提问如 "这个函数什么意思"、"改个 typo" 保持完全原生,没有任何流程弹窗和开销。)*
@@ -112,11 +114,11 @@ Immune-Brain 提供两种清晰的工作模式:日常轻量编码走 **Host-na
112
114
  | 你的情况 | 你做什么 / 说什么 | 会发生什么 |
113
115
  |---|---|---|
114
116
  | 日常编码、快速改动、普通问答 | 正常自然语言对话("帮我改下文案"、"解释这段代码") | **Host-native**:标准 Pi / Claude Code 行为,零流程开销 |
115
- | 想法模糊,需要梳理边界与风险 | `/imm-brainstorm` "帮我梳理一下通知系统的方案" | → `imm-brainstorm` 提问澄清、分析约束与风险(只读,不改代码) |
117
+ | 想法模糊,需要架构拷问、边界与决策确认 | `/grill-me`(推荐)或 `/imm-brainstorm` | → `/grill-me` 针对设计树逐项穷追猛打敲定决策;`/imm-brainstorm` 进行内置只读需求框架梳理 |
116
118
  | 目标明确,需要正规计划与规格 | `/imm-planner` "规划一下深色模式功能" | → `imm-planner` 产出 `TaskIntent` + Spec,包含可执行验收条件 |
117
119
  | 计划已确认,准备执行与验证 | `/imm-run` | → Executor 在范围内实现 → 确定性 QA 验收 → 隔离 Review 审查 → 任务结算 |
118
120
  | 会话中断或需恢复未完成任务 | `/imm-run` | → 从磁盘状态(`.imm/`)无缝恢复,以 Kernel projection 为准 |
119
- | 已发布的 Initiative 可以整批跑了 | "把 initiative `<slug>` 无人值守跑完" | → Host 的 `start_unattended_batch`:一次原生确认绑定有序 plan digest,child 串行执行 |
121
+ | 已发布的 Initiative 批次推进(串行 / 多 Lane 并行) | "无人值守跑完 initiative `<slug>`"(可指定 `--max-parallel 4` 或配置 `Lane max parallel`) | → Host 的 `start_unattended_batch`:一次原生确认绑定 plan digest。无配置时单工作区串行推进;配置并行度时开启多 Lane Git worktree 物理隔离并发执行 |
120
122
  | 跨 Host 协作(Claude 规划 + Pi 编码) | 在 Claude Code 中调 `/imm-planner`,切到 Pi 输入 `/imm-run` | → Spec 与 TaskIntent 共享于 Git,Pi 原生弹窗准入并执行 QA/Review 闭环 |
121
123
  | PR 被评论 / CI 挂了 | 对该 PR 使用 `/imm-pr-fix` | → 独立修复:在当前 PR 内针对性修复,不创建新 managed 任务 |
122
124
  | 文档过时需要清理 | `/imm-doc-prune` | → 只读审计过时文档,仅删除经哈希审批的条目 |
@@ -125,7 +127,7 @@ Immune-Brain 提供两种清晰的工作模式:日常轻量编码走 **Host-na
125
127
 
126
128
  > **核心原则:Skill 显式调用**
127
129
  > - **普通输入保持 Host-native**:自然语言提问绝不自动绑架流程或发起 Enrollment。你完全自主决定何时开启严格工程保障。
128
- > - **Managed 工作流显式启动**:需要澄清用 `imm-brainstorm`,制定计划用 `imm-planner`,执行与恢复用 `imm-run`。
130
+ > - **Managed 工作流显式启动**:需要澄清决策用 `/grill-me`(或 `imm-brainstorm`),制定计划用 `imm-planner`,执行与恢复用 `imm-run`。
129
131
 
130
132
  ### 跨 Host 协作:Claude Code 规划 + Pi 编码执行
131
133
 
@@ -163,6 +165,146 @@ Immune-Brain 的核心状态与契约完全去会话化(Session-neutral),
163
165
 
164
166
  ---
165
167
 
168
+ ## 推荐工作流:与 mattpocock/skills 组合使用
169
+
170
+ Immune-Brain 能够在工程进入实施阶段后提供坚不可摧的确定性闭环与质量约束,但在实际软件研发中,绝大多数失败早在编码前就已注定:**大模型在尚未充分遍历设计树、评估技术折中并推演边界条件时,就匆忙上手编码。**
171
+
172
+ 为了彻底杜绝盲目开工与范式漂移,生产环境中最推荐的最佳实践组合是将 Matt Pocock 的 **`mattpocock/skills`** 作为上游,与 **Immune-Brain** 构筑的下游确定性引擎组合使用:
173
+
174
+ > **双引擎协同哲学**
175
+ > - **上游苏格拉底式充分摩擦(`grill-me`)**:主动放慢思考节奏。AI 化身为苛刻的技术面试官,在落实任何代码与规格之前,对设计树的每一个分支、技术选型与隐性假设进行穷追猛打,逐一敲定决策。
176
+ > - **下游确定性工程闭环(`imm-planner` + `imm-run`)**:将敲定的共识翻译为不可篡改的机器契约(`TaskIntent` + living Spec),通过宿主原生弹窗由人授权,严格冻结文件边界(`scope_hint`),并由沙箱子进程 QA 真实跑通与隔离审查子代理把关交付。
177
+
178
+ ```text
179
+ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
180
+ │ 1. 上游苏格拉底式决策对齐 (mattpocock/skills /grill-me) │
181
+ │ 职责: 沿设计树每一个分支进行高压追问,梳理技术权衡与隐性假设,达成架构共识 │
182
+ └───────────────────────────────────────────────────┬────────────────────────────────────────────────────┘
183
+ │ 敲定的决策分支与架构设计共识
184
+ ▼
185
+ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
186
+ │ 2. 正式机器契约与方案规划 (Immune-Brain /imm-planner) │
187
+ │ 职责: 编写 Living Spec 与 TaskIntent (.intent.json);锁定 scope_hint 与 VerificationDescriptor v2 │
188
+ └───────────────────────────────────────────────────┬────────────────────────────────────────────────────┘
189
+ │ Git 追踪的机器契约制品
190
+ ▼
191
+ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
192
+ │ 3. 宿主原生人工准入确认 (Native Host Enrollment) │
193
+ │ 职责: 开发者在原生 TUI / MCP 弹窗中核对范围并授权;Kernel 原子记录 Git 基线并获取 SQLite CAS 锁 │
194
+ └───────────────────────────────────────────────────┬────────────────────────────────────────────────────┘
195
+ │ 工作区独占租约
196
+ ▼
197
+ ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
198
+ │ 4. 确定性执行与凭证结算 (Immune-Brain /imm-run) │
199
+ │ 职责: 冻结 Scope 内 Executor 编码 -> 真实子进程 QA (bun test) -> 隔离 Subagent Review -> CAS 凭证结算 │
200
+ └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
201
+ ```
202
+
203
+ ### 为什么推荐用 `grill-me` 代替 `imm-brainstorm` 进行决策确认
204
+
205
+ 虽然 Immune-Brain 内置了轻量的 `imm-brainstorm` 技能,但面对非平凡业务功能、重大架构调整或安全敏感边界时,**强烈推荐使用 `/grill-me` 作为前置决策工具**:
206
+
207
+ | 维度 | 内置 `imm-brainstorm` | 上游 `/grill-me` (`mattpocock/skills`) | 组合推荐姿态 |
208
+ |---|---|---|---|
209
+ | **生态与安装** | 内置于 Immune-Brain(开箱即用,零依赖) | 来自 `mattpocock/skills` 生态(`npx skills@latest add mattpocock/skills --skill grill-me`) | 由 `/grill-me` 担任上游思想对齐者,Immune-Brain 掌管下游确定性工程闭环 |
210
+ | **交互模式** | 结构化问题框架梳理;批量发问;只读概览 | 单轮迭代式、高压苏格拉底式追问;沿设计树逐项穷尽推演 | `/grill-me` 主动质疑开发者的盲目假设,拒绝模糊妥协 |
211
+ | **推演纪律** | 优先查阅仓库代码,提炼顶层目标与约束风险 | 优先查阅仓库代码,针对每个决策点主动提供带倾向的推荐方案 | 彻底消除“氛围感盲写”(vibe coding),在上游将设计决策压成确定性共识 |
212
+ | **产出形态** | 只读的 `brainstorm_framing` 总结块 | 遍历并收敛完成的完整设计树决策集合 | 将确认后的决策清单无缝输入给 `/imm-planner` 转化为机器契约 |
213
+ | **适用场景** | 轻量需求梳理、离线无网络环境或简单任务 | 复杂业务系统、核心架构重构、多服务联动与高危门禁功能 | 严肃工程研发与生产级任务的**首选推荐标准** |
214
+
215
+ ### 安装与配置
216
+
217
+ 使用官方 Skills 安装器将 `grill-me` 添加到当前项目或全局环境:
218
+
219
+ ```bash
220
+ # 仅添加 mattpocock/skills 中的 grill-me
221
+ npx skills@latest add mattpocock/skills --skill grill-me
222
+
223
+ # 或安装完整套件
224
+ npx skills@latest add mattpocock/skills
225
+ ```
226
+
227
+ ### 典型端到端流水线:`grill-me` → `imm-planner` → `imm-run`
228
+
229
+ 1. **第一步:苏格拉底式设计拷问(`/grill-me`)**
230
+ - 执行 `/grill-me "实现多租户 Webhook 分发系统,包含重试退避与防重放机制"`。
231
+ - Agent 会先阅读工程现有代码模式,随后针对设计树展开单点追问(存储选型、幂等方案、退避曲线、错误捕获),并在每个问题后给出明确的推荐选项与权衡说明。
232
+ - 开发者逐一确认直至全部分支收敛:“*决策树已全部收敛,准备开始制定工程计划。*”
233
+ 2. **第二步:机器契约与规格规划(`/imm-planner`)**
234
+ - 执行 `/imm-planner "基于刚才 grill-me 敲定的决策方案规划 Webhook 分发功能"`。
235
+ - `imm-planner` 吸收已确认的架构决策并生成:
236
+ - **Living Spec**(`docs/specs/webhook-dispatcher.spec.md`):锁定参考坐标、架构权衡与明确的禁止越界边界(Negative Scope)。
237
+ - **TaskIntent**(`docs/plans/webhook-dispatcher.intent.json`):锁定文件范围 `scope_hint`、风险等级(`material`)与自动化验收命令 `VerificationDescriptor v2`。
238
+ 3. **第三步:原生弹窗准入授权(Enrollment Gate)**
239
+ - 将生成的 Spec 与 Plan 纳入 Git 暂存(`git add docs/`)。
240
+ - 执行 `/imm-run`。弹出当前宿主的原生确认界面(Pi TUI 弹窗 / Claude Code MCP 交互弹窗)。
241
+ - 人工点击确认后,Kernel 原子生成 Git 基线快照(`enrollment-baseline.json`)并加持 SQLite CAS 工作区排他锁。
242
+ 4. **第四步:物理冻结执行与客观验证(`/imm-run`)**
243
+ - **Executor**:严格在 `scope_hint` 文件信封内编写代码,任何物理逃逸直接 fail-closed 阻断。
244
+ - **确定性 QA 引擎**:Kernel 直接前台拉起子进程执行 `bun test`,以真实退出码 0 判定胜负,拒绝口头汇报。
245
+ - **隔离 Reviewer 审查**:针对 `material`/`critical` 任务,调度独立的只读审查子代理基于 Git blob 制品严格审计。
246
+ - **结算归档**:Kernel 原子落盘证据至 `.imm/audit/<task-id>/` 并释放工作区锁。
247
+
248
+ ---
249
+
250
+ ## 实战案例
251
+
252
+ ### 案例 1:全新功能从零开发 — 多租户 Webhook 分发系统
253
+
254
+ - **目标**:实现一套生产级多租户 Webhook 分发引擎,具备 HMAC 密钥签名、指数退避重试与防重放攻击能力。
255
+ - **不使用本工作流的常见缺陷**:AI 拿到需求后立即动手写文件,随意引入未经评估的外部三方库,忘记校验时间戳导致重放漏洞,留下内存泄漏的定时器,并且在未做超时中断验证的情况下直接宣称“开发完成”。
256
+ - **实战流程**:
257
+ 1. **上游高压对齐(`/grill-me`)**:
258
+ - *问题 1(持久化选型)*:SQLite 还是外部队列?*推荐方案*:复用工程现有的 SQLite CAS 表,避免引入额外基础设施依赖。
259
+ - *问题 2(安全规范)*:如何防御重放攻击?*推荐方案*:强制要求 `X-Webhook-Timestamp` 请求头,允许最大 5 分钟时钟容差,使用 HMAC-SHA256 签名。
260
+ - *问题 3(韧性保障)*:重试策略与超时机制?*推荐方案*:采用 Full Jitter 指数退避,最多重试 5 次,单次请求通过 `AbortController` 施加 10 秒硬超时。
261
+ - *成果*:全套架构权衡在 3 分钟人机对话内全部锁定。
262
+ 2. **机器契约规划(`/imm-planner`)**:
263
+ - Planner 编写 `docs/specs/webhook-dispatcher.spec.md`,明确标记 Negative Scope(`src/auth/` 与 `src/billing/` 严禁改动)。
264
+ - 生成 `docs/plans/task-webhook-dispatcher.intent.json`,定级为 `material` 风险,配置验收命令真机运行 `bun test tests/webhook-dispatcher.test.ts`。
265
+ 3. **原生弹窗准入确认**:
266
+ - 开发者在 Git 中检视 diff,并在 Pi TUI / Claude Code 弹窗中授权。
267
+ 4. **执行、QA 验证与审查(`/imm-run`)**:
268
+ - Executor 在 `scope_hint` 限定范围内编写代码。
269
+ - Kernel 真机拉起沙箱执行 `bun test tests/webhook-dispatcher.test.ts`,验证退出码为 `0`。
270
+ - 隔离的 Reviewer 子代理审计 Git blob,核实无任何越界改动并检查异常处理规范。
271
+ - Kernel 原子落盘凭据至 `.imm/audit/<task-id>/`。
272
+
273
+ ### 案例 2:关键架构重构 — CAS 状态机存储引擎迁移(v1 → v2)
274
+
275
+ - **目标**:将持久化层从历史遗留的 JSON 文件平滑迁移为基于 SQLite 的原子 CAS 引擎,并保持零停机回滚和历史只读审计能力。
276
+ - **不使用本工作流的常见缺陷**:模型在底层存储重构时极易造成静默数据损坏、擅自删除历史兼容路径,并通过篡改断言在假测试中制造“通过”。
277
+ - **实战流程**:
278
+ 1. **上游高压对齐(`/grill-me`)**:
279
+ - *拷问焦点*:“迁移期间若有正在运行的 v1 任务该如何处理?推荐方案:实施严格的排空检查(`drain_required`),拒绝双写,存在活跃任务时立即中断拒绝迁移。”
280
+ - *拷问焦点*:“回滚时如何保证 WAL 不损坏?推荐方案:采用单文件事务、操作系统级排他文件锁与不可变 Git 快照。”
281
+ 2. **代码强制兜底规划(`/imm-planner`)**:
282
+ - 由于改动触碰了 `runtime/kernel/storage.ts`,Kernel 规则强制将风险等级锁定至 `critical` 底线。
283
+ - Planner 精准锚定代码坐标(`storage.ts:120`),并配置包含真实历史迁移固件的验收测试。
284
+ 3. **原生准入确认**:开发者在宿主原生弹窗中看到被强制锁定的 `critical` 风险与基线快照,点击授权。
285
+ 4. **确定性 QA 与对抗性审查(`/imm-run`)**:
286
+ - 真机执行全量回归套件与真实历史固件迁移测试。
287
+ - 独立的 Devil's Advocate Reviewer 子代理针对不可变 Git blob 展开对抗性审计,重点核验向后兼容逻辑。
288
+ - 原子结项并写入不可篡改的审计记录。
289
+
290
+ ### 案例 3:跨 Host 协同开发 — Claude Code(深度追问与方案规划)+ Pi(极速前台执行与真机验收)
291
+
292
+ - **目标**:最大化利用桌面端旗舰模型的深度推理进行架构推演,同时在极速本地/远程终端中执行代码,大幅节省 Token 成本并提升交付速度。
293
+ - **实战流程**:
294
+ 1. **在 Claude Code(桌面端)中**:
295
+ - 运行 `/grill-me`(来自 `mattpocock/skills`),利用 Claude 旗舰推理能力充分拷问架构方案。
296
+ - 运行 `/imm-planner`,生成精准定位到代码行号的 Living Spec 与 `TaskIntent` 机器契约。
297
+ - 将制品提交或暂存到 Git(`git add docs/ && git commit -m "docs: webhook spec and plan"`)。
298
+ 2. **切换到 Pi(本地或远程终端)中**:
299
+ - 在同一工作区中打开 Pi。
300
+ - 输入 `/imm-run`。Pi 自动识别到暂存的 `TaskIntent`,弹出原生 TUI 弹窗提示准入。
301
+ - Pi 的 Executor 角色调度高吞吐、高性价比模型(Fast / Mid Tier)在锁定的文件边界内写代码。
302
+ - 本地进程直接执行 `bun test` 产出真实退出码凭证。
303
+ - 审查通过后 Kernel 结算结项。
304
+ 3. **成果**:跨 Host 状态零损失无缝衔接,同时节约 60%~70% 的旗舰推理 Token 支出。
305
+
306
+ ---
307
+
166
308
  ## 核心设计哲学:把“判断”变成“查表”,用确定性工程驾驭多模型
167
309
 
168
310
  大模型(尤其是轻量/高性价比的 Fast 档模型)在工程落地中最容易失败的原因,不是代码语法不过关,而是死在**语义含糊、过度发挥**与**逃避严格验证**上。
@@ -395,7 +537,7 @@ flowchart TD
395
537
  - **按险定级与确定性兜底**:`routine` 仅需 QA;`material`/`critical` 必须追加独立只读 Reviewer 产出结构化裁决。触碰核心权威路径强制定级为 `material`。
396
538
  - **反证机制 (Live Refutation)**:主观 Review finding 可由真实通过的新鲜 QA 证据反证驳回;代码发生改动后反证自动失效并重新阻塞。
397
539
  - **不可变审计落盘**:任务结项时,完整的 `TaskRecord`、Git blob 打包的 `ReviewBundle`、QA Attestation 凭证原子沉淀至 `.imm/audit/<task-id>/` 并受 Git 追踪。
398
- - **批处理 (Unattended Batch)**:基于 GitHub Issue / `plan_digest` 串行推进,每个子任务独立走完 Enrollment → QA → Review → Commit 闭环。
540
+ - **批处理与多 Lane 并行 (Unattended Batch & Parallel Lanes)**:基于 GitHub Issue / `plan_digest` 推进。支持默认单分支串行或多 Lane 物理并行模式;并行时协调者基于 `scope_hint` 互斥拓扑调度独立 Git worktree 并发执行,结算时通过集成守卫(Integration Guard)在候选提交上重跑确定性验收命令再 fast-forward 主分支,杜绝并发污染。
399
541
 
400
542
  核心不变量:
401
543
 
@@ -410,12 +552,75 @@ flowchart TD
410
552
 
411
553
  ## 无人值守批次运行
412
554
 
413
- 当一个 Initiative 下已经有多个就绪的 child,可以把它们作为一批串行跑完,而不用逐个任务手动推进。
555
+ 当一个 Initiative 下包含多个已就绪的 child 任务时,开发者无需逐个手动触发 `imm-run`,可通过 Host 原生 privileged tool `start_unattended_batch` 进行整批无人值守推进。
556
+
557
+ 系统支持两种批次运行形态:**默认串行模式** 与 **多 Lane 并行模式(Parallel Batch Lanes)**。
558
+
559
+ ### 1. 批次运行模式概览
560
+
561
+ | 维度 | 串行批次 (Serial Batch,默认) | 多 Lane 并行批次 (Parallel Batch Lanes) |
562
+ |---|---|---|
563
+ | **开启方式** | 调用 `start_unattended_batch(slug)` | 显式传入 `max_parallel` 或在配置中设定 `Lane max parallel: <n>` |
564
+ | **工作区拓扑** | 共享唯一的专属批次分支(`imm-batch/<slug>`) | Coordinator 维护主批次分支;各并发任务独占独立 Git worktree(`imm-lane/<task-id>` 分支) |
565
+ | **调度策略** | 严格按依赖拓扑层级单任务逐个串行推进 | 互不依赖且物理修改范围(`scope_hint`)**完全不重叠(Scope-disjoint)**的任务并发执行 |
566
+ | **Authority 边界** | 协调者按序推进单个任务的本地 Authority Store | 每个 Lane 拥有完全隔离的本地 Authority Store,各自独立加锁,零全局 CAS 竞争 |
567
+ | **集成机制** | 任务验证完成直接在批次分支提交 1 个 commit | Lane 结算后通过 Git plumbing 校验变更等价性,并在候选提交上重跑集成守卫(Integration Guard)再 fast-forward |
568
+ | **适用场景** | 任务数少、前后改动文件强耦合、单核/受限环境 | 大中型 Initiative、多模块解耦子任务、多核或多 Host 算力充裕场景 |
569
+
570
+ ### 2. 批次授权与运行红线
571
+
572
+ - **入口显式且单一授权:** 未调用 `start_unattended_batch` 之前不存在任何批次状态或分支;未调用时 `imm-run` 行为与逐任务 Enrollment 完全一致。调用时由原生 gate(Pi TUI 弹窗或 Claude MCP elicitation)一次性展示有序任务清单与全局 `plan_digest`,用户的单次确认即为整批执行提供完备授权。
573
+ - **Child Authority 守恒:** 批次仅代表授权范围的聚合,绝非降低工程标准。每个 child 依然由 Kernel 单独执行 Enrollment、物理 Scope 冻结、真实子进程 QA、隔离 Review 与独立的 `TaskRecord` 结算。批次只是一次授权的覆盖范围,不是新的授权层级。
574
+ - **确定性执行边界:** 仅推进已发布且非 `critical` 的 child 任务;遇到人工决策挂起(`needs_human`)、预算/超时中断或提交异常时立即安全暂停批次,被阻断任务的下游依赖标记为跳过(`skipped_blocked`)而非无序推进。批次运行器不擅自 push、不开 PR、不代替用户结算决策。
575
+
576
+ ### 3. 多 Lane 并行流水线与架构(Parallel Batch Lanes)
577
+
578
+ 在多 Lane 并行模式下,系统通过 Coordinator(Parent Host)、`lane-steward`(工作区管家)与 Lane Executor Host(执行宿主)的严密协作,实现物理级并发隔离:
579
+
580
+ ```mermaid
581
+ sequenceDiagram
582
+ participant P as Coordinator (Parent Host)
583
+ participant B as Batch Runtime
584
+ participant S as lane-steward 角色
585
+ participant L as Lane Executor Host (Pi / Claude)
586
+ participant K as Lane Kernel (独立 Store)
587
+
588
+ Note over P,B: 1. 拓扑分析与并发调度 (Schedule)
589
+ P->>B: start_unattended_batch(slug, max_parallel)
590
+ B-->>P: handoffs: 调度准备 (provision Lane A, Lane B)
591
+
592
+ Note over P,S: 2. 物理隔离 Worktree 分配 (Provision & Admit)
593
+ P->>S: 调度创建 worktree (分支 imm-lane/..., 基线 batch base)
594
+ S-->>P: 返回独立 worktree 路径
595
+ P->>B: 提交 lane_offers 准入校验 (无重叠/干净度/基线校验)
596
+
597
+ Note over P,L: 3. 监督式并行执行 (Supervised Execution)
598
+ B-->>P: handoffs: 启动 Executor A, Executor B
599
+ P->>L: 拉起独立后台会话执行 imm-run (支持配置不同 Host/模型)
600
+ L->>K: 独立运行: Scope 冻结 -> 确定性 QA -> 隔离 Review -> 结算
601
+
602
+ Note over P,B: 4. 集成守卫与主分支快进 (Integration Guard & Fast-Forward)
603
+ L-->>P: 某个 Lane 结束通知
604
+ P->>B: 协调者推进 (reconcile)
605
+ B->>K: 读取 Lane 结算凭证与 commit
606
+ B->>B: 构建候选 commit + 重跑集成守卫 (自身与已集成兄弟描述符)
607
+ B->>B: Fast-forward 主批次分支 (1 child 1 commit)
608
+ B-->>P: handoffs: release Lane A / provision 新就绪 Lane C
609
+ ```
610
+
611
+ #### 并行执行的核心机制:
612
+
613
+ 1. **按 Scope 互斥拓扑调度 (Scope-Disjoint Scheduling)**:
614
+ Coordinator 实时计算任务依赖图与路径重叠度。仅当任务的前置依赖已全部集成,且其 `scope_hint` 与当前所有进行中(in-flight)Lane 的路径集合**在物理上完全无交集**时,才允许并发派发;存在路径重叠的任务自动排队,直到前序冲突 Lane 集成完毕。
615
+ 2. **监督式会话生命周期 (Supervised Host Sessions)**:
616
+ Parent Host 为每个 Lane 拉起独立的 Executor Host 进程(支持跨 Host 与模型档位配置,如 Pi 或 Claude Code)。Parent 监控会话退出事件,会话结束即触发下一轮协调;Parent 不轮询、不猜测终端输出。当 Parent 运行在 Herdr 内时,会为每个 Lane 的 Executor Host 开一个独立 tab,且绝不会替开发者回答其中的信任、登录或权限对话框。
617
+ 3. **集成守卫与候选验证 (Integration Guard)**:
618
+ 为防止并发修改产生隐式冲突,Lane 结算后不会盲目合入主分支。Coordinator 在 Git plumbing 层面构建候选提交,并在候选树上**重跑当前任务以及自其分叉以来所有已合入兄弟任务的确定性验收描述符**。只有全部再次跑通,才通过 fast-forward 原子合入主批次分支。
619
+ 4. **强故障隔离 (Fault Isolation)**:
620
+ 若某个 Lane 出现测试失败、评审驳回或集成冲突,主批次分支保持零写入(Zero-write),仅该任务被置为 `needs_human`,其后续依赖标记为 `skipped_blocked`;其他无冲突的并行 Lane 继续正常推进。
621
+ 5. **安全回收纪律 (Agents Only Create)**:
622
+ Parent 与 `lane-steward` 角色仅负责创建 Lane(worktree)和终端 tab,绝不擅自关闭 tab、不终止外部会话、不自动删除用户磁盘上的 worktree。任务集成完成后,系统明确告知开发者哪些 Lane 已可安全回收,由开发者自主清理。
414
623
 
415
- - **入口显式:** Host 的 privileged tool `start_unattended_batch`(参数为 Initiative slug)。未调用之前不存在任何 batch state、分支或授权;未调用时 `imm-run` 行为与逐任务 Enrollment 完全一致。
416
- - **一次确认、一个 digest:** 原生 gate(Pi TUI 弹窗或 Claude MCP elicitation)展示有序 child 列表与共享 plan digest,这一次 literal-user 确认就是全部 Batch Authorization。
417
- - **每个 child 的 authority 不变:** 每个 child 仍由 Kernel 单独 Enrollment、冻结、QA、Review 并以自己的 `TaskRecord` 结算。批次只是一次授权的覆盖范围,不是新的授权层级。
418
- - **边界:** 只跑已发布且非 `critical` 的 child,在专属 batch 分支上串行执行;一旦某个 child 需要人决策,或遇到预算/截止时间/授权/提交失败就暂停,被阻塞 child 的依赖项标记为跳过而不是调序。runner 不 push、不开 PR、不代替用户结算 decision、也不创建/切换/删除 Git worktree。
419
624
 
420
625
  ---
421
626
 
@@ -427,6 +632,10 @@ Immune-Brain **没有独立配置文件**,偏好设置写在仓库根目录下
427
632
  ## Immune-Brain Preferences
428
633
 
429
634
  - Initiative carrier default: github # 或 local
635
+ - Lane max parallel: 4 # 可选;开启 lane mode
636
+ - Lane Executor Host: claude-code # 可选;或 pi
637
+ - Lane Executor model: <model id> # 可选;需同时配置 Lane Executor Host
638
+ - Lane Executor effort: high # 可选;需同时配置 Lane Executor Host
430
639
  ```
431
640
 
432
641
  | 偏好 | 选项 | 默认 | 说明 |
@@ -434,6 +643,10 @@ Immune-Brain **没有独立配置文件**,偏好设置写在仓库根目录下
434
643
  | 回复语言 | 任意自然语言 | 仓库 `AGENTS.md` | 机器契约/路径/标识符保持原文 |
435
644
  | Initiative 载体 | `local` / `github` | 无默认,Planner 询问 | 仅当提案拆分为多个 TaskIntent 时生效 |
436
645
  | Advisory subagent | 允许 / 单人 | 允许 | 受 Pi host 策略与用户显式指令约束 |
646
+ | Lane max parallel | ≥ 1 的整数 | 无默认,批次保持串行 | 启动批次时作为 `max_parallel` 传入;续跑沿用批次记录的值 |
647
+ | Lane Executor Host | `claude-code` / `pi` | 无默认,优先用 Parent 同类 Host | 所有 Lane 都用该 Host,不回退到另一个 |
648
+ | Lane Executor model | 该 Host 的 model ID | 无默认,用 Executor Host 自己的默认 | 仅在配置了 `Lane Executor Host` 时生效 |
649
+ | Lane Executor effort | 该 Host 的强度档位 | 无默认,用 Executor Host 自己的默认 | 仅在配置了 `Lane Executor Host` 时生效;Claude Code 传 `--effort`,Pi 传 `--thinking` |
437
650
 
438
651
  优先级:**当前消息 > 仓库 agent 指令文件 > 用户级 agent 指令文件 > 询问**。Skill 会直接读取这些文件,因此即使 Host 不自动加载该文件,偏好依然生效。
439
652
 
@@ -485,6 +698,10 @@ docs/specs/ # Living specs(原地更新)
485
698
 
486
699
  **偏好配置为什么写在 AGENTS.md / CLAUDE.md 而不是独立配置文件?** 遵循“零外部负担、宿主原生”原则。将偏好(如 Initiative 载体、交互语言)声明在项目根目录受版本控制的指令文件中,既能在不同 Host 之间透明生效,又避免了本地全局配置文件容易漂移、团队成员无法共享的痛点。
487
700
 
701
+ **为什么在复杂任务中推荐用 `grill-me` 替代 `imm-brainstorm` 进行决策确认?** `imm-brainstorm` 是轻量内置的免安装工具,用于快速对齐顶层问题框架。而来自 `mattpocock/skills` 的 `grill-me` 则具备极具侵略性的苏格拉底式发问机制,能够沿着设计树分支主动提供带偏好的推荐方案并穷追猛打,促使开发者做出明确抉择。对于非平凡功能开发、重大架构重构或安全门禁边界,在上游先用 `grill-me` 彻底敲定决策树再输入给 `imm-planner`,能产出颗粒度极高、无后顾之忧的 Living Spec,从根源上杜绝下游返工。
702
+
703
+ **我是否必须安装 `mattpocock/skills` 才能使用 Immune-Brain?** 不是。Immune-Brain 本身是完全独立自闭环的,内置的 `imm-brainstorm` 可以零配置直接使用。与 `mattpocock/skills` 的组合属于强烈推荐的工程进阶工作流,旨在为严谨团队提供更极致的决策防线。
704
+
488
705
  **支持哪些 AI 编程工具?** Pi 与 Claude Code 是支持的宿主(Claude Code 最低版本为 `2.1.236`)。两者共享同一套确定性 Kernel 核心、质量保障机制与工具链。
489
706
 
490
707
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "immune-brain",
3
- "version": "5.0.0",
3
+ "version": "5.1.0",
4
4
  "description": "Immune-Brain agent skill system",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -78,6 +78,7 @@
78
78
  "plugins/immune-brain/runtime/workspace_scope.ts",
79
79
  "plugins/immune-brain/runtime/managed_task_routing_policy.ts",
80
80
  "plugins/immune-brain/runtime/github_issue_tracker.ts",
81
+ "plugins/immune-brain/runtime/local_initiative.ts",
81
82
  "plugins/immune-brain/runtime/verification_descriptor.ts",
82
83
  "plugins/immune-brain/runtime/role_prompt_bridge.ts",
83
84
  "plugins/immune-brain/runtime/loop_contract.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "immune-brain",
3
- "version": "5.0.0",
3
+ "version": "5.1.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"
@@ -139,6 +139,7 @@ const LOOP_TARGETS = [
139
139
  "architecture-exploration",
140
140
  "advisory-review",
141
141
  "compounder",
142
+ "lane-supply",
142
143
  ] as const;
143
144
  const LOOP_DIRECT_ROLES = ["qa", "code-review", "ui-review"] as const;
144
145
  const KERNEL_OPERATIONS = [
@@ -21,6 +21,7 @@ import type { BatchRunnerGitPort } from "../runtime/unattended/batch_git";
21
21
  import type { InitiativeObservationReader } from "../runtime/unattended/types";
22
22
  import { advancePiTask } from "./imm-canary-work";
23
23
  import { batchReason } from "../runtime/unattended/batch_reasons";
24
+ import { parseLaneOffers, parseMaxParallel, resolveLaneParallel, type LaneOffer } from "../runtime/unattended/batch_lanes";
24
25
  import {
25
26
  authorizeBatch,
26
27
  projectBatchPreflight,
@@ -99,6 +100,10 @@ export interface PiBatchExecutionOptions {
99
100
  */
100
101
  reuseOnly?: boolean;
101
102
  signal?: AbortSignal;
103
+ /** Lane mode: how many children may run at once. Absent selects the serial path. */
104
+ max_parallel?: number;
105
+ /** Lane mode: Lanes someone else created, offered to the batch. */
106
+ lane_offers?: LaneOffer[];
102
107
  batchKernel?: Partial<BatchRunnerKernelPort>;
103
108
  batchGit?: BatchRunnerGitPort;
104
109
  readInitiative?: InitiativeObservationReader;
@@ -139,6 +144,10 @@ export async function executePiUnattendedBatch(
139
144
 
140
145
  if (!reuseOnly && !interactive) return { state: "rejected", ...nonInteractiveRefusal() };
141
146
 
147
+ // A lane_offers-only call resumes the recorded lane batch; refused before any gate otherwise.
148
+ const resolvedParallel = resolveLaneParallel(root, initiativeSlug, options.max_parallel, options.lane_offers);
149
+ if (resolvedParallel !== undefined) options = { ...options, max_parallel: resolvedParallel };
150
+
142
151
  // 1. Host-independent batch preflight: claim ownership, branch availability,
143
152
  // working-tree cleanliness against the authorized scope, recovery children,
144
153
  // plan digest, and base HEAD are one shared projection, so neither Host
@@ -186,8 +195,8 @@ export async function executePiUnattendedBatch(
186
195
  }
187
196
  const confirmDetails = {
188
197
  title: `Authorize Unattended Batch: ${facts.initiative_slug}`,
189
- summary: `Initiative: ${facts.initiative_slug}\nBatch branch: ${facts.batch_branch}\nPlan digest: ${facts.plan_digest}\nBudget: max_children=${facts.budget.max_children}, qa_failure_limit=${facts.budget.qa_failure_limit}`,
190
- details: `Ordered children (${facts.children.length}):\n${facts.children.map((child) => ` - ${child.task_id} (${child.slice_id}) [risk: ${child.risk}] [status: ${child.status === "already_settled" ? "completed" : "pending execution"}]`).join("\n")}${facts.excluded.length > 0 ? `\n\nExcluded children:\n${facts.excluded.map((child) => ` - ${child.task_id} (${child.slice_id}): ${child.reason}`).join("\n")}` : ""}${facts.reuse_blockers.length > 0 ? `\n\nRe-confirmation required: ${facts.reuse_blockers.join(", ")}.\nRecovery: confirm to issue a fresh authorization bound to the current plan and HEAD.` : ""}`,
198
+ summary: `Initiative: ${facts.initiative_slug}\nBatch branch: ${facts.batch_branch}\nPlan digest: ${facts.plan_digest}\nBudget: max_children=${facts.budget.max_children}, qa_failure_limit=${facts.budget.qa_failure_limit}${options.max_parallel !== undefined ? `\nLane mode: max_parallel=${options.max_parallel}` : ""}`,
199
+ details: `Ordered children (${facts.children.length}):\n${facts.children.map((child) => ` - ${child.task_id} (${child.slice_id}) [risk: ${child.risk}] [status: ${child.status === "already_settled" ? "completed" : "pending execution"}]`).join("\n")}${facts.excluded.length > 0 ? `\n\nExcluded children:\n${facts.excluded.map((child) => ` - ${child.task_id} (${child.slice_id}): ${child.reason}`).join("\n")}` : ""}${options.max_parallel !== undefined ? `\n\nParallel groups (${facts.parallel_groups.length}):\n${facts.parallel_groups.map((group) => ` - ${group.join(", ")}`).join("\n")}${facts.scope_conflicts.length > 0 ? `\n\nSerialized by overlapping scope:\n${facts.scope_conflicts.map((c) => ` - ${c.task_id} after ${c.overlaps_with.join(", ")}`).join("\n")}` : ""}` : ""}${facts.reuse_blockers.length > 0 ? `\n\nRe-confirmation required: ${facts.reuse_blockers.join(", ")}.\nRecovery: confirm to issue a fresh authorization bound to the current plan and HEAD.` : ""}`,
191
200
  planDigest: facts.plan_digest,
192
201
  signal,
193
202
  };
@@ -280,6 +289,8 @@ export async function executePiUnattendedBatch(
280
289
  now,
281
290
  kernel: kernelPort,
282
291
  git: options.batchGit,
292
+ ...(options.max_parallel !== undefined ? { max_parallel: options.max_parallel } : {}),
293
+ ...(options.lane_offers !== undefined ? { lane_offers: options.lane_offers } : {}),
283
294
  });
284
295
 
285
296
  if (report.batch_state === "rejected") {
@@ -321,10 +332,15 @@ export default function (
321
332
  ],
322
333
  parameters: Type.Object({
323
334
  initiative_slug: Type.String({ pattern: "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$" }),
335
+ // Integer minimum 1 as Claude Code declares it; multipleOf keeps the schema constructors to Number.
336
+ max_parallel: Type.Optional(Type.Number({ minimum: 1, multipleOf: 1 })),
337
+ lane_offers: Type.Optional(Type.Array(
338
+ Type.Object({ task_id: Type.String(), path: Type.String() }, { additionalProperties: false }),
339
+ )),
324
340
  }, { additionalProperties: false }),
325
341
  execute: async (
326
342
  _toolCallId: string,
327
- params: { initiative_slug: string },
343
+ params: { initiative_slug: string; max_parallel?: number; lane_offers?: Array<{ task_id: string; path: string }> },
328
344
  signal: AbortSignal | undefined,
329
345
  _onUpdate: unknown,
330
346
  ctx: ExtensionContext,
@@ -343,9 +359,14 @@ export default function (
343
359
  });
344
360
  }
345
361
 
362
+ const maxParallel = parseMaxParallel(params.max_parallel);
363
+ const laneOffers = parseLaneOffers(params.lane_offers);
364
+
346
365
  const result = await executePiUnattendedBatch({
347
366
  root: ctx.cwd,
348
367
  initiativeSlug,
368
+ ...(maxParallel !== undefined ? { max_parallel: maxParallel } : {}),
369
+ ...(laneOffers !== undefined ? { lane_offers: laneOffers } : {}),
349
370
  interactive: ctx.mode === "tui",
350
371
  signal,
351
372
  readInitiative: dependencies.readInitiative,