Claude Code AfterCommand Hook

命令执行后触发机制详解

分类:Claude Code Hook 机制

核心主题:AfterCommand 钩子的功能、配置与实践

主要内容:概述、用途、配置方法、Hook 脚本格式、使用场景、代码示例、最佳实践、注意事项

关键词:Claude Code, AfterCommand, Hook, 结果检查, 资源清理, 日志记录, 自动化

一、概述

AfterCommand 是 Claude Code 提供的一种 Hook(钩子)机制,它在每条命令执行完成后自动触发。无论命令执行成功还是失败,AfterCommand Hook 都会被执行,这使得它成为实现命令后置处理逻辑的理想选择。

AfterCommand Hook 是 Claude Code 事件驱动架构的重要组成部分,与 BeforeCommand(命令执行前触发)形成完整的生命周期管理。通过 AfterCommand,开发者可以拦截命令执行结果,执行清理操作,记录日志,或在特定条件下触发通知。

核心特性

  • 自动触发: 每条命令执行完成后无需手动干预
  • 双向感知: 可获取命令执行的状态码、输出内容和执行时间
  • 非阻塞设计: 默认不阻塞后续命令的执行流程
  • 灵活脚本: 支持任何可执行脚本(Shell、Python、Node.js 等)
  • 上下文丰富: 可通过环境变量获取完整的命令上下文信息

触发时机

AfterCommand Hook 在 Claude Code 执行完一条命令后立即触发,触发顺序为:命令执行完成 → 收集退出码和输出 → 调用 AfterCommand 脚本 → 继续处理后续命令。整个过程对用户透明,不会影响命令本身的执行结果。

二、用途

AfterCommand Hook 的用途涵盖三个主要方面:结果检查、资源清理和日志记录。这些用途共同构成了 Claude Code 自动化工作流中不可或缺的闭环管理能力。

2.1 结果检查 (Result Checking)

AfterCommand 可自动检查命令的执行结果,验证命令是否按预期完成。通过获取退出码(exit code)和标准输出,可以判断命令执行状态。例如,编译命令返回非零退出码时,可以自动触发错误报告或重试机制。

检查维度

  • 退出码验证: 0 表示成功,非 0 表示失败
  • 输出内容分析: 检查输出中是否包含错误关键词
  • 超时检测: 命令执行是否超过预期时间
  • 资源消耗: 监控命令执行的内存和 CPU 使用

2.2 资源清理 (Cleanup)

命令执行后可能留下临时文件、锁文件、后台进程等资源。AfterCommand 可以自动清理这些资源,防止累积占用磁盘空间或导致后续命令执行异常。资源清理是维护开发环境健康的重要手段。

清理场景示例

  • 删除命令生成的临时目录和中间文件
  • 关闭命令启动的后台进程或数据库连接
  • 解锁命令执行期间占用的文件锁或端口
  • 还原命令修改的环境变量配置

2.3 日志记录 (Logging)

AfterCommand 可以将每条命令的执行信息持久化到日志文件中,形成完整的命令执行历史。这些日志可用于审计、调试和性能分析。日志记录的内容可以包括命令文本、执行时间、退出码、输出摘要等。

日志记录的价值

  • 审计追踪: 记录谁在什么时候执行了什么命令
  • 调试分析: 通过历史日志追踪问题根源
  • 性能监控: 统计命令执行耗时,识别性能瓶颈
  • 安全审计: 检测异常命令执行模式

三、配置方法

AfterCommand Hook 的配置通过 Claude Code 的配置文件 settings.jsonsettings.local.json 完成。配置文件位于项目根目录的 .claude/ 文件夹中,或全局配置目录下。

{ "hooks": { "AfterCommand": "bash .claude/hooks/after-command.sh" } }

配置项 "hooks.AfterCommand" 的值是一个字符串,指向可执行脚本的路径。路径可以是绝对路径,也可以是相对于项目根目录的路径。Claude Code 在每条命令执行完成后,会调用该路径指向的脚本。

配置文件层级

配置文件 位置 优先级 说明
settings.local.json .claude/settings.local.json 最高 项目本地配置,不纳入版本控制
settings.json .claude/settings.json 项目共享配置,纳入版本控制
全局配置 ~/.claude/settings.json 最低 用户级全局配置

配置建议

建议在 settings.local.json 中配置 AfterCommand Hook,避免将可能包含敏感信息或环境特定路径的配置提交到版本控制中。团队共享的 Hook 脚本可放在 settings.json 中,并确保脚本路径对所有成员有效。

四、Hook 脚本格式

AfterCommand Hook 脚本是一个可执行文件,支持 Shell、Python、Node.js、PowerShell 等任何语言编写的脚本。脚本通过环境变量获取命令执行的上下文信息。

环境变量

Claude Code 在执行 AfterCommand 脚本时,会设置以下环境变量:

环境变量 说明
CLAUDE_COMMAND 被执行的原始命令文本
CLAUDE_EXIT_CODE 命令的退出码(0 表示成功)
CLAUDE_STDOUT 命令的标准输出内容
CLAUDE_STDERR 命令的错误输出内容
CLAUDE_CWD 命令执行时的工作目录
CLAUDE_TIMESTAMP 命令执行的 Unix 时间戳
CLAUDE_DURATION 命令执行耗时(毫秒)

基本脚本结构

一个典型的 AfterCommand Shell 脚本结构如下:

#!/bin/bash # .claude/hooks/after-command.sh # AfterCommand Hook 脚本 - 用于日志记录和结果检查 echo "[$(date)] Command executed: $CLAUDE_COMMAND" >> /tmp/claude-commands.log echo "[$(date)] Exit code: $CLAUDE_EXIT_CODE" >> /tmp/claude-commands.log echo "[$(date)] Duration: ${CLAUDE_DURATION}ms" >> /tmp/claude-commands.log echo "---" >> /tmp/claude-commands.log if [ "$CLAUDE_EXIT_CODE" -ne 0 ]; then echo "[WARN] Command failed: $CLAUDE_COMMAND" >> /tmp/claude-errors.log fi

多语言支持

AfterCommand 脚本不限于 Shell,可以使用任何可执行语言编写。以下是 Python 版本的示例:

#!/usr/bin/env python3 # .claude/hooks/after-command.py import os import json import datetime command = os.environ.get('CLAUDE_COMMAND', '') exit_code = int(os.environ.get('CLAUDE_EXIT_CODE', '-1')) duration = os.environ.get('CLAUDE_DURATION', '0') log_entry = { 'timestamp': datetime.datetime.now().isoformat(), 'command': command, 'exit_code': exit_code, 'duration_ms': duration } with open('/tmp/claude-audit.jsonl', 'a') as f: f.write(json.dumps(log_entry) + '\n') if exit_code != 0: print(f"[HOOK] Command failed: {command[:80]}")

脚本权限要求

配置的 Hook 脚本必须具有可执行权限。在 Linux/macOS 上使用 chmod +x script.sh 设置执行权限。在 Windows 上,确保文件关联正确或使用 bash 作为脚本解释器前缀。

五、使用场景

AfterCommand Hook 在多种实际开发场景中发挥重要作用,以下是最常见的三类应用场景。

5.1 命令结果验证 (Command Result Validation)

在持续开发过程中,AfterCommand 可以自动验证命令执行结果,确保每次操作都符合预期。例如,编译命令执行后自动检查产物完整性,测试命令执行后自动解析测试报告,或部署命令执行后验证服务是否正常启动。

验证策略

  • 退出码检查: 快速判断命令是否成功执行
  • 输出模式匹配: 在输出中搜索特定关键词(如 "ERROR"、"FAIL"、"success")
  • 产物验证: 检查命令预期的输出文件是否生成且内容正确
  • 服务健康检查: 部署后验证目标服务是否响应正常

5.2 通知推送 (Notification)

当命令执行时间较长或结果需要关注时,AfterCommand 可以触发通知机制。典型场景包括:长时间运行的任务完成通知、命令失败告警、CI/CD 流水线状态更新等。

#!/bin/bash # 失败命令通知示例 if [ "$CLAUDE_EXIT_CODE" -ne 0 ]; then # 发送桌面通知 notify-send "Claude Code: Command Failed" \ "Exit code: $CLAUDE_EXIT_CODE\nCommand: $CLAUDE_COMMAND" # 发送 Slack 通知(可选) # curl -X POST -H 'Content-type: application/json' \ # --data "{\"text\":\"Command failed: $CLAUDE_COMMAND\"}" \ # https://hooks.slack.com/services/YOUR/WEBHOOK/URL fi

5.3 资源清理 (Resource Cleanup)

开发过程中经常会产生临时资源,AfterCommand 可以确保这些资源被及时清理,避免环境污染。这对于长时间运行的开发会话尤其重要。

#!/bin/bash # 资源清理示例 # 清理临时目录 if [ -d "/tmp/claude-temp-$CLAUDE_TIMESTAMP" ]; then rm -rf "/tmp/claude-temp-$CLAUDE_TIMESTAMP" echo "[HOOK] Cleaned up temporary directory" fi # 清理 Docker 容器(由当前命令创建的) docker ps -q --filter "label=claude-session=$CLAUDE_TIMESTAMP" | \ xargs -r docker rm -f # 回收磁盘空间 if [ "$(df / | tail -1 | awk '{print $5}' | tr -d '%')" -gt 90 ]; then echo "[HOOK] Disk usage exceeds 90%, triggering cleanup" docker system prune -f --volumes 2>/dev/null fi

其他场景

六、代码示例

本节提供完整的 AfterCommand Hook 脚本示例,涵盖不同编程语言和功能组合,可直接用于实际项目。

6.1 综合日志记录器 (Shell)

一个功能完善的日志记录脚本,将命令执行信息记录到结构化的 JSON 日志文件中:

#!/bin/bash # .claude/hooks/after-command-logger.sh # 功能:记录命令执行日志到 JSON 文件 LOGFILE="$HOME/.claude/logs/commands-$(date +%Y%m).jsonl" mkdir -p "$(dirname "$LOGFILE")" # 截断输出,避免日志文件过大 STDOUT_TRUNC=$(echo "$CLAUDE_STDOUT" | head -c 500) STDERR_TRUNC=$(echo "$CLAUDE_STDERR" | head -c 500) cat >> "$LOGFILE" <<- EOFLOG {"ts":$(date +%s),"cmd":"$(echo "$CLAUDE_COMMAND" | head -c 200)","exit":$CLAUDE_EXIT_CODE,"dur":${CLAUDE_DURATION:-0},"cwd":"$CLAUDE_CWD"} EOFLOG # 失败命令单独保存详细信息 if [ "$CLAUDE_EXIT_CODE" -ne 0 ]; then ERRORLOG="$HOME/.claude/logs/errors-$(date +%Y%m).log" { echo "=== [$(date)] ===" echo "Command: $CLAUDE_COMMAND" echo "Exit: $CLAUDE_EXIT_CODE" echo "stderr: $STDERR_TRUNC" echo } >> "$ERRORLOG" fi

6.2 环境状态检查 (Python)

一个 Python 脚本,在每条命令执行后检查环境状态并报告异常:

#!/usr/bin/env python3 """AfterCommand Hook: 环境状态检查器""" import os import psutil import json THRESHOLDS = { 'cpu_percent': 80.0, 'memory_percent': 85.0, 'disk_percent': 90.0, } alerts = [] if psutil.cpu_percent(interval=0.1) > THRESHOLDS['cpu_percent']: alerts.append('High CPU usage') if psutil.virtual_memory().percent > THRESHOLDS['memory_percent']: alerts.append('High memory usage') if alerts: report = { 'timestamp': os.environ.get('CLAUDE_TIMESTAMP'), 'command': os.environ.get('CLAUDE_COMMAND', '')[:100], 'alerts': alerts } print(f"[HOOK] Environment alert: {json.dumps(report)}")

6.3 通知与备份 (Node.js)

一个 Node.js 脚本,在重要命令执行后发送通知并备份关键文件:

#!/usr/bin/env node // .claude/hooks/after-command-notify.js const fs = require('fs'); const path = require('path'); const cmd = process.env.CLAUDE_COMMAND || ''; const exitCode = parseInt(process.env.CLAUDE_EXIT_CODE || '0'); // 检测文件修改类命令,自动创建备份 const modifyPatterns = [/^git\s+add/, /^git\s+commit/, /^rm\s+/, /^mv\s+/]; const isModification = modifyPatterns.some(p => p.test(cmd)); if (isModification && exitCode === 0) { const backupDir = path.join(process.env.HOME, '.claude/backups'); fs.mkdirSync(backupDir, { recursive: true }); fs.writeFileSync( path.join(backupDir, `snapshot-${Date.now()}.json`), JSON.stringify({ cmd, time: new Date().toISOString() }) ); console.log(`[HOOK] Backup snapshot created`); } // 失败命令告警 if (exitCode !== 0) { console.error(`[HOOK] Command failed (exit ${exitCode}): ${cmd.slice(0, 80)}`); }

脚本调试技巧

在开发 Hook 脚本时,可以使用 echo "[HOOK] debug: ..." 输出调试信息。这些输出会显示在 Claude Code 的界面中。如果脚本执行出错,请检查脚本的可执行权限和环境变量是否正确传递。

七、最佳实践

合理使用 AfterCommand Hook 可以大幅提升开发效率和自动化水平。以下是在实际项目中总结的最佳实践。

7.1 保持脚本轻量

AfterCommand 脚本在每条命令后都会执行,因此必须保持轻量和高效。避免在脚本中执行耗时的操作(如大型文件扫描、远程 API 调用等),这些操作会显著降低交互式开发的流畅度。建议将耗时任务异步化或仅在特定条件下执行。

性能准则

  • 脚本执行时间控制在 100ms 以内
  • 避免同步网络请求和数据库查询
  • 使用文件追加而非文件覆盖操作
  • 限制日志输出的大小,必要时进行轮转

7.2 错误隔离

Hook 脚本的错误不应影响主流程。在脚本中使用 set -e 时要谨慎,确保脚本错误不会导致 Claude Code 主进程异常。建议在脚本入口处使用 set +e 或在关键命令后添加 || true

#!/bin/bash # 错误隔离示例 set +e # 防止脚本错误中断主流程 # 即使 cleanup 失败,也不影响 Claude Code cleanup_temp_files || true # 记录日志失败不应导致告警 log_command 2>/dev/null || true

7.3 环境变量安全性

AfterCommand 脚本可以访问所有环境变量,包括可能包含敏感信息的变量。不要在日志中记录完整的命令文本(可能包含密码或 API 密钥),也不要将环境变量值输出到共享日志中。对输出内容进行脱敏处理。

# 脱敏日志记录示例 sanitize() { local input="$1" # 替换常见的敏感信息模式 input=$(echo "$input" | sed -E 's/(password|passwd|secret|token|api_key)=[^ ]+/\1=****/gi') input=$(echo "$input" | sed -E 's/(Authorization:\s*Bearer\s+)[^ ]+/\1****/gi') echo "$input" } safe_cmd=$(sanitize "$CLAUDE_COMMAND") echo "[LOG] $safe_cmd" >> /var/log/claude/commands.log

7.4 条件触发

不是每条命令后都需要执行完整的 Hook 逻辑。根据命令类型、退出码或执行时间有选择地执行,可以大幅提升性能。

#!/bin/bash # 条件触发示例 # 仅在命令失败时执行通知 if [ "$CLAUDE_EXIT_CODE" -eq 0 ]; then exit 0 fi # 仅对耗时超过 10 秒的命令进行详细记录 if [ "${CLAUDE_DURATION:-0}" -lt 10000 ]; then log_basic_info else log_detailed_info send_notification fi

7.5 版本控制策略

Hook 脚本和配置文件都建议纳入 Git 版本控制。在项目中创建 .claude/hooks/ 目录,将常用 Hook 脚本放在该目录下。同时将 settings.local.json 添加到 .gitignore 中,避免个人配置被提交。

推荐目录结构

.claude/ settings.json settings.local.json hooks/ after-command.sh before-command.sh after-command-notify.js

将通用的 Hook 脚本放在 hooks/ 目录下,团队成员共享。个人定制的脚本路径在 settings.local.json 中配置。

八、注意事项

在使用 AfterCommand Hook 时,需要注意以下关键事项,避免产生意外行为。

重要提醒

  • 性能影响: Hook 脚本的执行时间会累加到命令的总执行时间中,应严格控制脚本执行效率
  • 递归风险: 避免在 Hook 脚本中再次触发 Claude Code 命令,否则可能造成无限递归
  • 跨平台兼容: Windows 和 Unix 系统的路径分隔符、换行符和环境变量语法不同,需分别处理
  • 输出污染: Hook 脚本的标准输出会显示在 Claude Code 的界面中,注意不要输出无关信息
  • 权限管理: Hook 脚本具有当前用户的完整权限,编写时需注意安全性和最小权限原则

常见陷阱

陷阱 后果 解决方案
脚本中修改了工作目录 后续命令在错误目录执行 使用子 Shell ( ... ) 或显式还原目录
日志文件无限增长 磁盘空间耗尽 使用 logrotate 或按大小轮转日志
环境变量含特殊字符 脚本解析错误或注入攻击 始终对变量值进行引用和转义
脚本路径错误 Hook 静默失败 使用绝对路径或验证路径存在性

调试方法

如果 Hook 脚本未按预期执行,首先检查配置文件路径是否正确,然后确认脚本具有可执行权限。可以通过在脚本顶部添加 set -x(Shell)或在脚本中输出 [HOOK] 前缀的调试信息来跟踪执行过程。查看 Claude Code 的输出面板,Hook 脚本的标准输出会显示在其中。

九、核心要点总结