clawd-on-desk 子代理 Hook 协议实证:Issue 862 的 Claude Subagent 身份追踪与生命周期边界验证

发布时间:2026/10/9 13:08:56
clawd-on-desk 子代理 Hook 协议实证:Issue 862 的 Claude Subagent 身份追踪与生命周期边界验证 桌面应用交互助手【免费下载链接】clawd-on-deskA pixel desktop pet that watches Claude Code, Codex, Cursor other AI coding agents — so you dont have to.项目地址https://gitcode.com/gh_mirrors/cl/clawd-on-desk点击查看免费下载本文基于仓库内 docs/investigations/issue-862-subagent-hook-protocol-2026-08-14.md 调查文档展开系统梳理 clawd-on-desk 如何通过真实 Claude 会话捕获、验证并实现「子代理subagent身份追踪」这一核心机制。读完你将掌握Claude hook 协议中SubagentStart/SubagentStop/SessionStart的真实事件顺序与字段语义、被阻塞 stop 的自纠错规则、compact/clear 边界行为以及 clawd-on-desk 中「原生 ID 合成事件双通道、视觉计数取最大值」的实现原理与验证方法。1. 调查背景为何要证实子代理 Hook 协议clawd-on-desk 是一款监视 Claude Code、Codex、Cursor 等 AI 编程 Agent 的桌面宠物。其中一项核心职责是统计并展示当前会话中活跃子代理subagent的数量与生命周期——例如两个并行 Explore 子代理同时运行时宠物应显示正确的活跃状态而不是把一个子代理重复计成两个。这依赖 Claude Code 的 command hook 事件流。但 hook 事件中存在多种不确定性旧版本把子代理启动报告为PreToolUse(Task)新版本报告为PreToolUse(Agent)且有时不伴随原生SubagentStartSubagentStop只是「终止尝试」可能被其他 hook 以{decision:block}否决子代理随后继续运行父轮次的Stop并不等于全部子代理结束存在后台子代理/compact、/clear等会话边界会触发SessionStart其source字段startup/resume/clear/compact决定了是否应该清空已确认的子代理集合。Issue #862 的目标就是通过真实会话捕获而非 UI 模拟逐条验证上述行为为实现的「可信原生 ID 追踪」分支提供 D0 级证据。本文即该调查的完整记录。2. 验证环境与方法环境版本 / 状态说明macOS Claude Code2.1.211claude auth status显示loggedInfalse、authMethodnoneClaude Desktop Code Local与 CLI 同引擎未登录环境下的本地会话捕获Windows 11 物理机10.0.26200Claude Code2.1.232Node24.12.0真实双孩子并发运行PR headd3c5851b隔离--settings采样器方法要点隔离设置采样器通过create-settings生成一个独立的--settingshook 文件只做加法、绝不读取或修改~/.claude/settings.json已有的.claude/settings.local.json保持原样捕获完成后临时项目 hook 立即删除。真实性依据Anthropic 文档明确 Desktop Code 的 Local 会话与 CLI 使用同一底层引擎且 Desktop 与 CLI 共享 Claude 设置含 hooks因此这是真实本地 hook 协议捕获而非 UI 模拟。未登录捕获的边界一个隔离的claude -p捕获在Not logged in · Please run /login处停止仅发出UserPromptSubmit与SessionEnd(reasonother)未到达子代理生命周期——说明协议验证必须在已认证会话中进行。3. 认证 Desktop Local 捕获核心事件顺序一次隐私受限会话记录了以下原始顺序文档将协议子代理 ID 替换为 A/B/C顺序原始事件身份证据1PreToolUse(Agent)tool-use 12PreToolUse(Agent)不同的 tool-use 23SubagentStart子代理 Aagent_typeExplore4SubagentStart不同的子代理 Bagent_typeExplore5SubagentStop子代理 A 完全复用6SubagentStop子代理 B 完全复用7–8PostToolUse(Agent)复用最初的两个 tool-use id9–12PreToolUse(Agent)→ 原生 start C → 原生 stop C →PostToolUse(Agent)第三个子代理精确配对13父级Stop主轮次完成关键结论confirmedIds.size 2而 A 与 B 在时间上重叠——两个并发子代理产生两个不同的原生 ID原生 start/stop 携带稳定子代理 ID合成流与原生流观察到的是同一批子代理而不是两个群体当前 Desktop 的工具拼写是Agent而非旧版Taskhook 与兼容分类器已同时接受两者第三个子代理报告无法启动嵌套代理因此本次运行未触发父级发起者parent-originator风险——即嵌套子代理工具调用携带父级子代理 ID 的情况该风险留待后续验证。4. 被阻塞的 Stop同 ID 重新进入的自纠错规则一次一次性 command hook 对首个SubagentStop返回了文档规定的{decision:block,reason:...}被动采样器在该阻塞器之前运行。以真实子代理 ID 替换为 D 后观察到PreToolUse(Agent)→ 原生SubagentStart(D)第一个SubagentStop(D, stop_hook_activefalse)hook 否决后PreToolUse(Bash, agent_idD)→ 匹配的PostToolUse(Bash, agent_idD)第二个SubagentStop(D, stop_hook_activetrue)匹配的父级PostToolUse(Agent)→ 父级Stop。同一个子代理 ID 在被尝试停止后继续存活。这直接印证了实现所用的自纠错规则stop 时移除 ID但当后续来自该 ID 的非 stop 活动证明它仍然存活时重新加入。在 src/state.js 中这条规则体现为SubagentStart含合成与原生向confirmedIds集合添加 IDsrc/state.js#L2676-L2688SubagentStop或子代理作用域的SessionEnd从集合删除 IDsrc/state.js#L2689-L2694其他任何携带该 ID 的活动事件非SessionEnd重新添加——因为SubagentStop可能被其他 hook 否决后续活动是积极存活证据src/state.js#L2695-L2698。同时hook 层会把SubagentStop的stop_hook_active true原样保留为诊断标记hooks/clawd-hook.js#L785-L790供状态侧做同样的自纠错参考。5. 父轮次后的后台子代理一个真实的Agent工具以后台方式启动。以子代理 E 为例事件顺序为PreToolUse(Agent)父级PostToolUse(Agent)与原生SubagentStart(E)父级Stop约 0.5 秒后PreToolUse(Bash, agent_idE)约 20 秒后匹配的PostToolUse(Bash, agent_idE)SubagentStop(E)。因此原始父级Stop并不是整个追踪器的全局清空信号——子代理在主轮次结束后仍存活且可识别。实现据此设计只有SessionStart(sourcestartup/clear)或「权威的 typed 零快照」才允许清空追踪器src/state.js#L2717-L2723。值得注意的是第二次提示并未在该子代理 stop 之前赢得时序竞争后续构造使子代理将其 shell 后台化并提前停止。因此「子代理仍存活时出现UserPromptSubmit」这一场景仍标记为未验证而非通过。6. Compact 与 Clear 边界/compact该构建的 Desktop/compact在同一会话中按序发出PreCompact一个未匹配的SubagentStopID 此前从未出现且无对应SubagentStartSessionStart(sourcecompact)PostCompact。未匹配的 stop 验证了「仅匹配才清除」的 no-op 要求而compact 的SessionStart不得仅因为是主会话开始就清空已确认子代理。state.js 中对应的边界逻辑是仅source startup || source clear的SessionStart才清除确认 IDresume/compact及未知来源都保留src/state.js#L2657-L2667。/clear本次运行中Desktop/clear没有发出SessionStart(sourceclear)而是对旧会话发出SessionEnd(reasonother)下一次提示时发出两个不同 session id的SessionStart(sourcestartup)事件一个立即以reasonother结束另一个接收提示。因此实现中的 startup 清空就是该已安装版本的有效 Desktop clear 边界。此外在 Desktop UI 中离开并重新打开会话不会发出 resume hook因另有无关 Claude 会话在运行重启应用被有意跳过。7. Windows 11 SSH 捕获与权限边界报告人的 Windows 机器RULLER-PCWindows 1110.0.26200运行 Claude Code2.1.232与 Node24.12.0。一次只读的claude --print --settings isolated-file运行恰好启动两个并发 Explore 子代理产生 16 条隐私受限记录两个不同的PreToolUse(Agent)tool-use ID两个不同的原生SubagentStart子代理 ID两个匹配的原生SubagentStop子代理 ID两个匹配的PostToolUse(Agent)tool-use ID无采样器白名单之外的字段。命令以退出码 0 返回WINDOWS_862_DONE。首轮聚焦测试暴露了两个仅采样器相关的失败NTFS 在 Node 请求0600后仍把继承的 ACL 报告为模式0666。提交d3c5851b将 POSIX 模式断言限制在实现该语义的平台并记录 Windows ACL 边界精确重跑后聚焦的生命周期/hook/route/renderer 套件759 通过、0 失败、0 跳过。8. 主合同证据Anthropic Hook 参考Anthropic 当前的 hook 参考code.claude.com/docs/en/hooks规定SubagentStart携带agent_id即子代理的唯一标识SubagentStop携带相同的身份字段与stop_hook_activeSubagentStop可以被阻塞因此 stop 投递只是终止尝试而非子代理已退出的不可撤销证明SessionStart.source取值之一为startup、resume、clear、compact。这些合同字段支撑了实现的「可信原生 ID 通道」与显式SessionStartsource 处理。同一子代理在阻塞 stop 后的后续事件将其重新接纳re-admit。9. 仓库实现证据合成事件、原生通道与证据下限合成 SubagentStarthooks/clawd-hook.js 对当前PreToolUse(Agent)与旧版PreToolUse(Task)也会发出合成SubagentStarthooks/clawd-hook.js#L401-L410、hooks/clawd-hook.js#L624-L652。它独立转发payload.agent_id——因此嵌套子代理工具调用可能携带父级子代理 ID。分类必须先用显式生命周期来源或传入的 Agent/Task 工具名判断 ID 是否原生再考虑将其纳入原生集合hooks/clawd-hook.js#L648-L652。独立证据下限evidence floors实现中的追踪器采用互相独立的证据来源可信原生子代理 ID精确Set成员资格支持 2 层级合成/匿名投递有界视觉下限 1恢复的租约restored lease有界视觉下限 1且不能持有生命周期状态。视觉计数取这些观测的最大值而非求和max而非sum——这防止「原生 合成双投递」把 1 个子代理虚增为 2 个src/state.js#L2676-L2699 中的confirmedIds集合操作即其核心。10. 隔离采样器隐私受限的 D0 捕获工具scripts/manual/claude-subagent-event-sampler.js创建一个独立--settingshook 文件仅记录固定白名单原始/payload 事件名脱敏后的会话哈希redactSessionId以 SHA-256 salt 取前 16 位十六进制子代理 ID/类型工具名/工具 use ID开始/结束的 source 或 reasonstop_hook_active单调序列process.hrtime.bigint()与时间戳。明确排除提示词、工具输入/输出、cwd、转录路径、模型内容与环境数据。日志上限 1 MiBDEFAULT_MAX_BYTES 1024 * 1024POSIX 下以0600打开appendRecord/writeSettings中fchmodSync(fd, 0o600)Windows 下捕获位于当前用户 ACL 保护的临时目录因为 NTFS 不实现 POSIX 权限位。三个子命令create-settings --output file --log file --case id [--block-stop-marker file] record --log file --case id --salt salt --event event block-stop-once --marker filecreate-settings为EVENTS中的全部 11 个事件SessionStart、SessionEnd、UserPromptSubmit、PreToolUse、PostToolUse、PostToolUseFailure、Stop、SubagentStart、SubagentStop、PreCompact、PostCompact各生成一条 command hook超时 5 秒若指定--block-stop-marker还会在SubagentStop上追加一次性阻塞器record读取 stdin JSON按白名单构造记录并追加到日志block-stop-once通过O_EXCL创建 marker 文件实现恰好一次阻塞——首次调用输出{decision:block,reason:For this lifecycle test, use one harmless read-only tool once, then finish.}之后输出{}。测试覆盖test/claude-subagent-event-sampler.test.js 使用node:test覆盖白名单与脱敏记录仅含固定 14 个字段会话 ID 脱敏为 16 位prompt/tool_input/cwd/transcript_path等敏感字段不出现在序列化结果中test/claude-subagent-event-sampler.test.js#L26-L56事件注册每个 D0 事件都生成独立 command hook且命令不以$CLAWD_RAW_EVENT展开test/claude-subagent-event-sampler.test.js#L58-L75一次性阻塞器SubagentStop挂两个 hook被动记录 block-stop-oncemarker 恰好可声明一次test/claude-subagent-event-sampler.test.js#L77-L104权限与上限POSIX 下日志为0600超过上限的记录被拒绝且不破坏既有内容test/claude-subagent-event-sampler.test.js#L106-L120。用于 Desktop 捕获的临时设置与原始日志已在证据记录后审查并删除。11. 剩余证据与后续项核心身份/顺序单元已完备。当前证据与后续项一览✅ 两个并发子代理产生两个不同的原生 ID✅ start/stop 复用同一 ID且记录到真实顺序✅ 被阻塞的SubagentStop后出现同 ID 活动与最终第二次 stop✅ 后台子代理在父级Stop后仍保持活跃✅ 该已安装 Desktop 构建的 compact 与 clear 顺序已记录✅ 维护者手工验证了「存活子代理 stop 之前的新提示」真实 Desktop 行为未保留原始采样日志⏳ 嵌套 Agent/Task 投递、子代理作用域 end、resume、中断为非阻塞兼容性后续项✅ Windows 11 hook 调用产生两个不同的原生子代理 ID并通过聚焦的 759 测试生命周期/renderer 套件。综上Issue #862 的核心 macOS D0 门槛已满足Windows 平台门槛已完整关闭。对仍标记为「未验证」的时序场景如子代理存活期间的UserPromptSubmit文档明确将其列为后续采样目标未将其伪报为通过——这也是本调查证据严谨性的体现。若你需要在真实会话中复现上述验证可参照 scripts/manual/claude-subagent-event-sampler.js 的create-settings用法生成隔离 hook 文件配合claude --settings file启动只读捕获并严格使用 test/claude-subagent-event-sampler.test.js 的断言口径核对记录。赞分享桌面应用交互助手【免费下载链接】clawd-on-deskA pixel desktop pet that watches Claude Code, Codex, Cursor other AI coding agents — so you dont have to.项目地址https://gitcode.com/gh_mirrors/cl/clawd-on-desk点击查看免费下载相关推荐Clawd on Desk 集成 CodeWhale基于生命周期 Hook 的桌面宠物状态感知实现指南Clawd on Desk 集成 CodeWhale基于生命周期 Hook 的桌面宠物状态感知实现指南 本篇技术指南以 docs/guides/codewha桌面应用交互助手Clawd on Desk 已知限制全景指南权限气泡、会话生命周期与终端聚焦的边界Clawd on Desk 已知限制全景指南权限气泡、会话生命周期与终端聚焦的边界 导读 本文以 docs/guides/known limitations.桌面应用交互助手ElixirLS认证协议身份验证ElixirLS认证协议身份验证 ElixirLSElixir Language Server作为遵循语言服务器协议LSP和调试适配器协议DAP的上一篇不止RESTchinese-poetry-api GraphQL接口与Playground完全教程下一篇Off Grid AI新手避坑指南10个实用技巧让本地LLM聊天又快又稳创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询