如何使用 Claude Code Hook 强制采用正确的 CLI
学习如何使用 Claude Code Hook 阻止不需要的 CLI 命令,并引导 AI 编码智能体使用正确工具,而不是依赖 CLAUDE.md。
本页目录
关于 Claude Code,我最常被问到的问题之一是:如何强制它使用正确的 CLI 命令?
如何让它使用 pnpm 而不是 npm?如何让它调用我的包装脚本,而不是直接使用 npx ?又如何彻底阻止它运行某些命令?
The Problem with CLAUDE.md
最直接的答案,是在 CLAUDE.md 文件中写入一条指令:
Use pnpm instead of npm for all package management tasks.
大多数时候这样有效,但存在两个问题。
它会浪费指令预算。 这条指令只在 Claude 运行包管理器命令时才有用。把它放入 CLAUDE.md 会使它成为仓库中每项任务的全局上下文。LLM 的指令预算有限,大约超过 500 条指令后就会开始混乱。你应该把预算用在规划、实现和架构等难题上,而不是提醒该使用哪个包管理器。
它并不具备确定性。 添加“不要使用 git push”到 CLAUDE.md reduces 只会降低强制推送发生的概率,并不能 prevent 阻止它。你消耗了指令预算,却仍然无法得到保证。
想继续深入: 加入“面向真正工程师的 AI 编码”候补名单
Claude Code Hook:确定性解决方案
Hook 允许你在 Claude Code 执行周期的特定节点运行确定性代码。它们配置在 .claude/settings.json 文件中。
这里关注的 Hook 是 PreToolUse。它会在 工具调用 执行前触发,并可以阻止该操作。如果 Hook 以代码 2退出,操作就会被阻止,错误消息也会反馈给 Claude,让它进行调整。
下面是一个 PreToolUse Hook 的结构,用于阻止 Bash 命令:
{"hooks": {"PreToolUse": [{"matcher": "Bash","hooks": [{"type": "command","command": ".claude/hooks/enforce-pnpm.sh"}]}]}}
Hook 脚本会从 stdin 接收包含工具名称和参数的 JSON。它检查命令,然后以 0 退出以允许执行,或以 2 退出以阻止执行:
#!/bin/bashINPUT=$(cat)COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')if echo "$COMMAND" | grep -qE "^npm "; thenecho "Blocked: use pnpm instead of npm" >&2exit 2fiexit 0
Claude 看到“使用 pnpm 而不是 npm”的消息后,会用正确命令重试。这样既不浪费指令预算,也不可能运行错误命令。
提示词
无需手写这些 Hook,Claude Code 已经知道如何创建它们。下面这段提示词可以直接粘贴到 Claude Code 中,把 CLAUDE.md 中的指令转换成确定性 Hook:
Take the instructions in your @CLAUDE.md file and turn them intodeterministic Claude Code hooks in this project directory.Not all the instructions will be deterministic: only do the ones you can,such as instructions to use one CLI command over another, or disallowingcertain CLI commands.Hooks should be added to `.claude/settings.json` under the `hooks` key,using the `PreToolUse` event with a `Bash` matcher.Use separate bash scripts in `.claude/hooks/` for running the hooks:```sh#!/bin/bashINPUT=$(cat)COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')if echo "$COMMAND" | grep -q "drop table"; thenecho "Blocked: dropping tables is not allowed" >&2exit 2fiexit 0```First, confirm with the user which hooks will be created.Second, implement the hooks.Third, provide the user with instructions to test the newly created hooks(by restarting Claude Code).
该提示词会让 Claude 读取现有的 CLAUDE.md,识别哪些指令可以通过确定性方式强制执行,并将其转换为 PreToolUse Hook 脚本。创建任何内容前,它会先请求确认,然后引导你完成测试。