pi-claude-supervisor 0.5.5 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.cn.md +15 -13
- package/README.md +61 -24
- package/docs/architecture.md +67 -32
- package/docs/autonomy-target.md +42 -25
- package/docs/engineering-plan.md +15 -12
- package/docs/implementation-review.md +25 -22
- package/docs/independent-review.md +7 -6
- package/docs/testing.md +73 -37
- package/package.json +1 -1
- package/src/cwd-lease.ts +736 -49
- package/src/index.ts +83 -8
- package/src/policy.ts +21 -34
- package/src/supervisor.ts +19 -3
- package/src/types.ts +16 -3
- package/src/worker/environment.ts +187 -124
- package/src/worker/process-adapter.ts +60 -105
- package/src/worker/process-tree.ts +1 -59
- package/src/worker/tmux-adapter.ts +263 -126
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented here.
|
|
4
4
|
|
|
5
|
+
## [0.6.0](https://github.com/btnalit/pi-claude-supervisor/compare/v0.5.5...v0.6.0) (2026-09-16)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* preserve full automatic Claude capabilities ([#34](https://github.com/btnalit/pi-claude-supervisor/issues/34)) ([f3ef24b](https://github.com/btnalit/pi-claude-supervisor/commit/f3ef24bf4e2bbbce27516a0e36c6000a00222b71))
|
|
11
|
+
|
|
5
12
|
## [0.5.5](https://github.com/btnalit/pi-claude-supervisor/compare/v0.5.4...v0.5.5) (2026-09-15)
|
|
6
13
|
|
|
7
14
|
|
|
@@ -59,6 +66,10 @@ All notable changes to this project will be documented here.
|
|
|
59
66
|
- Keep protected CI checks on the exact checked-out commit while giving automatic-mode fixtures a local validation branch and an owned deterministic Claude executable.
|
|
60
67
|
- Add a Supervisor-owned automatic tmux bridge that renders Claude stream-json in a live PTY and carries structured records through private framing instead of an independent event sidecar; adopted sessions remain manual-only.
|
|
61
68
|
- Add parent-identity tmux guardians, guarded Linux bootstrap readiness/cleanup, explicit nested-Agent/background-reviewer denial, and tolerant Reviewer prose/fence/repeated-JSON parsing with separate display-truncation markers.
|
|
69
|
+
- Preserve the complete Supervisor environment when automatic callers provide partial overrides, while still removing only `CLAUDECODE`.
|
|
70
|
+
- Keep direct Claude Bash permission events observable by adding a safe default mode and rejecting Bash preauthorization in CLI/settings configuration.
|
|
71
|
+
- Permit verified automatic tmux recovery after the guardian removes the session, with dead-owner/process/cgroup/session proofs before reclaiming the cwd lease; bind recovery to persisted Worker/cgroup identities, persist phased cleanup-pending state before reservation, replace the same lease record atomically, and repeat the effective-settings permission check immediately before the tmux bridge spawns Claude.
|
|
72
|
+
- Retain verified empty automatic cgroups until cwd lease release, persist a no-spawn startup marker and provisional identity before Worker spawn, bind lock release/reclamation to directory identity and owner tokens, and pin the automatic tmux bridge cwd.
|
|
62
73
|
|
|
63
74
|
### Release readiness
|
|
64
75
|
|
package/README.cn.md
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
> preflight 和阶段进度通知;真实 Claude Code `2.1.270` 允许编辑的
|
|
16
16
|
> repair/reacceptance 演练已在隔离临时 worktree 通过。确认的产品目标是本地开发
|
|
17
17
|
> 完全无人值守;详见 [自动化目标](docs/autonomy-target.md)。代码进入远程仓库或
|
|
18
|
-
> main/integration
|
|
18
|
+
> main/integration 分支仍必须经过独立边界;Supervisor 管理的直接 push/merge 请求会拒绝,
|
|
19
|
+
> 而嵌套/自定义能力的硬边界必须由独立保护机制提供。
|
|
19
20
|
>
|
|
20
21
|
> **无人值守状态:** 自动模式会自主完成本地修改、测试、有限修复、验收、独立 Review
|
|
21
22
|
> 和本地提交检查;无法形成候选时自动挂起为不可发布候选。可选出站通知不授予权限,
|
|
@@ -25,13 +26,14 @@
|
|
|
25
26
|
|
|
26
27
|
- 不会在扩展加载时自动启动 Worker。
|
|
27
28
|
- 不经过 shell 启动子进程。
|
|
28
|
-
- Worker
|
|
29
|
-
-
|
|
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 权限循环。
|
|
30
32
|
- Linux 上优先使用可写的 cgroup v2 清理后代进程,包括 `setsid()` 后代;不可用时回退到进程组清理。需要强制失败闭环时,embedding 集成可使用 `cgroupMode: "required"`,并会在 Claude 启动前执行 preflight。
|
|
31
|
-
- 自动模式只接受裸的 `claude`/`claude.exe` 命令名,并从 Supervisor 的 PATH 解析、固定由操作者拥有的可执行文件(或使用 `PI_CLAUDE_SUPERVISOR_TRUSTED_CLAUDE`
|
|
33
|
+
- 自动模式只接受裸的 `claude`/`claude.exe` 命令名,并从 Supervisor 的 PATH 解析、固定由操作者拥有的可执行文件(或使用 `PI_CLAUDE_SUPERVISOR_TRUSTED_CLAUDE` 固定路径);显式路径和可写/不可信位置会被拒绝。自定义工具和嵌套 Worker 是受信任能力,硬性的 remote/main 边界仍必须由此进程之外的独立受保护边界提供。
|
|
32
34
|
- Worker 声称完成只会进入 `verifying`,不能作为成功证据。
|
|
33
35
|
- 默认独立验收命令为 `git diff --check`。
|
|
34
|
-
- 目标是任务启动后本地开发无人值守:Worker 可以修改、测试、修复和本地提交;
|
|
36
|
+
- 目标是任务启动后本地开发无人值守:Worker 可以修改、测试、修复和本地提交;Supervisor 管理的 remote push 或合并到 `main`/integration 分支请求仍会拒绝,嵌套/自定义能力的最终 remote/main 边界必须由独立保护机制提供。
|
|
35
37
|
- 扩展运行时不执行 merge、deploy、release 或 publish;远程/main 集成和仓库 Release 必须经过独立受保护边界。
|
|
36
38
|
- 默认 4 小时总时限、20 分钟无输出 watchdog 超时即停止 Worker;paused 期间不消耗无输出预算,resume 会重建基准但不会重置总时限。嵌入调用方可将对应选项设为 `0` 关闭。
|
|
37
39
|
- 验收命令、仓库证据收集和独立 Reviewer 共用 abort signal,人工 stop/shutdown 不必等待完整超时。
|
|
@@ -48,7 +50,7 @@ pi install npm:pi-claude-supervisor
|
|
|
48
50
|
|
|
49
51
|
```bash
|
|
50
52
|
export PI_CLAUDE_SUPERVISOR_MODE=auto
|
|
51
|
-
export PI_CLAUDE_SUPERVISOR_WORKER='claude --
|
|
53
|
+
export PI_CLAUDE_SUPERVISOR_WORKER='claude --permission-mode acceptEdits'
|
|
52
54
|
# 可选:候选/失败通知;generic 或 wecom
|
|
53
55
|
export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_URL='https://example.invalid/webhook'
|
|
54
56
|
export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_FORMAT=generic
|
|
@@ -58,7 +60,7 @@ export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_FORMAT=generic
|
|
|
58
60
|
自动模式支持 `claude-jsonl` 和 Supervisor 自有的 tmux bridge;JSONL 的 `result`、
|
|
59
61
|
`control_request` 和进程 `exit` 事件会唤醒 Decision Worker。tmux bridge 把结构化记录
|
|
60
62
|
通过同一个 live PTY 的私有 terminal framing 传回适配器,不创建独立 JSONL sidecar;
|
|
61
|
-
`adopt-tmux`
|
|
63
|
+
`adopt-tmux` 仍是手动模式。真实 Claude 检查默认从 `PATH` 解析当前 CLI(包括安装器提供的 `latest` 路径),支持 Claude Code `2.1.270` 及以上版本;本轮的已记录演练版本为 `2.1.270`。
|
|
62
64
|
|
|
63
65
|
然后在 Pi 中使用:
|
|
64
66
|
|
|
@@ -115,9 +117,9 @@ export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_FORMAT=generic
|
|
|
115
117
|
自动模式会将 Decision Worker 会话持久化到状态目录。Pi 非正常重启后,`/supervise sessions`
|
|
116
118
|
会显示 `recoverable` 任务;显式执行 `/supervise recover [--takeover] <task-id>` 会恢复 Decision Worker 上下文并
|
|
117
119
|
重新启动 Claude Worker,不会静默恢复或重复执行任务。旧 Pi 进程已退出且租约确认旧 Worker
|
|
118
|
-
进程组已消失且 cgroup 仍是真实、可读取的空边界时,才可显式添加 `--takeover`;缺失、仍存活或无法确认的 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
|
|
119
121
|
Worker 可在重启后使用 `adopt-tmux`,而不是 takeover;自动 bridge 会由 parent-death guardian
|
|
120
|
-
在 Supervisor
|
|
122
|
+
在 Supervisor 消失时终止,只有通过上述证据检查的 `recover --takeover` 才能重新取得 cwd lease。
|
|
121
123
|
自动模式下,Decision Worker 在任务授权范围内自动处理普通问题、测试失败和修复轮次,记录假设和证据;无法形成可交付候选时自动挂起并保留证据,而不是要求人工必须在线。可通过 `PI_CLAUDE_SUPERVISOR_REQUIRE_LOCAL_COMMIT=0` 或 task `autonomy.requireLocalCommit` 关闭本地 commit 要求,但自动模式仍要求有效 Git baseline 和非保护 worktree;远程 push 和 main/integration merge 仍由独立边界控制。
|
|
122
124
|
|
|
123
125
|
`v0.5.0` 已完成并发布“多命令验收—独立只读 Reviewer—结构化修复轮次—再次验收”闭环。
|
|
@@ -127,8 +129,8 @@ Reviewer 只能使用 `read`、`grep`、`find`、`ls`,不会修改工作树或
|
|
|
127
129
|
Worker 启动前捕获 git baseline,要求完整的 baseline-relative tracked/commit/untracked evidence,
|
|
128
130
|
并在默认情况下要求 Worker 在非保护分支本地 commit;无效输出、证据不完整、重复 finding、P0/P1 或预算耗尽
|
|
129
131
|
会自动挂起候选。自动模式拒绝 process-pipe,并在模型执行前检查目录、可执行文件、依赖
|
|
130
|
-
和 cgroup;
|
|
131
|
-
自动模式只接受裸的直接 Claude
|
|
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/仓库边界保护。
|
|
132
134
|
|
|
133
135
|
### tmux/PTY 交互模式
|
|
134
136
|
|
|
@@ -150,7 +152,7 @@ export PI_CLAUDE_SUPERVISOR_WORKER='claude'
|
|
|
150
152
|
输入提示,并复用 watchdog、审计和独立验收流程。自动模式会在 pane 内启动 bridge:它运行
|
|
151
153
|
Claude stream-json、把可读输出渲染到附着的终端,并通过同一 PTY 的私有 framing 返回结构化
|
|
152
154
|
记录;bridge 及其后代放入受 Supervisor 管理的 Linux cgroup,并由 parent-death guardian
|
|
153
|
-
|
|
155
|
+
保护;bridge 会在 spawn Claude 前再次读取生效设置,任一 containment 机制或权限检查不可用时 fail closed。适配器直接从 PTY 原始 pipe 解析,因此没有
|
|
154
156
|
独立 JSONL sidecar。自动模式拒绝被接管的 session;Supervisor 自有 bridge 支持自动输入串行化、
|
|
155
157
|
权限响应、turn 完成和 stop。
|
|
156
158
|
|
|
@@ -183,7 +185,7 @@ PTY 屏幕文字本身不是 Claude JSONL,不能把屏幕文字当作结构化
|
|
|
183
185
|
当前支持的是**独立任务会话并行**,不是共享工作树的协同多 Worker。后续多 Worker
|
|
184
186
|
开发任务会引入 parent/child 任务图、依赖、并发上限、结构化 handoff、汇总验收和
|
|
185
187
|
跨进程恢复,但不会放宽“一个 worktree 一个写入者”的边界,也不会自动 merge 或 publish。
|
|
186
|
-
|
|
188
|
+
该阶段应安排在 Claude `2.1.270` 以上版本的稳定性统计和单 Worker recovery 语义完成之后。
|
|
187
189
|
|
|
188
190
|
Pull Request 必须通过聚合的 `CI / Quality gate`。Release Please 根据 Conventional Commits 创建版本 PR;维护者合并后,Release workflow 会针对精确 tag commit 重新验证,并通过受保护的 `npm` environment 使用 npm provenance 发布。
|
|
189
191
|
|
package/README.md
CHANGED
|
@@ -16,8 +16,9 @@ worker remains an explicitly started child process.
|
|
|
16
16
|
> sessions remain manual-only. Repairable-vs-persistent capabilities,
|
|
17
17
|
> cancellable verification, evidence completeness gates, startup preflight and phase
|
|
18
18
|
> progress reporting. A real edit-capable Claude Code `2.1.270` repair/reacceptance
|
|
19
|
-
> drill passed in an isolated temporary worktree.
|
|
20
|
-
>
|
|
19
|
+
> drill passed in an isolated temporary worktree. Real-Claude validation resolves the
|
|
20
|
+
> current executable from `PATH` and accepts Claude Code `2.1.270` or newer. The
|
|
21
|
+
> confirmed product target is unattended local development; see [the autonomy target](docs/autonomy-target.md).
|
|
21
22
|
> Remote push and merge into the main/integration branch remain outside Worker authority
|
|
22
23
|
> and must cross an independent boundary.
|
|
23
24
|
>
|
|
@@ -30,12 +31,13 @@ worker remains an explicitly started child process.
|
|
|
30
31
|
|
|
31
32
|
- The extension never starts a worker automatically.
|
|
32
33
|
- Worker commands are launched without a shell.
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
34
|
+
- Manual workers retain the small inherited environment unless the caller supplies explicit variables. Automatic Claude workers inherit the supervisor environment unchanged except for `CLAUDECODE`, which must be removed so Claude can intentionally launch nested Claude sessions; credentials, Git/package helpers, custom settings and network configuration are not filtered.
|
|
35
|
+
- The full Claude Code tool surface is available in automatic mode, including agents, background tasks, plugins and MCP. Automatic mode refuses CLI/settings rules that pre-authorize `Bash`, and adds Claude's safe `default` permission mode when none is supplied, so Bash requests remain visible to the Supervisor; it does not remove the Bash tool. The adapter also adds stream-json transport framing and keeps every Worker descendant inside the Supervisor-owned cleanup boundary. `AskUserQuestion` is converted to ordinary text because no human is synchronously present.
|
|
36
|
+
- Local command and permission behavior follows the configured task/runtime policy; known direct remote push/main-integration operations and protected Git metadata remain rejected or parked without requiring a synchronous human response. Nested/custom tools run with the inherited capabilities and are cleaned with the Worker; they are not a second Supervisor permission loop.
|
|
37
|
+
- Automatic mode still admits only the bare `claude`/`claude.exe` command name, resolves and pins an operator-owned executable from the supervisor PATH (or `PI_CLAUDE_SUPERVISOR_TRUSTED_CLAUDE`), and rejects explicit paths or writable/untrusted locations. Manual/custom integrations must provide their own executable and host authority boundary.
|
|
36
38
|
- A worker completion is only a transition to `verifying`; it is not evidence of success.
|
|
37
39
|
- Verification is an independent host command (default: `git diff --check`).
|
|
38
|
-
- Target local development runs unattended after a task starts: the Worker may edit, test, repair and commit locally.
|
|
40
|
+
- Target local development runs unattended after a task starts: the Worker may edit, test, repair and commit locally. Supervisor-managed requests for remote push or merge into `main`/an integration branch remain denied, while the final remote/main boundary must independently protect trusted nested/custom capabilities.
|
|
39
41
|
- The extension never performs merge, deploy, release, or publish at runtime. Remote/main integration and repository releases cross independent protected boundaries.
|
|
40
42
|
- A 4-hour wall-clock and 20-minute no-output watchdog stop a worker by default for long development tasks; embedding callers can set either to `0` to disable.
|
|
41
43
|
- On Linux, the adapter automatically uses a writable cgroup v2 for descendant cleanup, including `setsid()` descendants; it falls back to process-group cleanup when unavailable. Use `cgroupMode: "required"` for a fail-closed integration; required mode is preflighted before Claude starts.
|
|
@@ -58,6 +60,11 @@ npm run check
|
|
|
58
60
|
npm run build
|
|
59
61
|
```
|
|
60
62
|
|
|
63
|
+
Authenticated real-Claude spikes resolve `claude` from `PATH` by default, so
|
|
64
|
+
installer-managed `latest` links work without a versioned path. Set
|
|
65
|
+
`PI_CLAUDE_SUPERVISOR_REAL_CLAUDE_PATH` only when an explicit executable is needed;
|
|
66
|
+
the spikes require Claude Code `2.1.270` or newer and report the resolved path and version.
|
|
67
|
+
|
|
61
68
|
## Use
|
|
62
69
|
|
|
63
70
|
Set the worker executable if needed, then use explicit commands in Pi:
|
|
@@ -108,7 +115,7 @@ be selected explicitly:
|
|
|
108
115
|
|
|
109
116
|
```bash
|
|
110
117
|
export PI_CLAUDE_SUPERVISOR_TRANSPORT=jsonl
|
|
111
|
-
export PI_CLAUDE_SUPERVISOR_WORKER='claude --
|
|
118
|
+
export PI_CLAUDE_SUPERVISOR_WORKER='claude --permission-mode acceptEdits'
|
|
112
119
|
```
|
|
113
120
|
|
|
114
121
|
This adds Claude Code stream-json flags and frames supervisor messages as JSONL.
|
|
@@ -124,12 +131,22 @@ scheduling, structured handoffs, aggregate acceptance and graph-aware recovery;
|
|
|
124
131
|
it will not grant any Worker remote push or main/integration merge authority.
|
|
125
132
|
Unattended local development is the target operating mode; a blocked or failed
|
|
126
133
|
candidate is parked with its evidence rather than made dependent on a human being
|
|
127
|
-
online. Automatic mode
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
134
|
+
online. Automatic mode preserves Claude Code's normal argument and extension surface:
|
|
135
|
+
its tools, agents, background tasks, plugins, MCP configuration, credentials and network
|
|
136
|
+
access are not replaced with a sandbox or allowlist. `CLAUDECODE` is removed from the
|
|
137
|
+
Worker environment so nested Claude sessions can start, and the Supervisor-owned cgroup
|
|
138
|
+
still cleans every descendant. Automatic mode adds a safe `default` permission mode
|
|
139
|
+
when omitted and rejects Bash preauthorization in the effective CLI/settings roots
|
|
140
|
+
(including an overridden `HOME`); Bash itself remains available through
|
|
141
|
+
Supervisor-visible permission requests. The automatic tmux bridge repeats that
|
|
142
|
+
settings check synchronously immediately before spawning Claude, so a mutation after
|
|
143
|
+
Supervisor preflight fails closed. The adapter also adds stream-json transport framing,
|
|
144
|
+
and its known direct command policy refuses remote push/main integration operations.
|
|
145
|
+
Automatic mode still accepts only the bare direct Claude command name, pins its
|
|
146
|
+
operator-owned resolved executable path, and rejects explicit executable paths or
|
|
147
|
+
writable/untrusted locations. Set `PI_CLAUDE_SUPERVISOR_TRUSTED_CLAUDE` when the resolved
|
|
148
|
+
path must be pinned explicitly. Custom tools and nested workers are trusted capabilities,
|
|
149
|
+
so a hard remote/main boundary must remain independently protected outside this process.
|
|
133
150
|
Set `PI_CLAUDE_SUPERVISOR_REQUIRE_LOCAL_COMMIT=0` only for a task that intentionally
|
|
134
151
|
produces no local commit candidate, or set `autonomy.requireLocalCommit` in its spec;
|
|
135
152
|
automatic mode still requires a valid Git baseline and non-protected worktree.
|
|
@@ -163,15 +180,30 @@ tasks; `/supervise recover [--takeover] <task-id>` explicitly restores the Decis
|
|
|
163
180
|
context and starts a new Claude Worker. It never silently resumes or duplicates
|
|
164
181
|
work. If the old Pi owner is dead, add `--takeover` only after the lease proves
|
|
165
182
|
the old Worker's process group is gone and its cgroup is a real, readable empty
|
|
166
|
-
boundary; missing or unverifiable Worker evidence is refused.
|
|
167
|
-
|
|
168
|
-
|
|
183
|
+
boundary; missing or unverifiable Worker evidence is refused. The lease also
|
|
184
|
+
persists the generated Worker/cgroup identity, including the cgroup device/inode,
|
|
185
|
+
and rejects a renamed or replaced cgroup. Automatic Workers retain a verified
|
|
186
|
+
empty cgroup until the owning cwd lease is released, covering a normal-exit
|
|
187
|
+
crash between Worker cleanup and lease finalization; release then removes it.
|
|
188
|
+
Automatic lease acquisition records a no-spawn startup marker and the adapter
|
|
189
|
+
persists its generated cgroup/socket plan before creating those resources,
|
|
190
|
+
then records cgroup and server identity in stages before spawn. Recovery
|
|
191
|
+
inspects and cleans a planned empty cgroup/session instead of assuming that
|
|
192
|
+
startup-only means no resource exists. A stale marker is reclaimable only after
|
|
193
|
+
its owner is proven dead because that adapter has not reached spawn. For an automatic tmux lease, takeover additionally requires Supervisor ownership,
|
|
194
|
+
dead tmux-server identity, a gone private tmux session, and a durable
|
|
195
|
+
cleanup-pending transaction plus atomic reservation of the private socket. The
|
|
196
|
+
replacement reuses the old lease record, and the reservation remains until that
|
|
197
|
+
replacement is written. Only then is the guardian-left-empty cgroup removed; a
|
|
198
|
+
fresh Supervisor can reconcile the pending transaction if recovery is
|
|
199
|
+
interrupted. For a persistent manual tmux Worker, use explicit `adopt-tmux`
|
|
200
|
+
instead of takeover.
|
|
169
201
|
Manual embedding integrations may pass credentials through an explicit
|
|
170
|
-
`WorkerStartInput.env
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
`PI_CLAUDE_SUPERVISOR_TRUSTED_CLAUDE`
|
|
174
|
-
|
|
202
|
+
`WorkerStartInput.env`. Automatic mode passes the full supervisor environment to the
|
|
203
|
+
Worker (except `CLAUDECODE`), including provider/remote credentials, credential helpers,
|
|
204
|
+
configuration and proxy settings. Keep the Supervisor's own environment appropriate for
|
|
205
|
+
the task; `PI_CLAUDE_SUPERVISOR_TRUSTED_CLAUDE` pins executable identity but is otherwise
|
|
206
|
+
not used to select the Claude binary.
|
|
175
207
|
|
|
176
208
|
### tmux/PTY transport
|
|
177
209
|
|
|
@@ -197,8 +229,11 @@ In automatic mode the Supervisor starts a bridge in the pane: it runs Claude's
|
|
|
197
229
|
stream-json protocol inside the live PTY, contains the bridge and descendants in
|
|
198
230
|
an owned cgroup, fails closed when that containment or the Linux guardian is
|
|
199
231
|
unavailable, renders readable deltas for the attached terminal, and returns
|
|
200
|
-
structured records through private terminal framing on the same PTY.
|
|
201
|
-
|
|
232
|
+
structured records through private terminal framing on the same PTY. The bridge
|
|
233
|
+
re-reads effective Claude settings in the same process immediately before its
|
|
234
|
+
child `spawn`, so a startup settings mutation fails closed instead of reaching
|
|
235
|
+
an unchecked Claude process. The adapter parses those records from the raw PTY
|
|
236
|
+
pipe, so there is no independent
|
|
202
237
|
JSONL event sidecar. Automatic mode refuses adopted sessions; use JSONL or the owned
|
|
203
238
|
bridge for unattended decisions, repair and protected command enforcement.
|
|
204
239
|
|
|
@@ -229,7 +264,9 @@ online. A normal terminal Claude process cannot be migrated into tmux, and
|
|
|
229
264
|
`--resume` is historical recovery rather than live PTY attach. Manual owned tmux
|
|
230
265
|
sessions survive a Pi disconnect and require an explicit `adopt-tmux` after
|
|
231
266
|
restart; automatic owned sessions are terminated by their parent-death guardian
|
|
232
|
-
when the Supervisor disappears.
|
|
267
|
+
when the Supervisor disappears. A later `/supervise recover --takeover` may
|
|
268
|
+
reclaim an automatic lease only after the guardian, process, cgroup and private
|
|
269
|
+
tmux-session proofs pass. Use plan/read-only flags for live testing.
|
|
233
270
|
|
|
234
271
|
## Development
|
|
235
272
|
|
package/docs/architecture.md
CHANGED
|
@@ -27,8 +27,9 @@ The extension keeps a registry of independent task sessions. Each session has
|
|
|
27
27
|
its own Supervisor, watchdog, state machine and Worker handle, while the event
|
|
28
28
|
log is shared and protected by an inter-process lock. Once a task starts, the
|
|
29
29
|
local development loop is intended to run unattended: the Worker may edit, test,
|
|
30
|
-
repair and commit locally.
|
|
31
|
-
|
|
30
|
+
repair and commit locally. Supervisor-managed remote push and merge into `main`/an integration branch
|
|
31
|
+
requests remain outside the local loop and cross an independent boundary; custom/nested tools require
|
|
32
|
+
that boundary to enforce the same rule independently. Concurrent active sessions must use non-overlapping canonical working
|
|
32
33
|
directories/worktrees; same-cwd and parent/child cwd starts are rejected before
|
|
33
34
|
spawn, including concurrent starts, to prevent uncoordinated edits. Pending starts
|
|
34
35
|
are also awaited during Pi shutdown.
|
|
@@ -83,13 +84,32 @@ fixed-version spike, renders the stream in the pane and carries structured recor
|
|
|
83
84
|
through private framing on the same PTY; explicit adoption remains manual-only.
|
|
84
85
|
|
|
85
86
|
A worker exit automatically triggers cleanup, and terminal status waits for
|
|
86
|
-
that cleanup to be confirmed (or reports a cleanup error).
|
|
87
|
-
|
|
87
|
+
that cleanup to be confirmed (or reports a cleanup error). Automatic Claude
|
|
88
|
+
startup rejects Bash preauthorization in the effective CLI/settings roots,
|
|
89
|
+
including an overridden `HOME`, and adds a safe `default` permission mode when
|
|
90
|
+
no mode was supplied, preserving the Supervisor's permission-event boundary
|
|
91
|
+
without removing the Bash tool. The automatic tmux bridge repeats the settings
|
|
92
|
+
inspection synchronously immediately before its Claude child `spawn`, so a
|
|
93
|
+
mutation after Supervisor preflight fails closed. On Linux,
|
|
94
|
+
manual workers may use cgroup v2 automatically when the current user cgroup is writable;
|
|
88
95
|
the `required` mode performs a preflight and fails before Claude starts if cgroup
|
|
89
96
|
attachment or cleanup is unavailable. Automatic JSONL workers always require the
|
|
90
97
|
same preflight and a guarded cgroup bootstrap; automatic startup fails closed on
|
|
91
98
|
non-Linux hosts or when the boundary cannot be established. Cgroup cleanup kills
|
|
92
|
-
descendants even when they call `setsid()` or create another process group.
|
|
99
|
+
descendants even when they call `setsid()` or create another process group. If
|
|
100
|
+
an automatic parent-death bootstrap performs cleanup after the Supervisor is
|
|
101
|
+
killed, it leaves the now-empty cgroup as takeover evidence; the lease persists
|
|
102
|
+
the generated Worker/cgroup identity and cgroup device/inode, and explicit
|
|
103
|
+
recovery removes the cgroup only after those identities, the dead tmux server,
|
|
104
|
+
and the empty boundary pass. Automatic workers retain their verified empty
|
|
105
|
+
cgroup until the owning cwd lease is finalized, so a normal-exit crash remains
|
|
106
|
+
recoverable; explicit lease release then removes it. Takeover first persists a
|
|
107
|
+
cleanup-pending transaction in the existing lease, then atomically reserves the
|
|
108
|
+
gone private socket; it replaces that same lease record before removing the
|
|
109
|
+
guardian cgroup and clears the transaction only after all cleanup proofs
|
|
110
|
+
complete. A fresh lease reader can reconcile the pending transaction after a
|
|
111
|
+
crash, retaining a replacement lease during the replacement phase, while
|
|
112
|
+
ordinary manual worker cleanup still removes its cgroup.
|
|
93
113
|
|
|
94
114
|
When cgroup v2 is unavailable, manual mode falls back to detached process-group
|
|
95
115
|
cleanup. That fallback is not recursive: `setsid()` descendants can escape, and
|
|
@@ -113,18 +133,19 @@ parent-death guardian is unavailable.
|
|
|
113
133
|
An owned manual worker gets a private tmux server/socket and executes the
|
|
114
134
|
validated Claude command directly in the pane. An owned automatic worker instead
|
|
115
135
|
starts the Supervisor bridge through a cgroup-joining pane bootstrap, so its
|
|
116
|
-
bridge identity is not a manual adoption target. The worker
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
136
|
+
bridge identity is not a manual adoption target. The worker environment is
|
|
137
|
+
passed through unchanged (apart from removing `CLAUDECODE` so nested Claude can
|
|
138
|
+
start); credentials are not copied into a file, and credential-shaped command
|
|
139
|
+
arguments are still rejected.
|
|
120
140
|
`load-buffer`, bracketed `paste-buffer` and `send-keys Enter` provide the input
|
|
121
141
|
boundary without interpolating a task into a shell command. C0/C1 terminal
|
|
122
|
-
control bytes are rejected; CRLF is normalized to a newline.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
142
|
+
control bytes are rejected; CRLF is normalized to a newline. Automatic agents,
|
|
143
|
+
background tasks, plugins, MCP servers and nested Claude processes stay in the
|
|
144
|
+
same cgroup and are cleaned with the Worker; they are intentionally not rejected
|
|
145
|
+
or polled as a nested-process policy failure. The lexical Bash/file-tool policy
|
|
146
|
+
still handles known direct remote/main operations, while custom descendants are
|
|
147
|
+
trusted and require an independent host/repository boundary for stronger
|
|
148
|
+
protection.
|
|
128
149
|
|
|
129
150
|
The transport has three deliberately separate observations:
|
|
130
151
|
|
|
@@ -153,9 +174,13 @@ that immutable pane target; a replacement process is refused. Adopted sessions
|
|
|
153
174
|
are not owned: stop and Pi shutdown detach rather than kill them. Tmux commands
|
|
154
175
|
and serialized input waits have bounded deadlines so shutdown cannot hang
|
|
155
176
|
forever. Manual sessions started by the adapter survive a Pi disconnect, but recovery
|
|
156
|
-
after restart is explicit re-adoption; automatic sessions are
|
|
157
|
-
|
|
158
|
-
|
|
177
|
+
after restart is explicit re-adoption; automatic sessions are terminated by
|
|
178
|
+
their parent-death guardian when the Supervisor disappears. The guardian leaves
|
|
179
|
+
the verified empty automatic cgroup so `recover --takeover` can confirm the
|
|
180
|
+
private tmux session and Worker identities. Recovery reserves the gone private
|
|
181
|
+
socket, writes the replacement lease, and only then releases the reservation
|
|
182
|
+
and removes that cgroup. The extension never claims to attach to an arbitrary
|
|
183
|
+
non-tmux PTY. Startup cleanup always attempts the
|
|
159
184
|
private tmux server teardown, including after partial session creation, and a
|
|
160
185
|
confirmed `kill-server` is sufficient cleanup evidence. A normal Claude
|
|
161
186
|
`--resume` starts another process from history and is not a live PTY migration.
|
|
@@ -191,10 +216,12 @@ only after the adapter confirms the worker and its descendant cleanup. An
|
|
|
191
216
|
unconfirmed lease left by a crashed Pi is intentionally retained. Ordinary
|
|
192
217
|
recovery refuses it; an operator may use `recover --takeover` only when the old
|
|
193
218
|
owner is dead, the Worker process group is gone, and the lease independently
|
|
194
|
-
reads a real empty cgroup boundary for the old Worker.
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
219
|
+
reads a real empty cgroup boundary for the old Worker. Automatic tmux takeover
|
|
220
|
+
additionally requires Supervisor ownership and a gone private tmux session, then
|
|
221
|
+
removes the guardian-left-empty cgroup only after all proofs pass. Missing or
|
|
222
|
+
unverifiable Worker evidence retains the lease and parks the task rather than
|
|
223
|
+
performing unsafe reclamation; later recovery can inspect or clean it without
|
|
224
|
+
requiring an operator to be online.
|
|
198
225
|
An explicitly adopted tmux session may hand off an existing lease only after
|
|
199
226
|
its owner identity is no longer live and its canonical cwd, tmux session/socket,
|
|
200
227
|
pane id, pane PID/start time, and pane command all match; ordinary starts
|
|
@@ -215,9 +242,18 @@ executable is checked for an operator-owned, non-writable path and then pinned b
|
|
|
215
242
|
absolute path; `PI_CLAUDE_SUPERVISOR_TRUSTED_CLAUDE` can pin the expected identity. The initial repository HEAD is captured, and the repository boundary immediately
|
|
216
243
|
before the Worker adapter starts must report that exact same HEAD (recovery captures
|
|
217
244
|
and compares its current HEAD separately while retaining the persisted baseline).
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
245
|
+
Automatic lease acquisition also persists a no-spawn startup marker. Automatic
|
|
246
|
+
adapters then persist the generated Worker/cgroup identity and clear that marker
|
|
247
|
+
before the actual Worker spawn, closing the startup-registration crash window;
|
|
248
|
+
a stale marker can only be replaced after the old owner is proven dead because
|
|
249
|
+
its adapter has not reached spawn. Adapters persist their generated cgroup/socket
|
|
250
|
+
plan before creating those resources, persist cgroup identity before guardian or
|
|
251
|
+
session setup, and persist tmux-server identity before the final spawn check. Startup
|
|
252
|
+
recovery validates and cleans any planned empty resource it finds instead of
|
|
253
|
+
assuming the marker means no resource exists. The built-in process adapter invokes
|
|
254
|
+
the same assertion through `preSpawnCheck` after cgroup/executable setup and
|
|
255
|
+
immediately before `spawn`; a failed preflight is fail-closed and does not start
|
|
256
|
+
Claude. Long acceptance commands and Reviewer
|
|
221
257
|
sessions share an abort signal with the Supervisor, so operator stop/shutdown
|
|
222
258
|
wins without waiting for a full check timeout. Progress hooks expose starting,
|
|
223
259
|
Worker heartbeat, acceptance, review, repair and candidate/decision phases in the Pi UI.
|
|
@@ -308,13 +344,12 @@ limit, so a normal large test report is not misclassified as a failed command.
|
|
|
308
344
|
- unauthenticated inbound webhook commands; outbound notifications are optional,
|
|
309
345
|
do not grant permission and do not replace the remote/main independent boundary;
|
|
310
346
|
- treating an unknown Claude interactive question as safe without task evidence or configured authorization;
|
|
311
|
-
- bypassing the
|
|
347
|
+
- bypassing the known direct remote/main command and Git metadata boundaries;
|
|
312
348
|
- accepting model text as verification;
|
|
313
349
|
- shell command interpolation;
|
|
314
|
-
- a host-level network sandbox for manual integrations. Automatic mode
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
credential filtering remain defense in depth;
|
|
350
|
+
- a host-level network sandbox for automatic or manual integrations. Automatic mode
|
|
351
|
+
deliberately preserves Claude Code's normal environment, network, tools, agents,
|
|
352
|
+
plugins and MCP configuration; nested/custom descendants are trusted capabilities;
|
|
318
353
|
- Claude CLI multi-version compatibility in the current stability milestone;
|
|
319
|
-
- full OS sandbox and low-privilege execution for custom Worker integrations in the
|
|
320
|
-
lifecycle milestone.
|
|
354
|
+
- full OS sandbox and low-privilege execution for custom or nested Worker integrations in the
|
|
355
|
+
current lifecycle milestone.
|
package/docs/autonomy-target.md
CHANGED
|
@@ -35,26 +35,32 @@ JSONL Worker or Supervisor-owned tmux bridge, and by default requires a local co
|
|
|
35
35
|
Automatic Worker supervision uses either the structured JSONL transport or a
|
|
36
36
|
Supervisor-owned tmux bridge. The bridge runs Claude's stream-json protocol inside the live
|
|
37
37
|
PTY, renders a human-readable display, and returns private framed records through the same
|
|
38
|
-
PTY; adopted tmux sessions remain manual-only.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
PTY; adopted tmux sessions remain manual-only. Automatic local work still has no Supervisor API
|
|
39
|
+
for remote push or merging into `main` or another protected integration branch. It also refuses
|
|
40
|
+
known direct Bash forms of those operations, protected Git metadata writes and package publication.
|
|
41
|
+
Starting candidate work directly on a protected integration branch remains refused; automatic
|
|
42
|
+
repositories use a non-protected local branch.
|
|
43
|
+
|
|
44
|
+
Automatic Claude workers intentionally inherit credentials, helpers, network configuration and
|
|
45
|
+
custom Claude configuration. Agents, background tasks, plugins, MCP servers and nested Claude
|
|
46
|
+
processes are allowed and remain inside the Supervisor-owned process/cgroup cleanup boundary.
|
|
47
|
+
Those custom or nested capabilities are trusted local execution, not a second Supervisor
|
|
48
|
+
permission loop; an absolute remote/main security boundary for them must be provided by the
|
|
49
|
+
repository, host or protected integration service. To keep the direct Claude Bash boundary
|
|
50
|
+
observable, automatic startup adds the safe `default` permission mode when none is supplied and
|
|
51
|
+
rejects `--allowedTools`/settings rules that pre-authorize `Bash`; the Bash tool remains available
|
|
52
|
+
through a Supervisor-visible permission request. Settings are resolved from the effective
|
|
53
|
+
`HOME`/`CLAUDE_CONFIG_DIR`, and the automatic tmux bridge repeats this inspection immediately
|
|
54
|
+
before spawning Claude so a startup mutation fails closed.
|
|
47
55
|
|
|
48
56
|
A completed local task is a candidate until it passes the independent boundary. That boundary may
|
|
49
57
|
be a later read-only review, CI policy, a maintainer action, or an explicit shutdown/rejection.
|
|
50
|
-
|
|
58
|
+
No local decision or model response may turn a blocked candidate into a published result.
|
|
51
59
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
synchronous human-approval boundary should be invented for local editing, local tests, local
|
|
57
|
-
commits, or local repair unless the task owner explicitly configures one.
|
|
60
|
+
Automatic mode still admits only the bare direct Claude command name and pins its operator-owned
|
|
61
|
+
resolved executable. No additional synchronous human-approval boundary should be invented for
|
|
62
|
+
local editing, local tests, local commits or local repair unless the task owner explicitly
|
|
63
|
+
configures one.
|
|
58
64
|
|
|
59
65
|
## 3. Unattended decision behavior
|
|
60
66
|
|
|
@@ -103,17 +109,26 @@ continue/redirect/answer/repair, acceptance and independent Review run without a
|
|
|
103
109
|
and unresolved situations become `blocked` candidates. The default task autonomy is unattended, requires a local commit, and permits two bounded
|
|
104
110
|
Decision Worker request retries. Automatic startup rejects non-Git/detached/bare/protected
|
|
105
111
|
repository states, malformed baselines, startup-HEAD races, the unstructured
|
|
106
|
-
process-pipe transport and non-Claude or untrusted
|
|
107
|
-
startup. The resolved
|
|
112
|
+
process-pipe transport, Bash-preauthorizing Claude arguments/settings and non-Claude or untrusted
|
|
113
|
+
executable identities before Worker startup. The resolved
|
|
108
114
|
executable identity is persisted with the Decision Worker recovery record and must match
|
|
109
115
|
again during recovery.
|
|
110
116
|
|
|
111
117
|
Legacy `humanRequired`, takeover and approval fields remain for compatibility and explicit operator
|
|
112
118
|
control. They are not entered by ordinary uncertainty, and a legacy approval object cannot override
|
|
113
|
-
the deterministic remote push/main merge denial. The existing independent Review
|
|
114
|
-
CI/release paths remain the final external checks.
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
the deterministic known-command remote push/main merge denial. The existing independent Review
|
|
120
|
+
and protected CI/release paths remain the final external checks. Automatic Claude workers preserve
|
|
121
|
+
Claude Code's normal environment, network, tool, agent and MCP surface; `CLAUDECODE` is removed
|
|
122
|
+
only to permit intentional nested Claude sessions. The Supervisor-owned cgroup remains a cleanup
|
|
123
|
+
boundary, not a capability allowlist. Automatic tmux parent-death recovery leaves an empty
|
|
124
|
+
cgroup as evidence and permits `recover --takeover` only after Supervisor ownership, persisted
|
|
125
|
+
Worker/cgroup identity (including the cgroup device/inode), dead tmux-server identity, a gone
|
|
126
|
+
private session, and an empty cgroup are all confirmed. Automatic normal-exit cleanup retains an
|
|
127
|
+
empty cgroup until cwd lease release, and automatic lease acquisition records a no-spawn startup
|
|
128
|
+
marker that is cleared only after provisional Worker/cgroup identity is persisted before spawn.
|
|
129
|
+
Recovery atomically reserves the private socket until the replacement lease is written. Full host/repository
|
|
130
|
+
enforcement for untrusted custom or nested integrations remains the independent boundary's
|
|
131
|
+
responsibility.
|
|
117
132
|
|
|
118
133
|
## 7. Explicit non-goals of this target
|
|
119
134
|
|
|
@@ -125,6 +140,8 @@ This target does not authorize:
|
|
|
125
140
|
- silently treating incomplete evidence as success;
|
|
126
141
|
- claiming that a failed or parked task completed.
|
|
127
142
|
|
|
128
|
-
Coordinated multi-Worker scheduling, OS sandboxing and
|
|
129
|
-
engineering milestones.
|
|
130
|
-
|
|
143
|
+
Coordinated multi-Worker scheduling, OS sandboxing and validation of future breaking CLI/API
|
|
144
|
+
changes remain separate engineering milestones. The supported Claude Code compatibility floor is
|
|
145
|
+
`2.1.270`; versioned install paths are not fixed, but a newer CLI should still rerun the real
|
|
146
|
+
spikes before release. These milestones must not be used to add synchronous human approval to the
|
|
147
|
+
local development loop.
|