Claude Code中英文系列教程24:使用钩子hooks扩展 Claude Code 的行为

Learn how to customize and extend Claude Code's behavior by registering shell commands

学习如何通过注册 Shell 命令来自定义和扩展 Claude Code 的行为

Claude Code hooks are user-defined shell commands that execute at various points in Claude Code's lifecycle. Hooks provide deterministic control over Claude Code's behavior, ensuring certain actions always happen rather than relying on the LLM to choose to run them.

Claude Code 钩子是用户定义的 Shell 命令,它们在 Claude Code 的生命周期中的不同点执行。钩子提供对 Claude Code 行为的确定性控制,确保某些操作总是发生,而不是依赖 LLM 来选择运行它们。

Example use cases for hooks include:

钩子的使用包括:

1,Notifications: Customize how you get notified when Claude Code is awaiting your input or permission to run something.

通知:自定义当 Claude Code 等待您的输入或运行权限时如何接收通知。

2,Automatic formatting: Run prettier on .ts files, gofmt on .go files, etc. after every file edit.

自动格式化:在每次文件编辑后 在.ts 文件上运行 prettier, 在.go 文件上运行gofmt 等。

3,Logging: Track and count all executed commands for compliance or debugging.

日志记录:跟踪和统计所有已执行的命令以符合合规要求或进行调试。

4,Feedback: Provide automated feedback when Claude Code produces code that does not follow your codebase conventions.

反馈:当 Claude Code 生成的代码不符合您的代码库规范时,提供自动反馈。

5,Custom permissions: Block modifications to production files or sensitive directories.

自定义权限:阻止对生产文件或敏感目录的修改。

By encoding these rules as hooks rather than prompting instructions, you turn suggestions into app-level code that executes every time it is expected to run.

通过将这些规则编码为钩子而不是提示指令,从而将建议转换为应用程序级别的代码,该代码在每次预期运行时都会执行。

You must consider the security implication of hooks as you add them, because hooks run automatically during the agent loop with your current environment's credentials. For example, malicious hooks code can exfiltrate your data. Always review your hooks implementation before registering them.

在添加钩子时,您必须考虑其安全影响,因为钩子在agent循环期间会使用当前环境的凭据自动运行。例如,恶意的钩子代码可以窃取您的数据。在注册钩子之前,始终审查您的钩子实现。

一,Hook Events Overview 钩子事件概述

Claude Code provides several hook events that run at different points in the workflow:

Claude Code 提供了多个在流程不同阶段运行的钩子事件:

1,PreToolUse: Runs before tool calls (can block them)

PreToolUse:在工具调用之前运行(可以阻止它们)

2,PermissionRequest: Runs when a permission dialog is shown (can allow or deny)

权限请求:当显示权限对话框时运行(可以允许或拒绝)

3,PostToolUse: Runs after tool calls complete

工具调用完成:在工具调用完成后运行

4,UserPromptSubmit: Runs when the user submits a prompt, before Claude processes it

用户提交提示:在用户提交提示后、Claude 处理之前运行

5,Notification: Runs when Claude Code sends notifications

通知:当 Claude Code 发送通知时运行

6,Stop: Runs when Claude Code finishes responding

停止:当 Claude Code 完成响应时运行

7,SubagentStop: Runs when subagent tasks complete

子代理停止:当子代理任务完成时运行

8,PreCompact: Runs before Claude Code is about to run a compact operation

预压缩:当 Claude Code 即将运行压缩操作时运行

9,Setup: Runs when Claude Code is invoked with --init, --init-only, or --maintenance flags

设置:当 Claude Code 使用 --init 、 --init-only 或 --maintenance 标志被调用时运行

10,SessionStart: Runs when Claude Code starts a new session or resumes an existing session

会话开始:当 Claude Code 启动新会话或恢复现有会话时运行

11,SessionEnd: Runs when Claude Code session ends

会话结束:当 Claude Code 会话结束时运行

Each event receives different data and can control Claude's behavior in different ways.

每个事件接收不同的数据,并以不同方式控制 Claude 的行为。

二,Quickstart 快速入门

In this quickstart, you'll add a hook that logs the shell commands that Claude Code runs.

在本快速入门中,你将添加一个钩子,用于记录 Claude Code 运行的 Shell 命令。

Prerequisites 前提条件:

Install jq for JSON processing in the command line.

在命令行中安装 jq 以进行 JSON 处理。

Step 1: Open hooks configuration

第一步:打开钩子配置

Run the /hooks command and select the PreToolUse hook event.

运行 /hooks 命令并选择 PreToolUse 钩子事件。

PreToolUse hooks run before tool calls and can block them while providing Claude feedback on what to do differently.

PreToolUse 钩子在工具调用之前运行,并且可以在向Claude提供不同操作的反馈时阻止它们。

Step 2: Add a matcher

第二步:添加匹配器

Select + Add new matcher... to run your hook only on Bash tool calls.

选择 + Add new matcher... ,以便仅在 Bash 工具调用时运行您的钩子。

Type Bash for the matcher.

为匹配器输入 Bash 。

You can use * to match all tools.

可以使用 * 来匹配所有工具。

Step 3: Add the hook

步骤 3:添加钩子

Select + Add new hook... and enter this command:

选择 + Add new hook... 并输入此命令:

jq -r '"\(.tool_input.command) - \(.tool_input.description // "No description")"' >> ~/.claude/bash-command-log.txt

这行命令的作用是:把某些 JSON 数据里的命令和描述提取出来,格式化成 "命令 - 描述" 这种一行一记录的样子,然后追加写到用户家目录下的 ~/.claude/bash-command-log.txt 文件里。

jq:命令行 JSON 处理器

-r:raw output 模式

// 是 jq 的默认值运算符,如果.tool_input.description 不存在或者为 null,就使用后面的 fallback 字符串 "No description"

Step 4: Save your configuration

步骤 4:保存你的配置

For storage location, select User settings since you're logging to your home directory. This hook will then apply to all projects, not just your current project.

对于存储位置,选择 User settings ,因为你正在记录到你的主目录。这个钩子将适用于所有项目,而不仅仅是你的当前项目。

Then press Esc until you return to the REPL. Your hook is now registered.

然后按 Esc 直到你返回到 REPL。你的钩子现在已注册。

Step 5: Verify your hook

第 5 步:验证你的钩子

Run /hooks again or check ~/.claude/settings.json to see your configuration:

再次运行 /hooks 或检查 ~/.claude/settings.json 查看您的配置:

```bash

{

"hooks": {

"PreToolUse": [

{

"matcher": "Bash",

"hooks": [

{

"type": "command",

"command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"No description\")\"' >> ~/.claude/bash-command-log.txt"

}

]

}

]

}

}

```

Step 6: Test your hook

第六步:测试你的钩子

Ask Claude to run a simple command like ls and check your log file:

让 Claude 运行一个简单的命令,如 ls ,然后检查你的日志文件:

cat ~/.claude/bash-command-log.txt

You should see entries like:

你应该看到类似以下的条目:

ls - Lists files and directories

For a complete example implementation, see the bash command validator example in our public codebase.

完整的示例实现,请查看我们公共代码库中的 bash 命令验证者 示例:

https://github.com/anthropics/claude-code/blob/main/examples/hooks/bash_command_validator_example.py

三,More Examples 更多示例

3.1 Code Formatting Hook 代码格式化钩子

Automatically format TypeScript files after editing:

编辑后自动格式化 你的TypeScript 文件:

```bash

{

"hooks": {

"PostToolUse": [

{

"matcher": "Edit|Write",

"hooks": [

{

"type": "command",

"command": "jq -r '.tool_input.file_path' | { read file_path; if echo \"file_path\\" \| grep -q '\\\\.ts'; then npx prettier --write \"$file_path\"; fi; }"

}

]

}

]

}

}

```

从 JSON 输入中取出 file_path,如果文件路径以 .ts 结尾,就对它执行 prettier 格式化(--write 直接改写原文件)

\.ts 中的 是正则的"行尾"锚点

-q = quiet,只返回退出状态,不输出任何内容

3.2 Markdown Formatting Hook Markdown 格式钩子

Automatically fix missing language tags and formatting issues in markdown files:

自动修复 markdown 文件中缺失的语言标签和格式问题:

```bash

{

"hooks": {

"PostToolUse": [

{

"matcher": "Edit|Write",

"hooks": [

{

"type": "command",

"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/markdown_formatter.py"

}

]

}

]

}

}

```

Create .claude/hooks/markdown_formatter.py with this content:

创建 .claude/hooks/markdown_formatter.py 并包含以下内容:

```bash

#!/usr/bin/env python3

"""

Markdown formatter for Claude Code output.

Fixes missing language tags and spacing issues while preserving code content.# Markdown格式化器用于Claude代码输出。修复缺失的语言标签和间距问题,同时保留代码内容。

"""

import json

import sys

import re

import os

def detect_language(code):

"""Best-effort language detection from code content."""

s = code.strip()

JSON detection

if re.search(r'^\s*[{\[]', s):

try:

json.loads(s)

return 'json'

except:

pass

Python detection

if re.search(r'^\s*def\s+\w+\s*\(', s, re.M) or \

re.search(r'^\s*(import|from)\s+\w+', s, re.M):

return 'python'

JavaScript detection

if re.search(r'\b(function\s+\w+\s*\(|const\s+\w+\s*=)', s) or \

re.search(r'=>|console\.(log|error)', s):

return 'javascript'

Bash detection

if re.search(r'^#!.*\b(bash|sh)\b', s, re.M) or \

re.search(r'\b(if|then|fi|for|in|do|done)\b', s):

return 'bash'

SQL detection

if re.search(r'\b(SELECT|INSERT|UPDATE|DELETE|CREATE)\s+', s, re.I):

return 'sql'

return 'text'

def format_markdown(content):

"""Format markdown content with language detection."""

Fix unlabeled code fences

def add_lang_to_fence(match):

indent, info, body, closing = match.groups()

if not info.strip():

lang = detect_language(body)

return f"{indent}```{lang}\n{body}{closing}\n"

return match.group(0)

fence_pattern = r'(?ms)^([ \t]{0,3})```([^\n]*)\n(.*?)(\n\1```)\s*$'

content = re.sub(fence_pattern, add_lang_to_fence, content)

Fix excessive blank lines (only outside code fences)

content = re.sub(r'\n{3,}', '\n\n', content)

return content.rstrip() + '\n'

Main execution

try:

input_data = json.load(sys.stdin)

file_path = input_data.get('tool_input', {}).get('file_path', '')

if not file_path.endswith(('.md', '.mdx')):

sys.exit(0) # Not a markdown file

if os.path.exists(file_path):

with open(file_path, 'r', encoding='utf-8') as f:

content = f.read()

formatted = format_markdown(content)

if formatted != content:

with open(file_path, 'w', encoding='utf-8') as f:

f.write(formatted)

print(f"✓ Fixed markdown formatting in {file_path}")

except Exception as e:

print(f"Error formatting markdown: {e}", file=sys.stderr)

sys.exit(1)

```

Make the script executable:

使脚本可执行:

chmod +x .claude/hooks/markdown_formatter.py

This hook automatically:

这个钩子会自动执行:

Detects programming languages in unlabeled code blocks

检测无代码标签块中的编程语言

Adds appropriate language tags for syntax highlighting

为语法高亮添加适当的语言标签

Fixes excessive blank lines while preserving code content

修复过多的空行,同时保留代码内容

Only processes markdown files (.md, .mdx)

仅处理 markdown 文件( .md , .mdx )

3.3 Custom Notification Hook 自定义通知钩子

Get desktop notifications when Claude needs input:

当 Claude 需要输入时获取桌面通知:

```bash

{

"hooks": {

"Notification": [

{

"matcher": "",

"hooks": [

{

"type": "command",

"command": "notify-send 'Claude Code' 'Awaiting your input'"

}

]

}

]

}

}

```

3.4 File Protection Hook 文件保护钩子

Block edits to sensitive files:

阻止对敏感文件进行编辑:

```bash

{

"hooks": {

"PreToolUse": [

{

"matcher": "Edit|Write",

"hooks": [

{

"type": "command",

"command": "python3 -c \"import json, sys; data=json.load(sys.stdin); path=data.get('tool_input',{}).get('file_path',''); sys.exit(2 if any(p in path for p in ['.env', 'package-lock.json', '.git/']) else 0)\""

}

]

}

]

}

}

```

python3 -c "..." :用 python3 执行后面的一行内联代码

path = data.get('tool_input', {}).get('file_path', '') #从 JSON 里挖出 tool_input.file_path 这个字段

如果路径命中黑名单 → 退出码 2

小结

钩子是用户定义的 Shell 命令

跟踪和统计所有已执行的命令

相关推荐
名字不好奇2 小时前
词嵌入与向量化
人工智能
子午2 小时前
【2026计算机毕设~AI项目】鸟类识别系统~Python+深度学习+人工智能+图像识别+算法模型
图像处理·人工智能·python·深度学习
发哥来了2 小时前
《AI视频生成工具选型评测:多维度解析主流产品优劣势》
人工智能
DisonTangor2 小时前
美团龙猫开源LongCat-Flash-Lite
人工智能·语言模型·自然语言处理·开源·aigc
杨浦老苏2 小时前
Docker方式安装你的私人AI电脑助手Moltbot
人工智能·docker·ai·群晖
昨夜见军贴06162 小时前
功能决定效率:IACheck的AI审核在生产型检测报告中的实践观察
人工智能
传说故事2 小时前
【论文自动阅读】Goal Force: 教视频模型实现Physics-Conditioned Goals
人工智能·深度学习·视频生成
186******205313 小时前
项目开发基础知识:从概念到落地的全流程指南
大数据·人工智能
说私域3 小时前
AI智能名片商城小程序数据清洗的持续运营策略与实践研究
大数据·人工智能·小程序·流量运营·私域运营