首页
/ ECC 的 Go 钩子:为 Claude Code / Cursor 配置 PostToolUse 自动格式化与静态检查

ECC 的 Go 钩子:为 Claude Code / Cursor 配置 PostToolUse 自动格式化与静态检查

2026-09-06 09:37:24作者:邬祺芯Juliet

本文以 ECC 仓库中的 Cursor 规则文件 .cursor/rules/golang-hooks.md 为主体,讲解它如何用 Go 专属内容扩展通用钩子规则:哪些 Go 工具应挂到 PostToolUse 钩子上、在 ~/.claude/settings.json 中如何配置,以及这些“编辑后自动检查”的语义在 ECC 自身代码中(质量门钩子、PostToolUse 分发器)是如何落地的。读完后你可以为一套 Claude Code/Cursor 工作流设计自己的 Go 语言 PostToolUse 钩子,并理解 ECC 钩子体系中“同步/异步分发、strict/fix 开关”的实现方式。

一、文档定位:一条按 glob 触发的 Cursor 规则

.cursor/rules/golang-hooks.md 是一份 Cursor Rules 格式的 Markdown 规则文件,头部 frontmatter 声明了它的触发条件:

---
description: "Go hooks extending common rules"
globs: ["**/*.go", "**/go.mod", "**/go.sum"]
alwaysApply: false
---
  • globs 匹配 **/*.go**/go.mod**/go.sum:只有当会话正在处理 Go 源码或模块文件时,这条规则才参与上下文注入;
  • alwaysApply: false 表示它不是常驻规则,避免在纯 JS/TS 会话中白白消耗上下文。

文件正文开宗明义:

This file extends the common hooks rule with Go specific content.

也就是说,它不是一个孤立的规则,而是对 ECC 通用钩子规则的分层扩展。对应的通用规则在仓库中有两处等价内容:Cursor 侧的 common-hooks.md 和规则源文件 rules/common/hooks.md;而 golang-hooks.md 的原始版本即 rules/golang/hooks.md,两者正文一致(后者 frontmatter 用 paths 字段表达同样的 **/*.go**/go.mod**/go.sum 匹配)。仓库中同一模式还扩展到 Kotlin、PHP、Python、Swift、TypeScript 等语言,形成 common-hooks.md + <lang>-hooks.md 的分层规则体系。

二、通用钩子规则回顾:三类钩子与权限约束

Go 规则所“扩展”的 common hooks 规则定义了 ECC 钩子体系的基础概念,理解它是理解 Go 钩子语义的前提:

钩子类型(Hook Types)

钩子类型 触发时机 典型用途
PreToolUse 工具执行前 参数校验、阻止危险操作
PostToolUse 工具执行后 自动格式化、检查(Go 规则正是扩展这一类)
Stop 会话响应结束时 最终校验、批量收尾工作

自动接受权限(Auto-Accept Permissions)约束:仅对可信、边界清晰的任务开启;探索性工作应关闭;永远不要使用 dangerously-skip-permissions 标志,而应在 ~/.claude.json 中通过 allowedTools 精确授权。这些约束同样适用于配置 Go 钩子时的环境——钩子只是自动化检查,权限边界仍需保守。

三、Go 专属的三个 PostToolUse 钩子

文档给出的核心内容很明确:在 ~/.claude/settings.json 中为 Go 项目配置以下三个 PostToolUse 钩子:

钩子 工具 作用
gofmt / goimports gofmt / goimports 编辑 .go 文件后自动格式化,并保持 import 分组与去重
go vet go vet 编辑 .go 文件后运行静态分析,发现可疑构造(printf 参数不匹配、锁误用、未生效的 case 等)
staticcheck staticcheck 被修改的包运行扩展静态检查,覆盖比 go vet 更宽的规则集

三者的分工是一个递进关系:gofmt 管“格式”,go vet 管“内置静态分析”,staticcheck 管“更深层的扩展检查”。配置位置统一在用户级 ~/.claude/settings.jsonhooks 字段下。

参考 ECC 仓库 hooks/hooks.jsonPostToolUse 条目的实际结构(matcher + hooks[].type/command/timeout,结构可对照 schemas/hooks.schema.json 校验),一个与上表对应的参考写法如下:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "gofmt -w \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ],
        "description": "Auto-format .go files after edit"
      },
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "go vet ./...",
            "timeout": 30
          }
        ],
        "description": "Run go vet after editing .go files"
      },
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "staticcheck ./...",
            "timeout": 45,
            "async": true
          }
        ],
        "description": "Run staticcheck on modified packages"
      }
    ]
  }
}

要点说明:

  • matcher 匹配的是工具名,只对写文件类工具(Edit/Write/MultiEdit)触发,读文件操作不会触发格式化;
  • 较慢的检查(staticcheck 扫描整包依赖)建议标 async: true,不阻塞 Agent 主循环——ECC 自身的异步 PostToolUse 分发器超时即设为 45 秒(见下文);
  • 命令中的 $CLAUDE_FILE_PATH 一类占位符与钩子接收的 tool_input.file_path 字段对应,实际字段取值以你的 Claude Code 版本钩子输入为准;仓库内实现(下一节)直接解析 stdin JSON 的 tool_input.file_path

四、仓库实现证据:quality-gate.js 中的 Go 质量门

文档中“编辑 .go 文件后自动格式化”这条建议,在 ECC 自身的钩子脚本里就有可运行的参照实现——scripts/hooks/quality-gate.js(质量门钩子,在文件编辑后运行轻量质量检查)。其 Go 分支行为如下(quality-gate.js#L106-L121):

  • 修复模式ECC_QUALITY_GATE_FIX=true):执行 gofmt -w <file>,直接改写文件,实现“编辑后自动格式化”;
  • 严格模式ECC_QUALITY_GATE_STRICT=true,且非 fix):执行 gofmt -l <file>,该命令只列出格式不符的文件名而不改写;若输出非空,说明文件不符合 gofmt 规范,钩子会向 stderr 记录 [QualityGate] gofmt check failed for <file>
  • 降级策略:两个环境变量都未设置时该分支直接返回,钩子保持 no-op。文件头注释(quality-gate.js#L2-L13)也写明:语言或工具链不可用时回退为 no-op,避免钩子把环境问题变成会话错误。

入口逻辑(quality-gate.js#L140-L149)从 stdin 读取钩子 JSON,取 tool_input.file_path 定位被编辑的单个文件,并按扩展名分派:.go 走 gofmt,.py 走 ruff,JS/TS 则根据项目检测到的格式化器(Biome/Prettier)处理,检测不到格式化器时跳过。每次子进程调用带有 15 秒超时(quality-gate.js#L33-L40),保证钩子不会卡死 Agent。这正是文档建议的第一项(gofmt 自动格式化)在生产钩子中的真实形态:单文件、快超时、可开关、失败可静默。

五、这些钩子在 hooks.json 中如何被分发

~/.claude/settings.json 写钩子只是“声明”,Claude Code 按 hooks/hooks.json 这类清单把钩子命令真正跑起来。ECC 的 PostToolUse 段采用分发器(dispatcher)模式

  • post:dispatcher:synchooks.json#L136-L148):matcher 为 .*,同步执行所有 PostToolUse 钩子,超时 30 秒,通过 ECC_POSTTOOLUSE_PASSTHROUGH=1 保持逐钩子的控制语义;
  • post:dispatcher:asynchooks.json#L149-L161):同样 matcher .*,但 "async": true、超时 45 秒,用于后台不阻塞的检查类钩子。

对 Go 钩子的配置建议是:把 gofmt/goimports 这类毫秒级操作放在同步路径,把 go vet/staticcheck 这类需要编译依赖的检查放在异步路径(或显式设置较大 timeout),与 ECC 分发器的 30s/45s 超时设计对齐。此外,同文件中的 pre:config-protection 钩子(hooks.json#L63-L74)会阻止 Agent 修改 linter/formatter 的配置文件——即“改代码而不是放松检查配置”,这条治理原则对 Go 场景同样成立:钩子报错时应修复代码,而不是在钩子命令里加 || true 或调低 staticcheck 级别。

六、与 Go 评审流程的呼应

PostToolUse 钩子解决“每次编辑后立刻可见”的反馈,而仓库中更完整的 Go 质量闭环由评审侧承担,二者共用同一套工具:

因此推荐的分层是:PostToolUse 钩子(本文主题)做行级/包级即时反馈/go-review提交前的完整评审,Stop 钩子做响应结束时的收尾——这与 common hooks 规则定义的三类钩子一一对应。

七、适用前提与限制

  • 钩子命令依赖本机已安装 Go 工具链(gofmt 随 Go 发行版提供,go vet 随模块可用,staticcheck 需单独安装);工具缺失时 ECC 的质量门实现会 no-op,但你自己手写进 settings.json 的钩子命令会直接报错,建议为命令加上容错或先检查 command -v staticcheck
  • go vetstaticcheck 都需要能解析包依赖,在 go.mod 未就绪(依赖未下载)时可能失败,属于预期行为;
  • 本文配置基于 ~/.claude/settings.json(用户级);~/.claude 与项目根目录下的 settings 文件同时存在时的合并优先级,以你所用 Claude Code 版本的官方文档为准;
  • 规则文件 .cursor/rules/golang-hooks.md 面向 Cursor 场景,但其 PostToolUse 语义与 Claude Code 钩子一致,两者可按同一套 matcher + command 结构配置。
登录后查看全文
热门项目推荐
相关项目推荐