pi-claude-supervisor 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/LICENSE +21 -0
- package/README.cn.md +98 -0
- package/README.md +122 -0
- package/docs/architecture.md +122 -0
- package/docs/engineering-plan.md +918 -0
- package/docs/implementation-review.md +62 -0
- package/docs/independent-review.md +332 -0
- package/docs/releasing.md +112 -0
- package/docs/testing.md +109 -0
- package/docs/transport-spike-2026-09-12.md +94 -0
- package/package.json +72 -0
- package/src/config.ts +35 -0
- package/src/decision-session-store.ts +170 -0
- package/src/decision-worker.ts +245 -0
- package/src/events.ts +179 -0
- package/src/index.ts +500 -0
- package/src/notifications.ts +85 -0
- package/src/policy.ts +61 -0
- package/src/state.ts +44 -0
- package/src/supervisor.ts +626 -0
- package/src/types.ts +122 -0
- package/src/verifier.ts +40 -0
- package/src/worker/environment.ts +31 -0
- package/src/worker/process-adapter.ts +604 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented here.
|
|
4
|
+
|
|
5
|
+
## [0.2.0](https://github.com/btnalit/pi-claude-supervisor/compare/v0.1.0...v0.2.0) (2026-09-12)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* persist decision worker sessions across restarts ([a926c0e](https://github.com/btnalit/pi-claude-supervisor/commit/a926c0e4f3455cbc5dfbbcff1441d1d1497939ed))
|
|
11
|
+
* persist Decision Worker sessions and add release gates ([de73d29](https://github.com/btnalit/pi-claude-supervisor/commit/de73d29549605026985db301112ae3745d164bd7))
|
|
12
|
+
|
|
13
|
+
## [0.1.0] - Unreleased
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Standard Pi/npm package metadata and TypeScript extension entry point.
|
|
18
|
+
- Dependency-free process-pipe WorkerAdapter with process-group control.
|
|
19
|
+
- Explicit Supervisor state machine, append-only event log and turn budget.
|
|
20
|
+
- Deterministic Policy Gate and independent verification phase.
|
|
21
|
+
- Minimal worker environment, argv-aware permission policy, watchdog timeouts and startup cleanup.
|
|
22
|
+
- Opt-in Claude JSONL framing with duplicate-message suppression and transport Spike evidence for prompt, multi-turn and session resume.
|
|
23
|
+
- Event-log sequence recovery and credential-shaped redaction.
|
|
24
|
+
- Bounded output capture, stdin-write timeout, process-group cleanup retry and stop preemption.
|
|
25
|
+
- Linux cgroup-v2 descendant cleanup, including a `setsid()` regression fixture, with required/auto modes.
|
|
26
|
+
- Lifecycle event retry/order preservation, output restoration after log failure and shutdown cleanup retries.
|
|
27
|
+
- Claude CLI 2.1.268 permission allow/deny and SIGTERM/SIGINT transport spike evidence.
|
|
28
|
+
- Event-driven JSONL `control_request`/`result`/exit events, permission responses, persistent Pi Decision Worker automation, bounded duplicate/turn handling, and outbound human-intervention webhooks.
|
|
29
|
+
- Long-task defaults are now 100 automatic turns, 4 hours wall time and 20 minutes without output; Decision Worker API failures alert human operators directly instead of attempting an LLM fallback.
|
|
30
|
+
- Automatic Decision Worker sessions now persist as Pi JSONL with a 0600 task registry. Unclean Pi restarts expose explicit `/supervise recover <task-id>` recovery; Claude work is not silently duplicated.
|
|
31
|
+
- Local tests and package-content checks.
|
|
32
|
+
|
|
33
|
+
### Limitations
|
|
34
|
+
|
|
35
|
+
- PTY transport and cross-version Claude CLI permission/session semantics are out of scope for this pinned release; Claude JSONL support remains opt-in outside automatic mode. The installed 2.1.268 CLI is covered by local permission and signal spikes, while the cgroup startup-attachment window remains.
|
|
36
|
+
- No automatic merge, deployment, release or publication is implemented.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 yancao
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.cn.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# pi-claude-supervisor
|
|
2
|
+
|
|
3
|
+
[](https://github.com/btnalit/pi-claude-supervisor/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/pi-claude-supervisor)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
[English](README.md)
|
|
8
|
+
|
|
9
|
+
用于 Pi 的 Claude Code Worker 监督扩展。MVP 中 Pi 负责生命周期、状态机、策略门和独立验收;Worker 只是被显式启动的子进程。
|
|
10
|
+
|
|
11
|
+
> 当前默认 transport 是无额外依赖的 process pipe,不是 PTY。已新增可选 Claude JSONL framing,并通过基础 prompt、多轮和 resume Spike。当前优先保证生命周期、进程组清理、恢复和独立验收;低权限用户、OS sandbox 与网络隔离不作为当前主线,按明确授权和宿主机策略运行,后续再做安全加固。
|
|
12
|
+
|
|
13
|
+
## 关键安全边界
|
|
14
|
+
|
|
15
|
+
- 不会在扩展加载时自动启动 Worker。
|
|
16
|
+
- 不经过 shell 启动子进程。
|
|
17
|
+
- Worker 只继承最小环境;凭据必须由调用方显式传入。
|
|
18
|
+
- 破坏性命令和绕过权限的 Worker 参数默认拒绝;需要复核的启动命令会请求用户批准,不会一律拒绝。
|
|
19
|
+
- Linux 上优先使用可写的 cgroup v2 清理后代进程,包括 `setsid()` 后代;不可用时回退到进程组清理。需要强制失败闭环时,embedding 集成可使用 `cgroupMode: "required"`。
|
|
20
|
+
- 普通联网查询不因联网本身被拒绝;下载后直接交给 shell 等高风险模式仍需人工复核。
|
|
21
|
+
- Worker 声称完成只会进入 `verifying`,不能作为成功证据。
|
|
22
|
+
- 默认独立验收命令为 `git diff --check`。
|
|
23
|
+
- 扩展运行时不执行 merge、deploy、release 或 publish;仓库 Release 只会在维护者合并 Release Please PR 且 CI 门禁全部通过后自动发布。
|
|
24
|
+
- 默认 4 小时总时限、20 分钟无输出 watchdog 超时即停止 Worker,适合长程开发任务;嵌入调用方可将对应选项设为 `0` 关闭。
|
|
25
|
+
|
|
26
|
+
## 安装和使用
|
|
27
|
+
|
|
28
|
+
需要 Pi 0.85+ 和 Node.js 22.19+:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
pi install npm:pi-claude-supervisor
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
在 Pi 中使用。手动/兼容模式默认使用 process-pipe。要启用事件驱动的 Pi Decision Worker,使用 Claude JSONL 自动模式:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
export PI_CLAUDE_SUPERVISOR_MODE=auto
|
|
38
|
+
export PI_CLAUDE_SUPERVISOR_WORKER='claude --safe-mode --tools Bash'
|
|
39
|
+
# 可选:人工升级通知;generic 或 wecom
|
|
40
|
+
export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_URL='https://example.invalid/webhook'
|
|
41
|
+
export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_FORMAT=generic
|
|
42
|
+
# export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_SECRET='shared-secret'
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
自动模式会强制使用 `claude-jsonl`,通过 `result`、`control_request` 和进程
|
|
46
|
+
`exit` 事件唤醒 Decision Worker;不会依赖 `/supervise poll` 轮询。本版本固定按已验证设备的
|
|
47
|
+
Claude CLI `2.1.268` 运行,跨版本兼容性不在本轮范围内。
|
|
48
|
+
|
|
49
|
+
然后在 Pi 中使用:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
/supervise capabilities
|
|
53
|
+
/supervise start inspect the current repository
|
|
54
|
+
/supervise poll
|
|
55
|
+
/supervise sessions
|
|
56
|
+
/supervise recover <task-id>
|
|
57
|
+
/supervise stop human requested stop
|
|
58
|
+
/supervise verify
|
|
59
|
+
/supervise approve <task-id> allow|deny [request-id]
|
|
60
|
+
/supervise takeover <task-id>
|
|
61
|
+
/supervise resume-auto <task-id>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
人工升级通知的 generic JSON 格式为:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"schema": "pi-claude-supervisor/human-intervention/v1",
|
|
69
|
+
"event": "human_intervention_required",
|
|
70
|
+
"task": { "id": "...", "goal": "...", "cwd": "..." },
|
|
71
|
+
"worker": { "id": "..." },
|
|
72
|
+
"reason": "...",
|
|
73
|
+
"question": "...",
|
|
74
|
+
"permission": { "requestId": "...", "toolUseId": "...", "toolName": "Bash", "input": {} },
|
|
75
|
+
"actions": ["approve_or_deny_permission", "send_instruction", "stop_worker", "takeover"]
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
当前 webhook 是出站通知,不直接接受批准命令;批准或接管仍通过 Pi。
|
|
80
|
+
自动模式会将 Decision Worker 会话持久化到状态目录。Pi 非正常重启后,`/supervise sessions`
|
|
81
|
+
会显示 `recoverable` 任务;显式执行 `/supervise recover <task-id>` 会恢复 Decision Worker 上下文并
|
|
82
|
+
重新启动 Claude Worker,不会静默恢复或重复执行任务。
|
|
83
|
+
自动模式下,Decision Worker 可以安全拒绝 `AskUserQuestion`,让 Claude 将问题转成普通文本,
|
|
84
|
+
再根据任务和仓库证据自动回答;无法确定时才升级人工。如需微信内闭环,需要另建带签名验证、
|
|
85
|
+
一次性 action token 和重放保护的入站 callback 服务。
|
|
86
|
+
|
|
87
|
+
可以从不同工作目录启动多个任务会话;活动会话不能共享同一 cwd,建议每个任务使用独立 worktree:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
/supervise sessions
|
|
91
|
+
/supervise poll all
|
|
92
|
+
/supervise poll <task-id>
|
|
93
|
+
/supervise send <task-id> continue after checking the test failure
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Pull Request 必须通过聚合的 `CI / Quality gate`。Release Please 根据 Conventional Commits 创建版本 PR;维护者合并后,Release workflow 会针对精确 tag commit 重新验证,并通过受保护的 `npm` environment 使用 npm provenance 发布。
|
|
97
|
+
|
|
98
|
+
详细内容见 [engineering-plan.md](docs/engineering-plan.md)、[independent-review.md](docs/independent-review.md)、[architecture.md](docs/architecture.md)、[testing.md](docs/testing.md) 和 [releasing.md](docs/releasing.md)。
|
package/README.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# pi-claude-supervisor
|
|
2
|
+
|
|
3
|
+
[](https://github.com/btnalit/pi-claude-supervisor/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/pi-claude-supervisor)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
English · [简体中文](README.cn.md)
|
|
8
|
+
|
|
9
|
+
A policy-gated [Pi](https://pi.dev) extension for supervising a Claude Code worker.
|
|
10
|
+
The MVP keeps Pi in control of lifecycle, state, policy and verification while the
|
|
11
|
+
worker remains an explicitly started child process.
|
|
12
|
+
|
|
13
|
+
> **MVP status:** the default transport is dependency-free process pipes, not PTY.
|
|
14
|
+
> An opt-in Claude JSONL framing mode has passed basic prompt, multi-turn and
|
|
15
|
+
> resume fixtures. The current priority is signal, shutdown, process-group and
|
|
16
|
+
> recovery validation; OS sandbox, low-privilege execution and network isolation
|
|
17
|
+
> are deferred hardening items and are not required by the current MVP plan.
|
|
18
|
+
|
|
19
|
+
## Safety boundary
|
|
20
|
+
|
|
21
|
+
- The extension never starts a worker automatically.
|
|
22
|
+
- Worker commands are launched without a shell.
|
|
23
|
+
- Workers receive a minimal environment; credentials must be explicitly supplied by the caller.
|
|
24
|
+
- Destructive command patterns and permission-bypass worker flags are denied; review-level patterns request explicit user approval instead of being blanket-denied.
|
|
25
|
+
- Ordinary network use is not denied merely because it is network use; download-to-shell patterns still require review.
|
|
26
|
+
- A worker completion is only a transition to `verifying`; it is not evidence of success.
|
|
27
|
+
- Verification is an independent host command (default: `git diff --check`).
|
|
28
|
+
- The extension never performs merge, deploy, release, or publish at runtime. Repository releases are automated only after a maintainer merges a Release Please PR and the full CI gate passes.
|
|
29
|
+
- 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.
|
|
30
|
+
- 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 the adapter's `cgroupMode: "required"` for a fail-closed integration.
|
|
31
|
+
- Events are append-only JSONL records in `~/.pi/agent/claude-supervisor/events.jsonl`.
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
Requires Pi 0.85+ and Node.js 22.19+.
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
pi install npm:pi-claude-supervisor
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For local development:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm ci --ignore-scripts
|
|
45
|
+
npm run check
|
|
46
|
+
npm run build
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Use
|
|
50
|
+
|
|
51
|
+
Set the worker executable if needed, then use explicit commands in Pi:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
export PI_CLAUDE_SUPERVISOR_WORKER=claude
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
/supervise capabilities
|
|
59
|
+
/supervise start inspect the current repository and report what should be changed
|
|
60
|
+
/supervise sessions
|
|
61
|
+
/supervise recover <task-id>
|
|
62
|
+
/supervise poll
|
|
63
|
+
/supervise poll all
|
|
64
|
+
/supervise send continue with read-only inspection
|
|
65
|
+
/supervise pause
|
|
66
|
+
/supervise resume
|
|
67
|
+
/supervise stop human requested stop
|
|
68
|
+
/supervise verify
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The default MVP writes the task to the worker's stdin as plain process-pipe
|
|
72
|
+
text. After running the transport spike for the target CLI, JSONL framing can
|
|
73
|
+
be selected explicitly:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
export PI_CLAUDE_SUPERVISOR_TRANSPORT=jsonl
|
|
77
|
+
export PI_CLAUDE_SUPERVISOR_WORKER='claude --safe-mode --tools ""'
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This adds Claude Code stream-json flags and frames supervisor messages as JSONL.
|
|
81
|
+
The supervisor allows only one active JSONL request per session: poll until its
|
|
82
|
+
`result` and `waiting` state before sending the next turn. Session resume is not
|
|
83
|
+
yet exposed by the adapter. Multiple independent task sessions can run
|
|
84
|
+
concurrently when they use different canonical working directories or
|
|
85
|
+
worktrees; same-directory starts are rejected even when concurrent, and
|
|
86
|
+
`/supervise sessions` lists the sessions. Unattended use still requires the
|
|
87
|
+
remaining lifecycle, signal and recovery checks. Host permissions and network
|
|
88
|
+
access follow explicit caller authorization and host policy; there is no
|
|
89
|
+
automatic merge, deploy, release or publish.
|
|
90
|
+
|
|
91
|
+
Automatic mode persists the Pi Decision Worker session under the configured state
|
|
92
|
+
directory. After an unclean Pi restart, `/supervise sessions` lists recoverable
|
|
93
|
+
tasks; `/supervise recover <task-id>` explicitly restores the Decision Worker
|
|
94
|
+
context and starts a new Claude Worker. It never silently resumes or duplicates
|
|
95
|
+
work. The adapter intentionally does not inherit arbitrary host environment variables.
|
|
96
|
+
Pass credentials through an explicit `WorkerStartInput.env` in an embedding
|
|
97
|
+
integration. For the built-in command, opt in to named variables, for example
|
|
98
|
+
`PI_CLAUDE_SUPERVISOR_WORKER_ENV=ANTHROPIC_API_KEY`.
|
|
99
|
+
|
|
100
|
+
## Development
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npm run typecheck
|
|
104
|
+
npm test
|
|
105
|
+
npm run check:package
|
|
106
|
+
npm run check:docs
|
|
107
|
+
npm run check:automation
|
|
108
|
+
npm run check:workflows
|
|
109
|
+
npm run build
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
See [the engineering plan](docs/engineering-plan.md), [the independent review](docs/independent-review.md),
|
|
113
|
+
[architecture](docs/architecture.md), [testing](docs/testing.md), and [releasing](docs/releasing.md).
|
|
114
|
+
|
|
115
|
+
Pull requests are gated by the aggregated `CI / Quality gate`. Release Please
|
|
116
|
+
creates version PRs from Conventional Commits; after a maintainer merges one,
|
|
117
|
+
`Release` verifies the exact tag commit and publishes the package with npm
|
|
118
|
+
provenance through the protected `npm` environment.
|
|
119
|
+
|
|
120
|
+
## License
|
|
121
|
+
|
|
122
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
## Control boundary
|
|
4
|
+
|
|
5
|
+
Pi owns the `Supervisor`. The supervisor owns the task state machine, event log,
|
|
6
|
+
turn budget, policy decision and independent verifier. `WorkerAdapter` owns only
|
|
7
|
+
process lifecycle and transport details.
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
Pi extension
|
|
11
|
+
|
|
|
12
|
+
v
|
|
13
|
+
Supervisor -> Policy Gate -> WorkerAdapter -> child process
|
|
14
|
+
|
|
|
15
|
+
+------> EventLog (JSONL)
|
|
16
|
+
+------> Independent Verifier
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The Worker cannot advance a task directly to `completed`. A clean worker exit
|
|
20
|
+
moves the supervisor to `verifying`; only a successful verifier moves it to
|
|
21
|
+
`completed`.
|
|
22
|
+
|
|
23
|
+
The extension keeps a registry of independent task sessions. Each session has
|
|
24
|
+
its own Supervisor, watchdog, state machine and Worker handle, while the event
|
|
25
|
+
log is shared and protected by an inter-process lock. Concurrent active sessions must use non-overlapping canonical working
|
|
26
|
+
directories/worktrees; same-cwd and parent/child cwd starts are rejected before
|
|
27
|
+
spawn, including concurrent starts, to prevent uncoordinated edits. Pending starts
|
|
28
|
+
are also awaited during Pi shutdown.
|
|
29
|
+
|
|
30
|
+
## MVP transport
|
|
31
|
+
|
|
32
|
+
`ProcessWorkerAdapter` uses `node:child_process.spawn` with:
|
|
33
|
+
|
|
34
|
+
- `shell: false` (the default and intentionally not overridden);
|
|
35
|
+
- a detached process group for pause/resume/kill control;
|
|
36
|
+
- separate stdout/stderr capture;
|
|
37
|
+
- idempotency keys for messages;
|
|
38
|
+
- no session-resume claim.
|
|
39
|
+
|
|
40
|
+
This is a control-boundary fixture and headless transport. It does not emulate a
|
|
41
|
+
terminal. Manual compatibility mode remains `process-pipe`; automatic mode
|
|
42
|
+
(`PI_CLAUDE_SUPERVISOR_MODE=auto`) forces Claude JSONL and uses the CLI contract
|
|
43
|
+
validated by the fixed-version spike.
|
|
44
|
+
|
|
45
|
+
A worker exit automatically triggers cleanup, and terminal status waits for
|
|
46
|
+
that cleanup to be confirmed (or reports a cleanup error). On Linux the adapter
|
|
47
|
+
uses cgroup v2 automatically when the current user cgroup is writable; the
|
|
48
|
+
`required` mode fails startup if cgroup attachment is unavailable. Cgroup
|
|
49
|
+
cleanup kills descendants even when they call `setsid()` or create another
|
|
50
|
+
process group. Attachment occurs immediately after spawn, so a worker that
|
|
51
|
+
forks before attachment remains a documented startup-window limitation.
|
|
52
|
+
|
|
53
|
+
When cgroup v2 is unavailable, the adapter falls back to detached
|
|
54
|
+
process-group cleanup. That fallback is not recursive: `setsid()` descendants
|
|
55
|
+
can escape, and PID reuse between leader exit and cleanup is a host-level
|
|
56
|
+
limitation. Production deployments that require an atomic boundary should use a
|
|
57
|
+
service-manager scope, Job Object, pidfd-aware reaper, or equivalent supervisor.
|
|
58
|
+
The Pi host installs graceful `SIGTERM`/`SIGINT` handlers, but `SIGSTOP` and
|
|
59
|
+
`SIGKILL` cannot be handled; no orphan guarantee is claimed for those host-fatal
|
|
60
|
+
signals.
|
|
61
|
+
|
|
62
|
+
## State machine
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
idle -> starting -> running -> waiting -> running -> verifying -> completed
|
|
66
|
+
| | | |
|
|
67
|
+
v v v v
|
|
68
|
+
paused failed stopped idle
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`stop` is available from `starting`, `running`, `waiting` and `paused`. Invalid
|
|
72
|
+
transitions fail closed. Supervisor lifecycle operations and their state/event
|
|
73
|
+
updates run through one serial queue, so concurrent `poll`, `send`, `stop`,
|
|
74
|
+
watchdog and shutdown work cannot produce duplicate terminal transitions. If a
|
|
75
|
+
lifecycle event append fails after the state transition, it remains pending and
|
|
76
|
+
is retried before the next lifecycle operation; output events restore their
|
|
77
|
+
chunks for a lossless retry.
|
|
78
|
+
|
|
79
|
+
## Event log
|
|
80
|
+
|
|
81
|
+
Events are JSONL with a monotonic sequence number, timestamp, task ID and worker
|
|
82
|
+
ID. Appends use a per-log atomic lock directory with owner PID, bounded waiting
|
|
83
|
+
and stale-owner detection. Each append refreshes the sequence from disk while
|
|
84
|
+
holding the lock, so independent Pi processes cannot reuse sequence numbers.
|
|
85
|
+
The log is diagnostic evidence, not an authorization mechanism. Log contents
|
|
86
|
+
must be treated as sensitive because worker output may contain repository data.
|
|
87
|
+
|
|
88
|
+
For Claude JSONL, the adapter tracks `activeRequests`, `lastInputAt` and
|
|
89
|
+
`lastOutputAt`. A `result` record closes an active request; malformed output does
|
|
90
|
+
not. JSONL sends are rejected while a request is active, and a valid terminal
|
|
91
|
+
result moves the session to `waiting`; only then may the next turn be sent.
|
|
92
|
+
Input writes are serialized with stop and are acknowledged through the stream
|
|
93
|
+
write callback before their idempotency key is consumed. Writes have a bounded
|
|
94
|
+
timeout, and `stop()` preempts a queued lifecycle operation by initiating adapter
|
|
95
|
+
termination immediately. This status is observable by `poll` and prevents blind
|
|
96
|
+
duplicate turns. The adapter also exposes event subscriptions for `result`,
|
|
97
|
+
`control_request`, permission requests and process exit. Automatic mode routes
|
|
98
|
+
those events to a persistent, read-only Pi Decision Worker; its Pi session JSONL
|
|
99
|
+
and task mapping are persisted under the supervisor state directory. After an
|
|
100
|
+
unclean Pi restart, recovery is explicit: `/supervise recover <task-id>` restores
|
|
101
|
+
the Decision Worker context and starts a new Claude Worker. It does not silently
|
|
102
|
+
resume or duplicate a task. It does not poll to detect turn completion. A watchdog timer remains only as a deadlock safety
|
|
103
|
+
fallback. Permission actions pass through `evaluatePermission` and can be
|
|
104
|
+
approved or denied manually with `/supervise approve`; human escalation is sent
|
|
105
|
+
to an outbound webhook when configured. If the Decision Worker API/model call
|
|
106
|
+
fails, the system records `decision_worker_failed` and directly alerts the
|
|
107
|
+
human operator; it does not attempt a second LLM fallback. Alert delivery is
|
|
108
|
+
kept independent from event-log persistence so an audit write failure cannot
|
|
109
|
+
suppress the alert.
|
|
110
|
+
|
|
111
|
+
## Deliberate non-goals
|
|
112
|
+
|
|
113
|
+
- automatic merge/deploy/release;
|
|
114
|
+
- unauthenticated inbound webhook commands; outbound notifications do not grant
|
|
115
|
+
permission and do not replace Pi human takeover;
|
|
116
|
+
- treating an unknown Claude interactive question as safe to answer automatically;
|
|
117
|
+
- bypassing Claude Code permissions;
|
|
118
|
+
- accepting model text as verification;
|
|
119
|
+
- shell command interpolation;
|
|
120
|
+
- automatic network denial or a fake domain allowlist. Network access follows
|
|
121
|
+
Claude's own permission model and the command policy; suspicious download-to-
|
|
122
|
+
shell patterns require human review rather than blanket network rejection.
|