Skip to content

fix(hooks): Claude hook payload via stdin, not $CLAUDE_TOOL_USE_INPUT - #1

Closed
chenyida7-prog wants to merge 1 commit into
mainfrom
fix/hook-payload-stdin
Closed

fix(hooks): Claude hook payload via stdin, not $CLAUDE_TOOL_USE_INPUT#1
chenyida7-prog wants to merge 1 commit into
mainfrom
fix/hook-payload-stdin

Conversation

@chenyida7-prog

Copy link
Copy Markdown
Collaborator

Summary

7ec8a2f 修复了 PreToolUse 的 matcher(Bash → Bash|Write|Edit),让 Write/Edit
调用能真正触发 hook。但 hook 命令本身其实从没生效过:它把字面量字符串
"$CLAUDE_TOOL_USE_INPUT" POST 给后端(单引号包住导致 shell 不展开,而且这个
环境变量本身也不存在——Claude Code 是把 PreToolUse 的 payload 写到 hook 命令
的 stdin,不是环境变量)。后端每次都 422,而 curl 遇到 422 退出码仍是 0,
Claude Code 就把它当作"放行"处理——不管 matcher 覆盖了哪些工具,7ec8a2f
前后都一样,写操作从没被真正拦过。

  • _hooks_command_claude():改用 -d @- 从 stdin 读取 POST body。
  • _merge_hook_entry():之前重装 hook 时只比较 matcher 字符串是否一致,
    一致就直接跳过——导致哪怕 command 是坏的,只要 matcher 已经是最新的,
    重装也不会把坏 command 换掉。现在改成识别到是自己的 hook 就整体覆盖
    (同时扩展识别逻辑,让装了旧版坏 command 的用户重装时能原地升级,
    不会重复追加一条 matcher)。

Test plan

  • 在真实 Claude Code 会话里对真实 KB 做了端到端验证:直接 Write、Edit、
    裸 rm 操作 KB 文件均被拦截并返回引导文案;MCP 工具(write__delete_document 等)
    正常放行。
  • 更新了 tests/test_client_config.py 的相关断言,并补了一条回归测试
    (test_upgrades_legacy_command_not_duplicated)覆盖"重装不会产生重复 matcher"。
  • pytest 未在本机跑通(本机没装 pytest)——合并前请在 CI / 开发环境跑一遍。

…SE_INPUT

7ec8a2f fixed the PreToolUse matcher (Bash -> Bash|Write|Edit) so Write/Edit
calls actually trigger the hook. But the hook command itself never worked:
it POSTed the literal string "$CLAUDE_TOOL_USE_INPUT" as the request body
(single-quoted, so the shell never expanded it — and no such env var exists
anyway; Claude Code delivers the PreToolUse payload on the hook command's
stdin). The backend 422'd on every single call, and curl's exit code stayed
0 on that 422, so Claude Code silently treated every operation as allowed —
regardless of matcher, before or after 7ec8a2f.

Fix: _hooks_command_claude() now uses `-d @-` to read the POST body from
stdin, where Claude Code actually writes it.

Also fixes _merge_hook_entry(): it only compared the `matcher` string when
deciding whether an existing install was "already current", so once the
matcher already read Bash|Write|Edit, a stale `command` (like the broken
one above) would survive every future reinstall untouched. It now
overwrites the whole entry whenever _matcher_is_mine() recognizes it as
ours (also extended to recognize the old broken command, so an existing
install upgrades in place instead of getting a duplicate matcher).

Verified end-to-end in a live Claude Code session against the real KB:
direct Write, Edit, and bare `rm` targeting KB files are now denied with
the intended guidance message; MCP tools (write__delete_document, etc.)
still pass through normally.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqKnwdnye3njPuxqxvLSi8
@CoderMoray

Copy link
Copy Markdown
Owner

Hook stdin 修复已收到并合入 main,非常感谢,这个修复很关键!

处理情况

  • 你的分支改动已通过 cherry-pick 合入 main(对应 main 上的 ee0a161),无冲突。
  • 这个修复挖到了比 matcher 更深的根因:$CLAUDE_TOOL_USE_INPUT 环境变量根本不存在、单引号包裹导致 POST 非法 JSON 被静默 allow。之前只修了 matcher,没发现 hook 命令本身也一直是坏的。
  • 合入后补了一个 docstring 对齐(e82f66e),把 hooks_matcher() 注释里残留的 $CLAUDE_TOOL_USE_INPUT 描述改为实际的 -d @-。

WorkBuddy 验证

  • 你问的 "WorkBuddy 是否走 stdin" 已确认:WorkBuddy 与 Claude Code 的 PreToolUse hook 协议完全同构(payload 走 stdin、读 hookSpecificOutput.permissionDecision、退出码 0/2/其它、配置落 ~/.workbuddy/settings.json 须完全重启)。
  • 我们的 -d @- 命令直接复用,无需单独适配;后端也不依赖 tool_use_id/call_id 字段,字段名差异无影响。

记录

  • 已同步到知识库(KB)和 docs/DEV.md(新增「Claude hook payload 走 stdin bugfix」节 + WorkBuddy 协议确认)。

测试

  • 后端 705 全绿。

一个协作提示(非本次代码问题)

  • 你 push 的 commit 作者邮箱是 chenyida@chenyidadeMacBook-Air.local,这是 git 未配置身份时自动生成的机器默认邮箱。建议配置 git 身份为你的 GitHub noreply 邮箱(格式 <数字ID>+<用户名>@users.noreply.github.com),否则 commit 不会关联到你的 GitHub 账号(不显示在贡献图/头像上,会显示为未知作者)。配置命令:git config --global user.name "你的名字"; git config --global user.email "你的noreply邮箱"。

你的 fix/hook-payload-stdin 分支改动已并入 main(cherry-pick),该 PR 已过时,可以关闭。后续建议基于最新 main 开新分支协作。再次感谢!

@CoderMoray

Copy link
Copy Markdown
Owner

改动已通过 cherry-pick 合入 main(ee0a161),本 PR 关闭,避免与 main 上的改动重复。

@CoderMoray CoderMoray closed this Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants