Codex CLI 完全指南:第六章·生命周期 Hooks

Hooks 是 Codex 的事件驱动扩展机制。在 AI 执行的各个生命周期节点,你可以注入自定义脚本——验证命令安全性、记录日志、触发通知、执行自动化检查。

生命周期事件

Codex 暴露了以下生命周期节点:

| 事件 | 触发时机 | 用途 |
|------|---------|------|
| pre_exec | 命令执行前 | 安全校验、环境检查 |
| post_exec | 命令执行后 | 日志记录、结果通知 |
| pre_edit | 文件修改前 | 备份文件、格式检查 |
| post_edit | 文件修改后 | 触发 lint、格式化 |
| pre_agent | Agent 启动前 | 初始化环境变量 |
| post_agent | Agent 结束后 | 清理临时文件 |
| on_error | 发生错误时 | 错误上报、回滚 |

配置文件中的 Hooks

hooks:
  pre_exec:
    - echo "[$(date)] 即将执行: {{.command}}" >> .codex/history.log
    - bash .codex/safety-check.sh "{{.command}}"

  post_exec:
    - echo "[$(date)] 执行完成: exit={{.exit_code}}" >> .codex/history.log

  pre_edit:
    - cp "{{.file}}" "{{.file}}.codex-backup"

  post_edit:
    - npx prettier --write "{{.file}}"

  on_error:
    - echo "错误: {{.error}}" >> .codex/errors.log

模板变量

Hooks 中使用双花括号传递上下文变量:

| 变量 | 说明 | 适用事件 |
|------|------|----------|
| {{.command}} | 即将执行的命令 | pre_exec, post_exec |
| {{.exit_code}} | 命令退出码 | post_exec |
| {{.file}} | 被修改的文件路径 | pre_edit, post_edit |
| {{.error}} | 错误信息 | on_error |
| {{.agent_id}} | 当前 Agent ID | pre_agent, post_agent |
| {{.model}} | 当前使用的模型名称 | 全部 |
| {{.timestamp}} | Unix 时间戳 | 全部 |

实战案例

安全审计 Hooks

hooks:
  pre_exec:
    - |
      DANGEROUS_PATTERNS=("rm -rf /" "sudo " "chmod 777" "> /dev/sda" "DROP TABLE" "shutdown")
      for pattern in "${DANGEROUS_PATTERNS[@]}"; do
        if [[ "{{.command}}" == *"$pattern"* ]]; then
          echo "⛔ 危险命令被阻止: {{.command}}"
          exit 1
        fi
      done

自动备份修改文件

hooks:
  pre_edit:
    - |
      BACKUP_DIR=".codex/backups/$(date +%Y%m%d)"
      mkdir -p "$BACKUP_DIR"
      if [ -f "{{.file}}" ]; then
        cp "{{.file}}" "$BACKUP_DIR/$(basename {{.file}})-{{.timestamp}}"
        echo "📦 已备份: {{.file}}"
      fi

代码质量自动检查

hooks:
  post_edit:
    - |
      FILE="{{.file}}"

      # TypeScript / JavaScript
      if [[ "$FILE" == *.ts ]] || [[ "$FILE" == *.tsx ]]; then
        npx eslint "$FILE" --fix && echo "✅ ESLint: $FILE"
      fi

      # Python
      if [[ "$FILE" == *.py ]]; then
        black "$FILE" && ruff check "$FILE" --fix && echo "✅ Format: $FILE"
      fi

      # Go
      if [[ "$FILE" == *.go ]]; then
        gofmt -w "$FILE" && echo "✅ gofmt: $FILE"
      fi

运行测试

hooks:
  post_edit:
    - |
      FILE="{{.file}}"
      if [[ "$FILE" == *.test.* ]] || [[ "$FILE" == *__tests__* ]]; then
        echo "🧪 已修改测试文件,自动运行..."
        npm test -- "$FILE"
      fi

企业微信/Slack 通知

hooks:
  post_exec:
    - |
      curl -X POST https://hooks.slack.com/services/XXX \
        -H "Content-Type: application/json" \
        -d "{\"text\": \"Codex 执行完成: {{.command}} (exit={{.exit_code}})\"}"

Git 自动提交

hooks:
  post_edit:
    - |
      FILE="{{.file}}"
      if git diff --quiet "$FILE"; then
        echo "无变更: $FILE"
      else
        git add "$FILE"
        echo "📝 已暂存: $FILE"
      fi

条件 Hooks

有时你只想在特定条件下触发 Hook:

hooks:
  pre_exec:
    - name: "安全审核"
      when: "execution.policy != 'always'"
      run: bash .codex/safety-check.sh "{{.command}}"

    - name: "debug 日志"
      when: "env.CODEX_DEBUG == 'true'"
      run: echo "[DEBUG] {{.command}}" >> debug.log

Hooks 脚本的退出码

  • 退出码 0:正常通过,继续执行
  • 退出码 非0(pre_* hooks):阻止后续操作执行
  • 退出码 非0(post_* hooks):记录警告但不影响后续

例如:

#!/bin/bash
# .codex/pre-exec-check.sh

if [[ "$1" == *"rm"* ]] && [[ "$1" != *"rm -rf node_modules"* ]]; then
    echo "⛔ rm 命令被阻止(除非删除 node_modules)"
    exit 1  # 阻止执行
fi

exit 0  # 放行

Hooks 的调试

在 codex.yaml 中开启详细日志:

hooks:
  debug: true             # 显示每个 Hook 的执行详情
  continue_on_error: false # Hook 失败时是否继续

最佳实践

将复杂 Hook 放在独立脚本文件hooks/pre-exec.sh 比 yaml 中的多行字符串好维护

**pre_* hooks 做校验**,post_* hooks 做收尾

不要同步调用慢速外部服务(如短信网关)——会阻塞 Codex

使用 .codex/ 目录统一管理 Hook 脚本,并加入 .gitignore

Hook 脚本本身加入版本控制,让团队成员共享相同的行为规则

小结

Hooks 让 Codex 从工具升级为平台。通过生命周期节点,你可以将团队的编码规范、安全策略和质量标准硬编码为自动执行的检查规则。AI 生成代码 + Hooks 自动质检 + 沙箱安全隔离——这三者结合,构建了一个既高效又安全的 AI 编程工作台。