pi-claude-supervisor 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,54 @@
2
2
 
3
3
  All notable changes to this project will be documented here.
4
4
 
5
+ ## [0.7.1](https://github.com/btnalit/pi-claude-supervisor/compare/v0.7.0...v0.7.1) (2026-09-17)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * **policy:** judge heredoc bodies by their consumer and separate statements on newlines ([ac69208](https://github.com/btnalit/pi-claude-supervisor/commit/ac692083d824b05b7665c2864aad9478f7b367a4))
11
+ * **policy:** stop vetoing ordinary shell and scratchpad writes on the Worker's behalf ([eb72c8f](https://github.com/btnalit/pi-claude-supervisor/commit/eb72c8f267f77f4097f20c325c4087c925be5803))
12
+
13
+ ## [0.7.0](https://github.com/btnalit/pi-claude-supervisor/compare/v0.6.0...v0.7.0) (2026-09-17)
14
+
15
+
16
+ ### Features
17
+
18
+ * **config:** add Worker/Decision model and safety-limit knobs ([a12710a](https://github.com/btnalit/pi-claude-supervisor/commit/a12710a0579a03f8a836c56e85ea1a707f88621e))
19
+ * **decision:** compact Decision Worker prompts, proactive compaction, and model/usage wiring ([a423515](https://github.com/btnalit/pi-claude-supervisor/commit/a423515d7b345edb9b265795c07ff11e0a869d19))
20
+ * declare hook relay and interactive tmux contracts ([2a7db8d](https://github.com/btnalit/pi-claude-supervisor/commit/2a7db8d46ab8ee975f49a9808a37a92b7e0778a7))
21
+ * declare token-accounting and permission-authority contracts ([73e77d9](https://github.com/btnalit/pi-claude-supervisor/commit/73e77d97157091452fdb953712790e4746727665))
22
+ * **hooks:** Claude Code hook relay and Supervisor hook server ([92877f6](https://github.com/btnalit/pi-claude-supervisor/commit/92877f6b20ccaa825609ceb7fb33af7bd8997c28))
23
+ * **index:** install the Claude Code hook relay automatically in interactive tmux mode ([a0f3923](https://github.com/btnalit/pi-claude-supervisor/commit/a0f39233c52335791f0f0dbc5d306c54996a9006))
24
+ * **index:** wire token controls, cost status and docs ([bf4c341](https://github.com/btnalit/pi-claude-supervisor/commit/bf4c3411f3af3e72e003f5743ce29f2367204084))
25
+ * let adapter preflight see the interactive flag ([7c93346](https://github.com/btnalit/pi-claude-supervisor/commit/7c93346196b3ee6aff35fa72d27c23125ee3a3e7))
26
+ * permission phase and defer contracts for interactive sessions ([399683c](https://github.com/btnalit/pi-claude-supervisor/commit/399683cecdb6132c5544b0a20801b0014e261390))
27
+ * **supervisor:** anchor automatic tasks to the baseline commit, not the branch ([7b75593](https://github.com/btnalit/pi-claude-supervisor/commit/7b75593792d124cff2a1acb3dcc7b2b88ff54587))
28
+ * **supervisor:** route routine permissions through policy, account for Worker/Pi cost ([342b2c2](https://github.com/btnalit/pi-claude-supervisor/commit/342b2c2c0b94d26b9357ba436ee44d813ed07ee4))
29
+ * **tmux:** hook-driven interactive Claude sessions ([e942911](https://github.com/btnalit/pi-claude-supervisor/commit/e9429112945090462307120958cf6b91bc37fb6c))
30
+ * wire hook-driven interactive tmux supervision ([29eb6fe](https://github.com/btnalit/pi-claude-supervisor/commit/29eb6fedd9f69a19bdab11243e59320b36fd7d50))
31
+ * WorkerStatus.detached contract for kept-open sessions ([a970d89](https://github.com/btnalit/pi-claude-supervisor/commit/a970d897b9a7446c085f158d014292710d4ec95c))
32
+
33
+
34
+ ### Bug Fixes
35
+
36
+ * close post-review gaps in noop handling, redaction, reviewer abort and log rotation ([fb856d6](https://github.com/btnalit/pi-claude-supervisor/commit/fb856d6feed03183c1575f59f36f90380d1efe31))
37
+ * **cwd-lease:** quarantine unreadable leases and remove nested cgroups ([d45da59](https://github.com/btnalit/pi-claude-supervisor/commit/d45da59349832a66fdea1d59287e4f3b628ebd99))
38
+ * **decision:** surface Decision Worker and Reviewer API/abort failures ([5e1a9ea](https://github.com/btnalit/pi-claude-supervisor/commit/5e1a9ea2a88b5dfdc27d921780c74c6381b2f3e9))
39
+ * **events:** make EventLog.append O(1) in log size and add rotation ([960ab8e](https://github.com/btnalit/pi-claude-supervisor/commit/960ab8edb08c17140477ba226c341ce8934f819d))
40
+ * hand a kept-open interactive session back to the operator cleanly ([eaff8f3](https://github.com/btnalit/pi-claude-supervisor/commit/eaff8f30340599bb5d617fb997634d888a780440))
41
+ * harden the routine-permission classifier and cost accounting after review ([81d8f7d](https://github.com/btnalit/pi-claude-supervisor/commit/81d8f7db5d623a49291ef87a9e956bd3acd0cf41))
42
+ * **hooks:** keep the hook socket under the unix sun_path limit ([00a2ffd](https://github.com/btnalit/pi-claude-supervisor/commit/00a2ffdec7d59af135e3b54a53f5cfc4aa003b24))
43
+ * **index:** wire review timeout and event-log rotation; align docs ([f2b81d4](https://github.com/btnalit/pi-claude-supervisor/commit/f2b81d43e26806161988e9836b5665e34c28e201))
44
+ * **policy:** clarify deny reasons, narrow redaction, retry webhooks, raise evidence limits ([f9fcc0c](https://github.com/btnalit/pi-claude-supervisor/commit/f9fcc0c1acf6baf93de3c60ed6983f82a0b52a71))
45
+ * **supervisor:** close lifecycle-event and shutdown safety gaps ([47b9a10](https://github.com/btnalit/pi-claude-supervisor/commit/47b9a10e04e228781720da1809135f3818834890))
46
+ * **supervisor:** drive watchdog verification, tighten commit/evidence gates, replay deferred decisions ([b193441](https://github.com/btnalit/pi-claude-supervisor/commit/b1934415528231860a1f9e69db973896dcdde611))
47
+ * **tmux:** distinct prompt-phase request ids, pid-anchored hook binding, precise relay matching ([d4f6bc7](https://github.com/btnalit/pi-claude-supervisor/commit/d4f6bc7dac2359db1915217512b3c1f1eb8897ee))
48
+ * **tmux:** errored and idle turns, questions during takeover, quieter takeover notices ([d133f70](https://github.com/btnalit/pi-claude-supervisor/commit/d133f705c03601ee8df4c27bb47c1669b4f1e3ee))
49
+ * **tmux:** recover launcher-wrapped interactive sessions and preflight interactive args ([d986253](https://github.com/btnalit/pi-claude-supervisor/commit/d986253467b56c51bfb310c51f0cefe64eacbae5))
50
+ * **tmux:** type the task into an idle adopted interactive session ([acc8160](https://github.com/btnalit/pi-claude-supervisor/commit/acc8160ade5053f2affb719b782ddb119dfd510b))
51
+ * **worker:** repair dead process-group detection and tmux guardian readiness ([ea7645e](https://github.com/btnalit/pi-claude-supervisor/commit/ea7645ef388066b626c7d06e996e8e765da45d4e))
52
+
5
53
  ## [0.6.0](https://github.com/btnalit/pi-claude-supervisor/compare/v0.5.5...v0.6.0) (2026-09-16)
6
54
 
7
55
 
package/README.cn.md CHANGED
@@ -4,189 +4,389 @@
4
4
  [![npm](https://img.shields.io/npm/v/pi-claude-supervisor)](https://www.npmjs.com/package/pi-claude-supervisor)
5
5
  [![MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
6
6
 
7
- [English](README.md)
8
-
9
- 用于 Pi 的 Claude Code Worker 监督扩展。MVP 中 Pi 负责生命周期、状态机、策略门和独立验收;Worker 只是被显式启动的子进程。
10
-
11
- > `v0.5.3` 已发布为单 Worker recovery 基线。默认手动 transport 是无额外依赖的
12
- > process pipe,不是 PTY;自动模式支持 Claude JSONL 或 Supervisor 自有的 tmux bridge,被接管的
13
- > tmux session 仍仅限手动交互。当前工作树已实现
14
- > repairable/persistent 能力拆分、可取消验收/Reviewer、证据完整性门禁、启动前
15
- > preflight 和阶段进度通知;真实 Claude Code `2.1.270` 允许编辑的
16
- > repair/reacceptance 演练已在隔离临时 worktree 通过。确认的产品目标是本地开发
17
- > 完全无人值守;详见 [自动化目标](docs/autonomy-target.md)。代码进入远程仓库或
18
- > main/integration 分支仍必须经过独立边界;Supervisor 管理的直接 push/merge 请求会拒绝,
19
- > 而嵌套/自定义能力的硬边界必须由独立保护机制提供。
20
- >
21
- > **无人值守状态:** 自动模式会自主完成本地修改、测试、有限修复、验收、独立 Review
22
- > 和本地提交检查;无法形成候选时自动挂起为不可发布候选。可选出站通知不授予权限,
23
- > push 和 main/integration merge 仍必须经过独立边界。
24
-
25
- ## 关键安全边界
26
-
27
- - 不会在扩展加载时自动启动 Worker。
28
- - 不经过 shell 启动子进程。
29
- - 手动 Worker 保留小型继承环境,调用方也可以显式传入任意变量。自动 Claude Worker 继承 Supervisor 的完整环境,只移除 `CLAUDECODE`(Claude Code 用它拒绝嵌套会话);远程凭据、Git/包管理器 helper、自定义配置和网络设置都不会被过滤。
30
- - 自动模式保留完整 Claude Code 工具面,包括 Agent、Task、后台任务、插件和 MCP;会从生效的 `HOME`/`CLAUDE_CONFIG_DIR` 检查 CLI/配置,并拒绝预授权 `Bash` 的规则;在未指定时加入 Claude 的安全 `default` permission mode,使 Bash 请求仍能被 Supervisor 看到(不会移除 Bash 工具本身)。自动 tmux bridge 会在实际 spawn Claude 子进程前再次同步检查设置,启动间隙发生修改时 fail closed。适配器再添加 stream-json transport framing,并把所有 Worker 后代放入 Supervisor 自有的清理边界。由于没有同步在线用户,`AskUserQuestion` 会转换为普通文本。
31
- - 本地命令和权限行为按任务/运行时策略处理;已知的直接 remote push/main-integration 操作和 Git 元数据写入仍会拒绝或挂起,不要求同步人工响应。嵌套/自定义工具继承这些能力并随 Worker 清理,不另起第二套 Supervisor 权限循环。
32
- - Linux 上优先使用可写的 cgroup v2 清理后代进程,包括 `setsid()` 后代;不可用时回退到进程组清理。需要强制失败闭环时,embedding 集成可使用 `cgroupMode: "required"`,并会在 Claude 启动前执行 preflight。
33
- - 自动模式只接受裸的 `claude`/`claude.exe` 命令名,并从 Supervisor 的 PATH 解析、固定由操作者拥有的可执行文件(或使用 `PI_CLAUDE_SUPERVISOR_TRUSTED_CLAUDE` 固定路径);显式路径和可写/不可信位置会被拒绝。自定义工具和嵌套 Worker 是受信任能力,硬性的 remote/main 边界仍必须由此进程之外的独立受保护边界提供。
34
- - Worker 声称完成只会进入 `verifying`,不能作为成功证据。
35
- - 默认独立验收命令为 `git diff --check`。
36
- - 目标是任务启动后本地开发无人值守:Worker 可以修改、测试、修复和本地提交;Supervisor 管理的 remote push 或合并到 `main`/integration 分支请求仍会拒绝,嵌套/自定义能力的最终 remote/main 边界必须由独立保护机制提供。
37
- - 扩展运行时不执行 merge、deploy、release 或 publish;远程/main 集成和仓库 Release 必须经过独立受保护边界。
38
- - 默认 4 小时总时限、20 分钟无输出 watchdog 超时即停止 Worker;paused 期间不消耗无输出预算,resume 会重建基准但不会重置总时限。嵌入调用方可将对应选项设为 `0` 关闭。
39
- - 验收命令、仓库证据收集和独立 Reviewer 共用 abort signal,人工 stop/shutdown 不必等待完整超时。
40
-
41
- ## 安装和使用
42
-
43
- 需要 Pi 0.85+ 和 Node.js 22.19+:
7
+ [English](README.md) · 简体中文
8
+
9
+ ## 这是什么
10
+
11
+ pi-claude-supervisor 是一个标准的 [Pi](https://pi.dev) agent 扩展包,用于监督
12
+ Claude Code 完成无人值守的本地开发。Pi 负责任务的生命周期、状态机、策略决策、
13
+ 验收检查和独立 Review;Claude Code 是负责实际编辑的 Worker。这个扩展只需要一次
14
+ `pi install`:Pi 会自行发现并加载它,没有单独的构建步骤或二进制文件,在 Pi 内部
15
+ 除了环境变量之外也没有任何需要配置的地方。
16
+
17
+ 有一条 Worker 永远不能越过的硬边界,无论它自己的权限设置如何:它不能 push 到
18
+ 远程仓库、合并进 `main` 或 integration 分支、创建 pull request,也不能执行任何
19
+ 远程 CLI 变更;`.git` 元数据写入和对受保护分支的破坏性改写一律拒绝。除此之外的
20
+ 一切——编辑、测试、shell 命令、本地提交——都按你配置的策略执行。扩展本身在运行时
21
+ 从不执行 merge、deploy、release 或 publish。
22
+
23
+ 任务启动后,这个循环是这样运作的:
24
+
25
+ - Worker 执行一轮;一轮结束时(`turn_completed`),Pi 的 Decision Worker——一个
26
+ 持久化、只有只读工具的 Pi session——会选择继续、重定向、回答问题、验收、停止
27
+ 或挂起任务。
28
+ - `verify` 运行验收检查(默认是 `git diff --check`,或者来自 `--spec` 文件的检查)。
29
+ - 一个独立的 Reviewer——全新的只读 Pi session——返回通过、需要修改或需要人工介入。
30
+ - 需要修改时会给 Worker 发送一轮有限的修复(最多 `maxRepairRounds` 轮);通过后
31
+ 产出一个 `completed` 候选。
32
+ - 无法解决的工作会被挂起为 `blocked`(不可发布的候选,而不是崩溃);崩溃和超时
33
+ 则变为 `failed`。
34
+ - 每个终态都会发出候选通知,既在 Pi UI 中显示,也可以选择发到 webhook(企业微信
35
+ 或通用 JSON 格式,失败会重试)。
36
+
37
+ ## 快速开始
38
+
39
+ 需要 Pi 0.85+、Node.js 22.19+、Claude Code 2.1.270+(交互式 hooks 已在 2.1.273
40
+ 上验证),cgroup 和 tmux 相关功能需要 Linux。
41
+
42
+ 像安装任何其他 Pi 扩展一样安装它:
44
43
 
45
44
  ```text
46
45
  pi install npm:pi-claude-supervisor
47
46
  ```
48
47
 
49
- 在 Pi 中使用。手动/兼容模式默认使用 process-pipe。要启用事件驱动的 Pi Decision Worker,使用 Claude JSONL 自动模式:
48
+ 这就是全部安装步骤——Pi 会直接加载包中的 `./src/index.ts` 扩展并注册
49
+ `/supervise` 命令。配置只通过环境变量完成,在启动 Pi 之前设置(或写入
50
+ `~/.config/pi-claude-supervisor/env`):
50
51
 
51
52
  ```bash
52
53
  export PI_CLAUDE_SUPERVISOR_MODE=auto
53
- export PI_CLAUDE_SUPERVISOR_WORKER='claude --permission-mode acceptEdits'
54
- # 可选:候选/失败通知;generic 或 wecom
54
+ export PI_CLAUDE_SUPERVISOR_TRANSPORT=tmux
55
+ # 可选:候选/失败通知
55
56
  export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_URL='https://example.invalid/webhook'
56
57
  export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_FORMAT=generic
57
- # export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_SECRET='shared-secret'
58
58
  ```
59
59
 
60
- 自动模式支持 `claude-jsonl` 和 Supervisor 自有的 tmux bridge;JSONL 的 `result`、
61
- `control_request` 和进程 `exit` 事件会唤醒 Decision Worker。tmux bridge 把结构化记录
62
- 通过同一个 live PTY 的私有 terminal framing 传回适配器,不创建独立 JSONL sidecar;
63
- `adopt-tmux` 仍是手动模式。真实 Claude 检查默认从 `PATH` 解析当前 CLI(包括安装器提供的 `latest` 路径),支持 Claude Code `2.1.270` 及以上版本;本轮的已记录演练版本为 `2.1.270`。
60
+ 然后在任意 Pi session 中:
61
+
62
+ ```text
63
+ /supervise start implement the requested change
64
+ /supervise adopt-tmux my-tmux-session implement the requested change
65
+ ```
64
66
 
65
- 然后在 Pi 中使用:
67
+ 用 `/supervise status <task-id>` 或 `/supervise sessions` 观察任务;对于 tmux
68
+ transport,可以直接用两者打印出的 `tmux -S <socket> attach -t <session>` 命令
69
+ attach。`/supervise stop <task-id>` 会关闭任务;在交互式 tmux transport 下,
70
+ 完成的任务默认会保持会话开启(见下文)。
71
+
72
+ ## 模式与 transport
73
+
74
+ `PI_CLAUDE_SUPERVISOR_MODE=auto`(或 `PI_CLAUDE_SUPERVISOR_AUTOMATION=1`)启用
75
+ 自动监督——也就是上面的 Decision Worker/Reviewer 循环。不设置时,`/supervise`
76
+ 仍然暴露所有命令,但 Worker 运行时没有这个循环。
77
+
78
+ | Transport | `TRANSPORT` | `TMUX_MODE` | Worker 以什么形式运行 | 适用场景 |
79
+ | --- | --- | --- | --- | --- |
80
+ | 交互式 tmux | `tmux` | `interactive`(默认) | 在 tmux pane 中运行真实、未经修改的 Claude Code TUI,由 Claude Code hooks 驱动 | 想要观察或偶尔亲自输入 Claude 正在使用的那个会话 |
81
+ | Headless JSONL | `jsonl`(自动模式下默认) | – | `claude -p --input-format stream-json`,没有终端界面 | 每一个与权限相关的命令都必须对 Supervisor 可见 |
82
+ | tmux bridge | `tmux` | `bridge` | Claude 的 stream-json 协议,渲染进 tmux pane | 需要一个可见的 pane,但使用较早的结构化(非 hook)transport |
83
+ | 手动(process-pipe) | `process-pipe`(`MODE` 未设置时默认) | – | Worker 的 stdin/stdout 作为纯文本 | 只暴露命令,不启用自动监督 |
84
+
85
+ ## 交互式 tmux 模式(hooks)
86
+
87
+ `PI_CLAUDE_SUPERVISOR_TRANSPORT=tmux` 默认在 tmux pane 中运行真实、未经修改的
88
+ Claude Code TUI——就是你自己运行 `claude` 时看到的那个界面——而不是下文描述的
89
+ 结构化 stream-json bridge。你可以随时 attach 到打印出的 `attach=...` 命令上观察,
90
+ 或者亲自输入;Pi 通过 Claude Code 自身的 hooks 上报事件,而不是抓取屏幕文字。
91
+
92
+ 当扩展以交互模式(默认 `TMUX_MODE`)加载
93
+ `PI_CLAUDE_SUPERVISOR_TRANSPORT=tmux` 时,会自动把它用到的八个 Claude Code hook
94
+ 事件的小型 relay 命令安装进 `~/.claude/settings.json`(或
95
+ `$CLAUDE_CONFIG_DIR/settings.json`)——这个安装是幂等的,并且只会在 Pi UI 中
96
+ 提示一次。设置 `PI_CLAUDE_SUPERVISOR_AUTO_INSTALL_HOOKS=0` 可以关闭自动安装;
97
+ `/supervise uninstall-hooks` 会移除这一条目,`/supervise install-hooks` 仍然
98
+ 可以用来手动安装。在没有 Supervisor 监听的 Claude session 中,relay 本身只是
99
+ 一个耗时约 1 毫秒的空操作。owned 的 `/supervise start` 完全不依赖这个机制——
100
+ 它会传入自己的 `--settings` 文件——但 `/supervise adopt-tmux` 运行在你自己的
101
+ Claude Code 配置中,需要那里已经装好 relay。
66
102
 
67
103
  ```text
68
- /supervise capabilities
69
- /supervise start inspect the current repository
70
- /supervise start --spec ./task.json
71
- /supervise poll
72
- /supervise sessions
73
- /supervise recover [--takeover] <task-id>
74
- /supervise stop human requested stop
75
- /supervise verify
76
- /supervise approve <task-id> allow|deny [request-id]
77
- /supervise takeover <task-id>
78
- /supervise resume-auto <task-id>
104
+ /supervise start <task>
105
+ /supervise adopt-tmux <tmux-session> <task>
79
106
  ```
80
107
 
81
- `--spec` 接受 JSON 文件;验收命令始终使用 argv 执行,不经过 shell。例如:
108
+ Pi 会在 Claude 结束一轮对话时(`Stop`;轮中 API/模型失败会以 `StopFailure` 到达
109
+ 并按"出错的一轮"交给 Decision Worker 重试;提示符空闲一分钟且没有结束信号时作为
110
+ 兜底把这一轮收尾)、Claude 即将向你展示真实权限提示时(仅此时——其余每一次普通
111
+ 工具调用都交给你自己的 Claude Code 权限模式处理)、Claude 询问 `AskUserQuestion`
112
+ 时(Decision Worker 会选择一个答案,Claude 以普通文本形式继续,与 headless 模式
113
+ 中完全一致),以及 session 退出时介入。在展示提示之前的 `PreToolUse` 否决点只会
114
+ 拒绝已知的直接远程 push/merge/PR 或其他破坏性/受保护分支操作(或转发一个
115
+ `AskUserQuestion`);它从不干预普通的编辑、读取或本地命令——那些请求会直接进入
116
+ 你自己的权限模式,Pi 完全不做决策。
117
+
118
+ **这对安全边界意味着什么。** 交互式模式有意跳过 headless 模式那条"拒绝设置中
119
+ 预授权 `Bash` 或 `auto`/`bypassPermissions` 模式"的检查:你自己的 Claude 配置
120
+ 决定 Claude 无需询问就能做什么,和你亲自运行 Claude 时完全一样。凡是你的设置
121
+ 已经放行的操作都不会到达 Decision Worker;它只在 Claude 本来要问*你*的地方做
122
+ 判断。硬边界(远程 push/merge/PR、远端 CLI 变更、`.git` 写入、受保护分支的
123
+ 破坏性改写)由 `PreToolUse` 强制执行,与权限模式无关——已在 Claude Code 2.1.273
124
+ 的 `auto` 模式下实测——这也是该模式在你自己的设置之外唯一的保证。需要让每个
125
+ `Bash` 调用都经过 Supervisor 时,请使用 headless(`bridge`)模式。
126
+
127
+ **接管空闲会话。** `adopt-tmux` 只在 Claude 空闲停在提示符时才把任务敲进去;
128
+ 接管时正在跑的一轮会保留其当前工作,等它下一次 `Stop` 再判断。
129
+
130
+ **人机协同。** 如果你在已 attach 的 session 中输入内容,自动化会暂停
131
+ (`human_takeover`,以警告形式呈现),直到你执行 `/supervise resume-auto
132
+ <task-id>`;你接管期间完成的那一轮会在此时重放给 Decision Worker,因此不会
133
+ 丢失已经完成的工作。
134
+
135
+ **完成后把会话交还给你。** 与其他 transport 不同,任务完成后默认只是让 Pi 与
136
+ 该会话断开,而不是关闭它,方便你在同一窗口中继续工作或查看 Claude 做了什么;
137
+ `/supervise stop <task-id>` 可以显式关闭它,被阻塞或失败的候选仍会像以往一样
138
+ 停止 Worker。设置 `PI_CLAUDE_SUPERVISOR_CLOSE_WORKER_ON_COMPLETION=1` 可恢复
139
+ 旧的"完成即关闭"行为。这次交还是干净的,而不只是断开连接:在报告候选就绪之前,
140
+ Pi 会把每个进程从自己的私有 cgroup 移到其父进程(而不是杀掉它们)并停止 guardian
141
+ 进程,tmux server 和 pane 会保持原样——会话能在 Pi 重启后继续存在,不会留下任何
142
+ 未完成的清理。之后它就是一个普通的、没有 Supervisor 附着的 tmux session;
143
+ `tmux -S <socket> attach -t <session>` 可以直接连上去,`/supervise adopt-tmux`
144
+ 也可以像对待其他外部创建的 session 一样重新接管它。
145
+
146
+ **成本核算的限制。** TUI 的 `Stop` hook 没有 `total_cost_usd` 或 token `usage`
147
+ (这些字段只出现在 Claude 自己的 `result` stream-json 记录中,而 TUI 不会产生
148
+ 这种记录),因此交互模式下的成本统计只计算轮次,不计算费用;`--max-budget-usd`
149
+ 同样不可用(Claude Code 只在 `-p` 模式下强制执行它),也不会传给交互式启动。
150
+ 如果设置了 `autonomy.maxWorkerCostUsd`,请预期它在交互模式下不起作用;需要
151
+ 硬性成本上限时请使用 bridge/jsonl 模式。
152
+
153
+ **信任对话框。** Claude Code 第一次在某个目录中运行时,会先弹出它自己的
154
+ 一次性"是否信任该文件夹"对话框,然后 hook 才会开始生效。由 `/supervise start`
155
+ 启动的会话,启动器会自动接受它——且仅当 pane 所在目录就是任务目录时;被接管的
156
+ 会话是你自己启动的,你早已回答过。
157
+
158
+ ## Headless 模式(JSONL)
159
+
160
+ `PI_CLAUDE_SUPERVISOR_TRANSPORT=jsonl` 以 `claude -p --input-format
161
+ stream-json` 的方式运行 Claude,完全没有终端界面;一旦设置
162
+ `PI_CLAUDE_SUPERVISOR_MODE=auto`,它就是默认 transport。Claude 发出的每一个
163
+ 权限请求都由 Supervisor 回答——拒绝列表、任务目录内的常规编辑、以及只读/本地
164
+ 开发类 shell 命令由策略直接回答,其余都交给 Decision Worker。`worker_usage`
165
+ 事件携带来自 Claude 自身 `result` 记录的完整 token 和费用信息,因此
166
+ `--max-budget-usd` 以及下文的 token/费用统计都能按预期工作。当任何操作都不能
167
+ 在 Supervisor 看不到的情况下运行,或者你不需要 attach 时,使用这个 transport。
168
+
169
+ ## 安全边界
170
+
171
+ - 无论策略或权限模式如何,始终拒绝:远程 push、合并/PR 进 `main` 或 integration
172
+ 分支、其他远程 CLI 变更、`.git` 元数据写入,以及对受保护分支的破坏性改写
173
+ (`reset`、`update-ref`、`symbolic-ref`,或带删除/移动/强制标志的 `branch`)。
174
+ 策略看不透的 shell 参数(`$VAR`、`$(…)`、通配符)只在可能触及这条边界的命令上
175
+ 被尽力拦截——git、gh、npm/pnpm/yarn、curl/wget/ssh、嵌套的 `claude`,以及
176
+ `eval`、`sh -c`、`xargs`、`find -exec` 之类的解释器/执行器。带引号分隔符的
177
+ heredoc 正文按其消费者判断:交给 shell 就是命令,交给 `cat > file` 或
178
+ `git commit -m` 就是数据。除此之外的一切(`for f in …; do echo "$f"`、
179
+ `rm -rf ./dist`、写入 Claude 自己的 scratchpad)都按配置的策略处理——由
180
+ Claude 自己的权限模式决定,和你亲自运行 Claude 时一样。
181
+ - `autonomy.permissionAuthority`(`policy` | `hybrid` 默认 |
182
+ `decision-worker`)决定谁来回答权限请求——headless 模式下是每一个请求,交互式
183
+ tmux 模式下只是那些 Claude 本来会弹窗问你的请求:`hybrid` 会让策略独自回答
184
+ 任务目录内的常规编辑和本地只读/开发类 shell 命令,并把所有含糊的请求发给
185
+ Decision Worker(策略拒绝总是直接生效)。
186
+ - **看 baseline,不看分支。** 任何分支,包括 `main`,都可以被监督;候选只需要
187
+ 从记录的 baseline commit 派生出来(`merge-base --is-ancestor`)。任务过程中
188
+ 切换分支会被记录(`worker_branch_changed`),而不是被拒绝;落在受保护分支上
189
+ 的候选会在通知中报告(`branch`、`protectedBranch`),而不是被挂起。
190
+ `checkout`/`switch` 到 `main` 是允许的;只有对受保护分支名的破坏性改写才会
191
+ 被拒绝。Claude Code 自己"默认分支上先切分支"的建议只是提示,不会被强制执行。
192
+ - Worker 命令不经过 shell 启动。自动模式只接受裸的 `claude` 命令名,并固定
193
+ 由操作者拥有的、不可写的可执行文件路径(可用
194
+ `PI_CLAUDE_SUPERVISOR_TRUSTED_CLAUDE` 显式固定)。
195
+ - Linux 上,cgroup v2 边界会清理每一个后代进程,包括 `setsid()` 后代;
196
+ `required` 模式会 fail closed,而不是回退到其他清理方式。
197
+ - 默认 4 小时总时限、20 分钟无输出 watchdog 会停止 Worker;嵌入方调用可以修改或
198
+ 关闭任一项(`deadlineMs`、`noOutputTimeoutMs`)。
199
+ - 验收命令、证据收集和 Reviewer 共用一个 abort signal,因此 stop 或 shutdown
200
+ 不必等待完整的命令或模型超时。
201
+ - 每个任务只持有一个 cwd 租约;并发任务需要各自独立的 worktree。
202
+
203
+ ## 任务 spec
204
+
205
+ `--spec file.json` 接受如下格式:
82
206
 
83
207
  ```json
84
208
  {
85
- "goal": "实现请求的修改",
209
+ "goal": "Implement the requested change",
86
210
  "scope": ["src/"],
87
- "constraints": ["保持公共 API 兼容"],
88
- "forbidden": ["不要发布构建产物"],
211
+ "constraints": ["Keep the public API compatible"],
212
+ "forbidden": ["Do not publish artifacts"],
89
213
  "acceptance": [
90
- { "id": "tests", "name": "tests", "command": "npm", "args": ["test"], "required": true }
214
+ { "id": "tests", "name": "tests", "command": "npm", "args": ["test"], "required": true, "timeoutMs": 120000 }
91
215
  ],
92
216
  "maxRepairRounds": 3,
93
217
  "autonomy": {
94
218
  "unattended": true,
95
219
  "requireLocalCommit": true,
96
- "maxDecisionRetries": 2
220
+ "maxDecisionRetries": 2,
221
+ "permissionAuthority": "hybrid",
222
+ "maxWorkerCostUsd": 20
97
223
  }
98
224
  }
99
225
  ```
100
226
 
101
- 候选/失败通知的 generic JSON 格式为(旧 human-intervention webhook 名称保持兼容):
102
-
103
- ```json
104
- {
105
- "schema": "pi-claude-supervisor/candidate/v1",
106
- "event": "candidate_status",
107
- "task": { "id": "...", "goal": "...", "cwd": "..." },
108
- "worker": { "id": "..." },
109
- "reason": "...",
110
- "status": "ready|blocked|failed",
111
- "deliverable": false,
112
- "note": "This notification does not grant remote push or main/integration merge permission."
113
- }
114
- ```
115
-
116
- 当前 webhook 只是出站候选通知,不直接接受批准命令;显式 stop、takeover 等兼容控制仍通过 Pi。
117
- 自动模式会将 Decision Worker 会话持久化到状态目录。Pi 非正常重启后,`/supervise sessions`
118
- 会显示 `recoverable` 任务;显式执行 `/supervise recover [--takeover] <task-id>` 会恢复 Decision Worker 上下文并
119
- 重新启动 Claude Worker,不会静默恢复或重复执行任务。旧 Pi 进程已退出且租约确认旧 Worker
120
- 进程组已消失且 cgroup 仍是真实、可读取的空边界时,才可显式添加 `--takeover`;缺失、仍存活或无法确认的 Worker 会被拒绝。自动 Worker 会保留已验证为空的 cgroup,直到所属 cwd 租约释放,以覆盖正常退出后 Pi 在租约收尾前崩溃的窗口;释放租约时再删除它。租约获取时会先持久化“尚未 spawn”的启动标记;适配器会在创建 cgroup/socket 前持久化生成的资源计划,再分阶段记录 cgroup identity 和 tmux server identity,启动期崩溃恢复会检查并清理已创建但尚未完成登记的空资源,而不是假定没有资源。只有确认旧 owner 已退出后才能接管残留标记。租约拒绝被替换或改名的 cgroup。自动 tmux 还要求确认 Supervisor 所有、tmux server identity 已死亡、私有 tmux session 已消失,并先持久化 cleanup-pending 事务,再原子保留私有 socket;替换会复用旧租约记录,写入新租约后才释放保留并删除 guardian 留下的空 cgroup;若恢复中断,新的 Supervisor 会先协调该待清理事务。手动 owned tmux
121
- Worker 可在重启后使用 `adopt-tmux`,而不是 takeover;自动 bridge 会由 parent-death guardian
122
- 在 Supervisor 消失时终止,只有通过上述证据检查的 `recover --takeover` 才能重新取得 cwd lease。
123
- 自动模式下,Decision Worker 在任务授权范围内自动处理普通问题、测试失败和修复轮次,记录假设和证据;无法形成可交付候选时自动挂起并保留证据,而不是要求人工必须在线。可通过 `PI_CLAUDE_SUPERVISOR_REQUIRE_LOCAL_COMMIT=0` 或 task `autonomy.requireLocalCommit` 关闭本地 commit 要求,但自动模式仍要求有效 Git baseline 和非保护 worktree;远程 push 和 main/integration merge 仍由独立边界控制。
124
-
125
- `v0.5.0` 已完成并发布“多命令验收—独立只读 Reviewer—结构化修复轮次—再次验收”闭环。
126
- 任务可通过 API 或 JSON spec 提供 `goal`、`scope`、`constraints`、`forbidden`、多个
127
- `acceptance` 命令和 `autonomy` 控制;旧的纯文本任务继续使用默认 `git diff --check`。
128
- Reviewer 只能使用 `read`、`grep`、`find`、`ls`,不会修改工作树或批准权限。自动模式在
129
- Worker 启动前捕获 git baseline,要求完整的 baseline-relative tracked/commit/untracked evidence,
130
- 并在默认情况下要求 Worker 在非保护分支本地 commit;无效输出、证据不完整、重复 finding、P0/P1 或预算耗尽
131
- 会自动挂起候选。自动模式拒绝 process-pipe,并在模型执行前检查目录、可执行文件、依赖
132
- 和 cgroup;Claude 的完整工具、Agent/Task、插件、MCP、网络和环境会保持可用。自动模式会在未指定时加入安全的 `default` permission mode,并拒绝 Bash 预授权;Bash 仍通过 Supervisor 可见的 permission request 使用。详见 [自动化目标](docs/autonomy-target.md)。协同多 Worker 属于后续独立开发阶段,
133
- 自动模式只接受裸的直接 Claude 命令名,会固定解析后的操作者拥有的可执行文件;任意自定义可执行文件和显式可执行路径会在自动模式拒绝。需要固定路径时设置 `PI_CLAUDE_SUPERVISOR_TRUSTED_CLAUDE`。自定义工具和嵌套 Worker 的 remote/main 权限必须由独立 host/仓库边界保护。
134
-
135
- ### tmux/PTY 交互模式
136
-
137
- 如果希望在可见的 Claude Code 终端中工作,可显式启用 tmux transport:
227
+ 验收命令始终使用 argv 执行,不经过 shell。纯文本任务(不带 `--spec`)会变成一个
228
+ 带默认 `git diff --check` 验收检查(120 秒超时)和下文环境默认值的 `goal`。
229
+
230
+ ## 配置参考
231
+
232
+ 环境变量(或 `~/.config/pi-claude-supervisor/env`),均以 `PI_CLAUDE_SUPERVISOR_`
233
+ 为前缀;完整模板见 `.env.example`。
234
+
235
+ | 变量 | 默认值 | 含义 |
236
+ | --- | --- | --- |
237
+ | `MODE` | 未设置(手动) | `auto` 启用自动监督(Decision Worker + Reviewer 循环) |
238
+ | `AUTOMATION` | 未设置 | `1` 等价于 `MODE=auto` |
239
+ | `TRANSPORT` | 自动模式下 `jsonl`,否则 `process-pipe` | `jsonl` \| `tmux` \| `process-pipe`(仅手动模式) |
240
+ | `TMUX_MODE` | `interactive` | `interactive`(通过 hooks 驱动真实 TUI) \| `bridge`(pane 中的 stream-json) |
241
+ | `AUTO_INSTALL_HOOKS` | `true` | 仅交互式 tmux 模式:加载时自动把 hook relay 安装进用户 Claude 配置;`0` 关闭自动安装 |
242
+ | `CLOSE_WORKER_ON_COMPLETION` | `false` | 仅交互式 tmux:完成时关闭 Worker/session,而不是保持开启 |
243
+ | `CGROUP_MODE` | `auto` | `off` \| `auto` \| `required`;自动模式在 Linux 上要求 cgroup;`required` 只在手动(非自动)tmux Worker 上会被拒绝;自动模式在 Linux 上总是使用 `required` |
244
+ | `TMUX_SOCKET` | 未设置(默认 tmux server) | 接管非默认 tmux server 时使用的 socket 路径 |
245
+ | `WORKER` | `claude` | Worker 命令;可以包含参数 |
246
+ | `NODE` | 未设置(从 `PATH` 解析) | 显式 `node` 可执行文件路径,用于 Bun 编译版 Pi |
247
+ | `TRUSTED_CLAUDE` | 未设置 | 显式固定预期的解析后 Claude 可执行文件身份 |
248
+ | `STATE_DIR` | `~/.pi/agent/claude-supervisor` | Supervisor 状态目录 |
249
+ | `CWD_LEASE_DIR` | `<state>/cwd-leases` | 共享的 cwd 租约注册目录 |
250
+ | `WORKER_ENV` | 未设置 | 传给手动 Worker 的环境变量名逗号分隔列表 |
251
+ | `HUMAN_WEBHOOK_URL` | 未设置 | 出站候选/失败通知的目标地址 |
252
+ | `HUMAN_WEBHOOK_FORMAT` | `generic` | `wecom` \| `generic` |
253
+ | `HUMAN_WEBHOOK_SECRET` | 未设置 | HMAC 签名密钥;以 `x-pi-supervisor-signature` header 发送 |
254
+ | `UNATTENDED` | `true` | 任务无需同步人工回调即可运行 |
255
+ | `REQUIRE_LOCAL_COMMIT` | `true` | 完成前要求在候选所在分支上有本地 commit |
256
+ | `MAX_DECISION_RETRIES` | `2`(0–10) | Decision Worker 调用超时或失败(429/529、网络、鉴权)时的重试次数 |
257
+ | `PERMISSION_AUTHORITY` | `hybrid` | `policy` \| `hybrid` \| `decision-worker` |
258
+ | `WORKER_MAX_BUDGET_USD` | 未设置 | 作为 `--max-budget-usd` 传入的硬上限;交互式 tmux 下不可用 |
259
+ | `WORKER_MODEL` | 未设置(Claude 自身默认值) | Claude Worker 的 `--model` |
260
+ | `WORKER_AUTOCOMPACT_TOKENS` | 自动模式默认 `200000` | 每轮上下文上限;`0` 保留 Claude 自身默认值 |
261
+ | `WORKER_MCP_CONFIG` | 未设置 | 作为 `--strict-mcp-config --mcp-config` 传入的路径,限制 Worker 可用的 MCP server |
262
+ | `DECISION_MODEL` | 未设置(Pi 默认) | Pi Decision Worker 使用的 `provider/model-id`,格式与 Pi 列出的一致 |
263
+ | `REVIEWER_MODEL` | 未设置(Pi 默认) | 独立 Reviewer 使用的 `provider/model-id` |
264
+ | `DECISION_COMPACT_TOKENS` | `60000` | 持久化 Decision Worker session 超过此大小时主动 compact;`0` 关闭该功能 |
265
+ | `PROGRESS_HEARTBEAT_MS` | `60000` | 同一阶段重复进度通知之间的最小间隔 |
266
+ | `DECISION_SESSION_RETENTION_DAYS` | `30` | 启动时清理早于此天数的已关闭 Decision Worker session 记录;`0` 表示永久保留 |
267
+ | `EVIDENCE_MAX_BYTES` | `1048576`(1 MiB) | 每个任务收集的最大仓库证据字节数 |
268
+ | `EVIDENCE_MAX_UNTRACKED_FILES` | `512` | 每个任务作为证据收集的最大未跟踪文件数 |
269
+ | `REVIEW_TIMEOUT_MS` | `600000`(10 分钟) | 每轮独立 Reviewer 的总预算,含一次针对 provider 错误的重试 |
270
+ | `EVENT_LOG_MAX_BYTES` | `67108864`(64 MiB) | `events.jsonl` 达到该大小后滚动,保留 5 份滚动文件 |
271
+
272
+ ## 恢复、租约与状态
273
+
274
+ Pi 非正常重启后,`/supervise sessions` 会列出可恢复的任务;`/supervise recover
275
+ [--takeover] <task-id>` 会恢复 Decision Worker 上下文并启动一个新的 Claude
276
+ Worker,它不会静默恢复或重复执行任务。只有在租约证明旧 Worker 的进程组已经
277
+ 消失、其 cgroup 是真实可读的空边界时(对 tmux 而言,还要求私有 tmux session
278
+ 也已消失)才应添加 `--takeover`;缺失或无法确认的证据会被拒绝,而不是被强行
279
+ 接管。`/supervise recover` 不会持久化原始任务是否为交互式;它在恢复时根据当前
280
+ 的 `TRANSPORT`/`TMUX_MODE` 配置来判断,因此在启动任务和恢复任务之间请不要
281
+ 改变这两个配置。
282
+
283
+ 每个任务在 `CWD_LEASE_DIR` 下持有一个 cwd 租约;并发任务需要各自独立的
284
+ worktree。无法读取的租约记录(损坏的 JSON、异常的结构)会被隔离到 quarantine
285
+ 目录,而不会阻塞其他查找;`/supervise sessions` 会列出当前被隔离的记录,方便
286
+ 操作者检查和清理。
287
+
288
+ 事件以 append-only 的 JSONL 形式写入 `<STATE_DIR>/events.jsonl`,其中
289
+ `worker_output` 有大小上限,日志会在超过 `EVENT_LOG_MAX_BYTES` 后滚动。每个
290
+ 任务的 Decision Worker session 都持久化为状态目录下独立的 JSONL 文件,由
291
+ `DECISION_SESSION_RETENTION_DAYS` 负责清理。
292
+
293
+ ## 通知
294
+
295
+ 每个终态(`completed`、`blocked`、`failed`)都会在 Pi UI 中发出候选通知,如果
296
+ 设置了 `HUMAN_WEBHOOK_URL`,还会以 `wecom` 或 `generic` JSON 格式发到 webhook,
297
+ 设置了 `HUMAN_WEBHOOK_SECRET` 时会附带签名。被挂起并提出问题的候选会发出一条
298
+ 单独的"需要你"通知;人工接管(你在会话里敲了字)只在 Pi 界面提示,因为你本来就在。当通知涉及 tmux session 时,两种通知
299
+ 都会带一个 `attach` 字段,内容是可直接执行的 `tmux -S <socket> attach -t
300
+ <session>` 命令,以及一份费用摘要(`CandidateNotice.usage`:费用、Worker
301
+ 轮次/token、Pi token、decision 和 reviewer 调用次数)。webhook 投递会对瞬时
302
+ 错误(网络、429/5xx)重试。通知只是出站单向的:收到通知不授予任何批准权限,
303
+ webhook 也不能把命令推回 Pi——需要那样做时请使用 `/supervise
304
+ send`/`approve`/`takeover`。
305
+
306
+ ## Token 消耗与成本控制
307
+
308
+ 以下数据来自一次真实的无人值守 review 任务(总耗时 29 分钟):
309
+
310
+ | 组成部分 | 轮次/调用次数 | Token | 花费 |
311
+ | --- | --- | --- | --- |
312
+ | Claude Code Worker | 70 轮 | 15.5M cache-read + 370k cache-write + 100k output | $18.46 |
313
+ | Pi Decision Worker | 30 次模型调用 | 约 1.0M(91k 未缓存 + 914k cache-read) | $0.04 |
314
+
315
+ 花费几乎全部来自 Worker,而不是 Supervisor 自身的 Decision Worker 或 Reviewer
316
+ 调用。这次运行中 Worker 每轮平均消耗约 22 万 token 的上下文,原因是它以单个
317
+ 长期 `-p` session 运行在 1M token 窗口下,从未触发过 compact;一次普通的
318
+ Claude Code 轮次仅系统提示词就要消耗约 2.4 万 prompt token,与配置了哪些 MCP
319
+ server 无关。30 次 Decision Worker 调用中有 28 次是权限请求;Decision Worker
320
+ 推翻确定性 policy 的情形有 4 次(拒绝下载和任务目录之外的写入)——这正是默认
321
+ `permissionAuthority` 选择 `hybrid` 而不是 `policy` 的原因。把这 28 次请求
322
+ 回放到实际发布的 `isRoutinePermission` 分类器,有 4 次可在本地直接回答;那次
323
+ 任务以内联 `node -e` 脚本和 `$(...)` 替换为主,这两类永远不算例行操作。普通
324
+ 实现类任务主要是 cwd 内的 `Edit`/`Write`、`npm test` 和 `git
325
+ status/diff/add/commit`,这些都是例行操作,Decision Worker 调用次数会下降
326
+ 得多得多。
327
+
328
+ 各项开关及其默认值和取舍:
329
+
330
+ - `PERMISSION_AUTHORITY`(`policy` | `hybrid` 默认 | `decision-worker`):
331
+ `hybrid` 会让确定性 policy(`src/policy.ts` 的 `isRoutinePermission`)直接
332
+ 回答任务目录内的常规文件编辑和本地只读/开发类 shell 命令,其余请求以及任何
333
+ policy 拒绝仍会发给 Decision Worker。它主要节省的是延迟和 Decision Worker
334
+ 的上下文大小,而不是费用:上面的 30 次调用本身只花了 $0.04。
335
+ - `WORKER_MODEL` / `--model`:Opus 级和 Sonnet 级模型之间大约相差 5 倍价格,
336
+ 是账单上最大的单一杠杆;这是操作者自己的选择,Supervisor 不会替你决定。
337
+ - `WORKER_AUTOCOMPACT_TOKENS`(自动模式默认 200000;`0` 保留 Claude 自身默认
338
+ 值):限制每轮 Worker 的上下文大小,避免像本例一样持续累积到约 22 万
339
+ token/轮;能节省几十个百分点,但会牺牲一些上下文质量。
340
+ - `WORKER_MAX_BUDGET_USD` / `autonomy.maxWorkerCostUsd`:作为
341
+ `--max-budget-usd` 传给 Claude,并由 Supervisor 根据 Worker `result` 的
342
+ 累计花费再次核对;这是一个上限而不是节省手段,达到上限的任务会连同证据一起
343
+ 被挂起。
344
+ - `WORKER_MCP_CONFIG`(`--strict-mcp-config --mcp-config`):限制 Worker 只能
345
+ 使用列出的 MCP server;它约束的是 Worker 能触达的范围,而不是普通轮次约
346
+ 2.4 万 token 的固定开销。
347
+ - `DECISION_MODEL` / `REVIEWER_MODEL`(`provider/model-id`,例如
348
+ `anthropic/claude-haiku-4-5-20251001`):Pi Decision Worker 和 Reviewer
349
+ 使用的模型。本例中 Pi 侧花费本就只有几美分,换更便宜的模型主要是换取延迟,
350
+ 而不是显著省钱。
351
+ - `DECISION_COMPACT_TOKENS`(默认 60000;`0` 关闭):当持久化的 Decision
352
+ Worker session 估算的上下文超过该阈值时主动 compact,并在 compact 之后的
353
+ 下一次 prompt 里重新发送一次启动指令。
354
+
355
+ Supervisor 记录的是实际花费,而不是事后估算:每条 Worker `result` 记录都会
356
+ 生成一条 `worker_usage` 事件,每次 Decision Worker/Reviewer 模型调用都会生成
357
+ 一条 `pi_usage` 事件,二者都会累计进 `session.usage`(`SupervisorTokenUsage`)。
358
+ `/supervise status <task-id>` 会打印一行 `cost=… workerTurns=…
359
+ workerTokens=… piTokens=… decisionCalls=… reviewerCalls=…` 摘要;进度通知
360
+ 携带 `SupervisorProgress.costUsd`/`.piTokens`,候选通知则通过
361
+ `CandidateNotice.usage` 携带同样的摘要(generic webhook 以数值型 `usage`
362
+ 对象输出,WeCom 格式追加两行费用/tokens)。
363
+
364
+ 除了 Worker 模型和预算的选择之外,以上机制本身并不会改变任务的实际花费;
365
+ Supervisor 侧的这些改动主要是削减 Decision Worker 的 token 消耗和延迟,而
366
+ 这部分原本就只有几美分。对成本敏感的无人值守场景,一个合理的起点是:
367
+ `WORKER_MODEL` 选择 Sonnet 级模型、为任务设置明确的 `WORKER_MAX_BUDGET_USD`、
368
+ 保留默认的 `hybrid` permission authority,并将 `DECISION_MODEL` 设为 Haiku
369
+ 级模型。
370
+
371
+ ## 开发
372
+
373
+ 为扩展本身贡献代码(使用这个扩展本身不需要这些步骤):
138
374
 
139
375
  ```bash
140
- export PI_CLAUDE_SUPERVISOR_TRANSPORT=tmux
141
- export PI_CLAUDE_SUPERVISOR_WORKER='claude'
142
- # 当前手动 tmux 也要求 Linux(用于 pane identity 和清理);可使用 cgroup auto/off。
143
- # 设置 PI_CLAUDE_SUPERVISOR_MODE=auto 启用 Supervisor 自有的自动 bridge;自动 tmux
144
- # 要求 Linux cgroup v2 和 parent-death guardian,缺失时会 fail closed。
145
- # 接管非默认 tmux server 时可选:
146
- # export PI_CLAUDE_SUPERVISOR_TMUX_SOCKET=/path/to/tmux.sock
147
- ```
148
-
149
- `/supervise start <task>` 会在私有 tmux server 中启动 Claude,并返回可复制的 attach 命令。
150
- 可以在另一个终端 attach 到同一个 PTY,观察或人工输入。多行消息通过 tmux buffer 和 Enter
151
- 发送,不会把消息拼接进 shell 命令;`pipe-pane` 记录原始输出,`capture-pane` 检测稳定的 Claude
152
- 输入提示,并复用 watchdog、审计和独立验收流程。自动模式会在 pane 内启动 bridge:它运行
153
- Claude stream-json、把可读输出渲染到附着的终端,并通过同一 PTY 的私有 framing 返回结构化
154
- 记录;bridge 及其后代放入受 Supervisor 管理的 Linux cgroup,并由 parent-death guardian
155
- 保护;bridge 会在 spawn Claude 前再次读取生效设置,任一 containment 机制或权限检查不可用时 fail closed。适配器直接从 PTY 原始 pipe 解析,因此没有
156
- 独立 JSONL sidecar。自动模式拒绝被接管的 session;Supervisor 自有 bridge 支持自动输入串行化、
157
- 权限响应、turn 完成和 stop。
158
-
159
- 如果 Claude 已由你在 tmux 中启动,可以显式接管且不会重放原始任务:
160
-
161
- ```text
162
- /supervise adopt-tmux <tmux-session-name> <task description>
376
+ npm ci --ignore-scripts
377
+ npm run check
378
+ npm run build
379
+ npm run test:pi
380
+ npm run test:install
163
381
  ```
164
382
 
165
- 接管会检查 cwd、pane 中的进程,并拒绝已有其他输出 pipe 的 pane;但不宣称拥有该 session。owned session 使用自动生成的私有 tmux socket,
166
- 请保存 `start` 输出的完整 `attach=...` 命令。Pi 重启后重新接管时,先把该命令中的 socket 路径设置到
167
- `PI_CLAUDE_SUPERVISOR_TMUX_SOCKET`;只有默认 server 才能只使用 session 名称。对被接管的 session,
168
- `/supervise stop` 和 Pi 关闭只会断开监督,不会杀掉你的 tmux 窗口;需要关闭时请由你执行
169
- `tmux kill-session`。`/supervise takeover <task-id>` 会暂停 Decision Worker 自动发送,只有
170
- `/supervise resume-auto <task-id>` 才恢复。
171
-
172
- PTY 屏幕文字本身不是 Claude JSONL,不能把屏幕文字当作结构化权限证据;只有 Supervisor bridge
173
- 的私有 framing 记录才是结构化证据。TUI 决策应按任务授权策略处理并记录;无法形成候选时可以自动挂起,不要求人工持续在线。普通终端里已经运行的 Claude 不能安全迁移进 tmux;`--resume`
174
- 是读取历史的新进程,不是实时 attach。实时测试请使用 plan/read-only 参数。
175
-
176
- 可以从不同工作目录启动多个任务会话;活动会话不能共享同一 cwd,建议每个任务使用独立 worktree:
177
-
178
- ```text
179
- /supervise sessions
180
- /supervise poll all
181
- /supervise poll <task-id>
182
- /supervise send <task-id> continue after checking the test failure
183
- ```
383
+ 部分测试会针对真实的 checkout 校验可信可执行文件和受保护分支的边界,因此必须
384
+ 从非受保护分支、且不在 group/world-writable 路径下运行。
184
385
 
185
- 当前支持的是**独立任务会话并行**,不是共享工作树的协同多 Worker。后续多 Worker
186
- 开发任务会引入 parent/child 任务图、依赖、并发上限、结构化 handoff、汇总验收和
187
- 跨进程恢复,但不会放宽“一个 worktree 一个写入者”的边界,也不会自动 merge 或 publish。
188
- 该阶段应安排在 Claude `2.1.270` 以上版本的稳定性统计和单 Worker recovery 语义完成之后。
386
+ 详见 [architecture](docs/architecture.md)、[testing](docs/testing.md) 和
387
+ [releasing](docs/releasing.md);`docs/autonomy-target.md` 记录了本项目所
388
+ 围绕的、已确认的无人值守开发目标。
189
389
 
190
- Pull Request 必须通过聚合的 `CI / Quality gate`。Release Please 根据 Conventional Commits 创建版本 PR;维护者合并后,Release workflow 会针对精确 tag commit 重新验证,并通过受保护的 `npm` environment 使用 npm provenance 发布。
390
+ ## License
191
391
 
192
- 详细内容见 [engineering-plan.md](docs/engineering-plan.md)、[autonomy-target.md](docs/autonomy-target.md)、[independent-review.md](docs/independent-review.md)、[architecture.md](docs/architecture.md)、[testing.md](docs/testing.md) 和 [releasing.md](docs/releasing.md)。
392
+ MIT。见 [LICENSE](LICENSE)。