ECC 事件驱动 Hook 体系完全指南从安装、配置到自定义开发【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECCECCEverything Claude Code的 Hook 体系是一套事件驱动的自动化机制它在 Claude Code 等 Agent 工具执行的前后自动触发用于强制执行代码质量、提前发现错误、自动化重复性检查。本文以仓库中 docs/ja-JP/hooks/README.md 为核心骨架结合 hooks/hooks.json 的完整 Hook 图谱与 scripts/hooks/ 的源码实现系统讲解 ECC Hook 的工作原理、安装方式、内置 Hook 清单、运行期控制、自定义 Hook 开发以及跨平台注意事项帮助你在实际项目中把 Hook 用起来、改明白、写得出。Hook 的工作原理Hook 的本质是事件驱动自动化它们在 Claude Code 的工具执行前后触发用来强制代码质量、尽早检测错误、自动化重复检查。ECC 以插件形式为 Claude Code、Codex、Opencode、Cursor 等多款 Agent 工具提供统一的 Hook 能力核心执行流程如下用户请求 → Claude 选择工具 → PreToolUse Hook 执行 → 工具执行 → PostToolUse Hook 执行围绕这一主流程ECC 的 Hook 覆盖了五个事件边界PreToolUse在工具执行前运行。可以阻止退出码 2或警告输出到 stderr不阻止。PostToolUse在工具完成之后运行。可以分析输出但不能阻止工具执行。Stop在 Claude 每次响应结束后运行。SessionStart / SessionEnd在会话的生命周期边界运行。PreCompact在上下文压缩context compaction之前运行适合保存状态。在仓库中这些事件对应的 Hook 声明集中在 hooks/hooks.json而内存持久化生命周期的稳定契约单独沉淀在 hooks/memory-persistence/ 目录中。执行调度与分发器从源码结构看ECC 的 Hook 并非每个事件裸跑一条命令而是通过分发器集中调度Bash 类工具执行前的多项检查质量、tmux、git push、GateGuard统一由pre:bash:dispatcher入口合并实际逻辑在 scripts/hooks/bash-hook-dispatcher.js 与 scripts/hooks/pre-bash-dispatcher.js 中PostToolUse 事件拆分为同步post:dispatcher:sync超时 30 秒与后台post:dispatcher:async超时 45 秒两条通道统一由 scripts/hooks/posttooluse-dispatcher.js 调度实现一次进程跑完该事件的所有 Hook同时保留每个 Hook 的独立开关控制每个具体 Hook 是否执行由 scripts/hooks/run-with-flags.js 依据 Hook 配置文件profile与开关统一裁决规则见 scripts/lib/hook-flags.js。这种声明式配置 运行时裁决的架构是 ECC 能够同时支撑多款 Agent 工具、并支持精细化开关的关键。安装 HookClaude Code 手动安装仓库中签入的hooks.json是面向插件/仓库的声明文件不要把它的原始内容直接粘贴到~/.claude/settings.json也不要直接复制到~/.claude/hooks/hooks.json。签入文件假设它要么通过 ECC 安装器安装要么作为插件被加载只有安装器会把 Hook 命令中的路径重写为真实可用的 Claude 根目录。正确的安装方式是使用 ECC 安装器指定hooks-runtime模块bash ./install.sh --target claude --modules hooks-runtimePowerShell 用户pwsh -File .\install.ps1 --target claude --modules hooks-runtime安装完成后解析后的 Hook 会写入~/.claude/hooks/hooks.json。在 Windows 上Claude 配置根目录是%USERPROFILE%\.claude。安装器为何必须重写路径从 hooks/hooks.json 可以看到每条 Hook 命令的开头都内嵌了一段插件根目录解析逻辑优先读取CLAUDE_PLUGIN_ROOT环境变量否则在~/.claude/plugins下按ecc、eccecc、marketplaces/ecc、everything-claude-code等候选目录探测找到包含scripts/lib/resolve-ecc-root.js的根目录。这段逻辑在插件场景下能正确定位但手工粘贴到 settings 时容易出现路径错位因此官方明确推荐走安装器。ECC 内置 Hook 清单PreToolUse Hook工具执行前Hook匹配器行为退出码开发服务器拦截器Bash拦截在 tmux 之外运行npm run dev等开发服务器 — 确保日志可访问2阻止Tmux 提示器Bash对长耗时命令npm test、cargo build、docker提示使用 tmux0警告Git 推送提示器Bash在git push之前提示审查变更0警告提交前质量检查Bash在git commit前执行质量检查对暂存文件做 lint、校验-m/--message提供的提交信息格式、检测 console.log/debugger/密钥2阻止关键项 / 0警告文档文件警告Write对非标准.md/.txt文件给出警告README、CLAUDE、CONTRIBUTING、CHANGELOG、LICENSE、SKILL、docs/、skills/ 为允许项跨平台路径处理0警告战略压缩建议Edit\|Write在逻辑间隔约每 50 次工具调用建议手动/compact0警告上述清单中的提交质量检查对应 scripts/hooks/pre-bash-commit-quality.js开发服务器拦截对应 scripts/hooks/pre-bash-dev-server-block.jsgit push 提示对应 scripts/hooks/pre-bash-git-push-reminder.jstmux 提示对应 scripts/hooks/pre-bash-tmux-reminder.js文档文件警告对应 scripts/hooks/doc-file-warning.js压缩建议对应 scripts/hooks/suggest-compact.js。值得关注的是hooks/hooks.json 中的实际 PreToolUse 图谱还包含若干未出现在文档表格中的安全与治理类 Hook配置保护pre:config-protection阻止修改 linter/formatter 配置文件引导 Agent 修代码而不是削弱配置超时 5 秒、MCP 健康检查pre:mcp-health-check在 MCP 工具执行前检查服务器健康并阻止异常调用、事实强制门pre:edit-write:gateguard-fact-force对每个文件首次 Edit/Write/MultiEdit 强制先调研导入者、数据 schema 与用户指令超时 5 秒、治理捕获pre:governance-capture通过ECC_GOVERNANCE_CAPTURE1启用记录密钥、策略违规与审批请求以及持续学习观察器pre:observe:continuous-learning异步记录工具调用供持续学习使用。PostToolUse Hook工具执行后Hook匹配器行为PR 日志器Bash在gh pr create之后记录 PR URL 与审查命令构建解析Bash在构建命令之后于后台解析异步、非阻塞质量门Edit\|Write\|MultiEdit编辑后执行快速质量检查设计质量检查Edit\|Write\|MultiEdit当前端编辑偏向通用模板风 UI 时给出警告Prettier 格式化Edit编辑后对 JS/TS 文件自动执行 Prettier 格式化TypeScript 检查Edit编辑.ts/.tsx文件后执行tsc --noEmitconsole.log 警告Edit对编辑文件中的console.log语句给出警告对应实现分别位于 scripts/hooks/post-bash-pr-created.js、scripts/hooks/post-bash-command-log.js构建/命令解析、scripts/hooks/quality-gate.js、scripts/hooks/design-quality-check.js、scripts/hooks/post-edit-format.js、scripts/hooks/post-edit-typecheck.js、scripts/hooks/post-edit-console-warn.js。生命周期 HookLifecycle HooksHook事件行为会话开始SessionStart加载上次上下文并检测包管理器压缩前PreCompact在上下文压缩前保存状态Console.log 审计Stop每次响应后检查所有变更文件中的console.log会话摘要Stop在转录路径可用时持久化会话状态模式提取Stop评估会话中可提取的模式持续学习成本跟踪器Stop输出轻量级的运行成本遥测标记桌面通知Stop发送带任务摘要的 macOS 桌面通知standard会话结束标记SessionEnd生命周期标记与清理日志在 hooks/hooks.json 中这些生命周期 Hook 的映射如下SessionStartsession:start加载受限的历史上下文并检测项目状态与session-start:plan-canvas-sessions展示未完成的 Plan Canvas 审查会话便于新会话接续循环PreCompactpre:compact由 scripts/hooks/pre-compact.js 在压缩前保存状态Stopstop:format-typecheck对本次响应中编辑过的全部 JS/TS 文件做一次批量 Biome/Prettier 格式化与tsc类型检查超时 300 秒避免每次 Edit 都跑一遍、stop:check-console-log、stop:session-end异步持久化会话状态、stop:evaluate-session异步评估可提取模式、stop:cost-tracker异步成本遥测、stop:desktop-notify异步桌面通知standard、stop:plan-canvas-pending投递未送达的 Plan Canvas 浏览器反馈SessionEndsession:end:marker由 scripts/hooks/session-end-marker.js 记录生命周期标记非阻塞。内存持久化生命周期契约hooks/memory-persistence/README.md 定义了 ECC 的内存持久化契约它是文档层面稳定、可读的生命周期定义面生产环境实际加载的 Hook 图谱仍是 hooks/hooks.json事件Hook目的是否阻塞SessionStartsession:start加载受限的历史上下文与项目元数据否PreCompactpre:compact压缩前保存状态否PreToolUsepre:observe:continuous-learning捕获工具意图供学习信号使用否PostToolUsepost:observe:continuous-learning捕获工具结果供学习信号使用否PostToolUsepost:session-activity-tracker记录工具与文件活动供 ECC2 指标使用否Stopstop:format-typecheck编辑后的批量质量门是Hook 失败时Stopstop:check-console-log审计变更文件的调试日志依 Hook 输出警告/报错对应的可执行实现都位于 scripts/hooks/session-start.js加载受限的历史上下文、检测项目状态并准备会话元数据pre-compact.js在压缩前捕获状态session-end.js在转录元数据可用时持久化会话摘要observe-runner.js记录工具使用观察用于持续学习session-activity-tracker.js记录工具与文件活动供 ECC2 状态与可观测性使用。该契约还给出操作者期望Operator Expectations默认保持持久化数据本地化除非用户显式开启集成否则不向托管服务发送转录或工具痕迹用ECC_SESSION_START_MAX_CHARS限制会话开始加载的上下文用ECC_SESSION_START_CONTEXToff允许退出生命周期 Hook 统一通过ECC_HOOK_PROFILE与ECC_DISABLED_HOOKS做 profile 门控。自定义与运行期控制禁用某个 Hook删除或注释 hooks/hooks.json 中对应的 Hook 条目如果 Hook 以插件形式安装则在~/.claude/settings.json中覆盖{ hooks: { PreToolUse: [ { matcher: Write, hooks: [], description: Override: allow all .md file creation } ] } }运行期 Hook 控制推荐不必编辑hooks.json用环境变量即可控制 Hook 行为# minimal | standard | strict默认: standard export ECC_HOOK_PROFILEstandard # 禁用指定 Hook ID逗号分隔 export ECC_DISABLED_HOOKSpre:bash:tmux-reminder,post:edit:typecheck # 仅在搭建或恢复期间关闭 GateGuard export ECC_GATEGUARDoff # 限制 SessionStart 附加上下文默认: 8000 字符 export ECC_SESSION_START_MAX_CHARS4000 # 完全禁用 SessionStart 附加上下文 export ECC_SESSION_START_CONTEXToff三个 profile 的含义minimal— 只保留必需的生命周期 Hook 与安全 Hookstandard— 默认质量与安全检查之间取得平衡strict— 启用额外的提示与更严格的护栏。源码层面scripts/lib/hook-flags.js 是这些开关的裁决者ECC_HOOKS_ENABLED控制总开关默认 true可接受1/true/yes/on与0/false/no/offECC_HOOK_PROFILE只接受minimal|standard|strict非法值回退到standardECC_DISABLED_HOOKS按逗号拆分为禁用 ID 集合每个 Hook 通过run-with-flags.js传入自己允许的 profile 列表例如standard,strict表示该 Hook 只在 standard 与 strict 下启用最终由isHookEnabled()综合裁决。此外安装器还可以在ecc/setup.json中写入受管配置enabled、profile作为环境变量缺失时的最终回退。环境变量ECC_DRY_RUN1可开启干跑模式仅打印[DryRun] Hook ... would execute: ...而不真正执行。ECC_GATEGUARDoff与ECC_SESSION_START_*的语义也可在源码中验证scripts/hooks/gateguard-fact-force.js 中ECC_GATEGUARDoff会关闭事实强制门scripts/hooks/session-start.js 中ECC_SESSION_START_CONTEXT与ECC_SESSION_START_MAX_CHARS控制会话开始注入的附加上下文注入被截断时还会输出提示指导用户调高上限或彻底关闭。自己动手写 HookHook 本质上是这样的 shell 命令从 stdin 接收 JSON 格式的工具输入向 stdout 输出 JSON。基本结构// my-hook.js let data ; process.stdin.on(data, chunk data chunk); process.stdin.on(end, () { const input JSON.parse(data); // 访问工具信息 const toolName input.tool_name; // Edit、Bash、Write 等 const toolInput input.tool_input; // 工具特有参数 const toolOutput input.tool_output; // 仅 PostToolUse 可用 // 警告非阻塞写入 stderr console.error([Hook] 展示给 Claude 的警告信息); // 阻止仅 PreToolUse以退出码 2 退出 // process.exit(2); // 始终向 stdout 输出原始数据 console.log(data); });退出码约定0— 成功继续执行2— 阻止工具调用仅 PreToolUse其他非零 — 错误记入日志但不阻止Hook 输入 Schemainterface HookInput { tool_name: string; // Bash、Edit、Write、Read 等 tool_input: { command?: string; // Bash: 要执行的命令 file_path?: string; // Edit/Write/Read: 目标文件 old_string?: string; // Edit: 被替换的文本 new_string?: string; // Edit: 替换文本 content?: string; // Write: 文件内容 }; tool_output?: { // 仅 PostToolUse output?: string; // 命令/工具的输出 }; }异步 Hook对于不应阻塞主流程的 Hook例如后台解析{ type: command, command: node my-slow-hook.js, async: true, timeout: 30 }异步 Hook 在后台运行不能阻止工具执行。在 hooks/hooks.json 中pre:observe:continuous-learning、post:dispatcher:async、stop:session-end、stop:evaluate-session、stop:cost-tracker、stop:desktop-notify、session:end:marker均为异步 Hook各自配有超时1045 秒不等。从源码理解 Hook 运行器的健壮性设计scripts/hooks/run-with-flags.js 揭示了 ECC Hook 运行器的几个工程细节stdin 上限读取 stdin 上限为 1MBMAX_STDIN超限会截断并抑制直通输出fail-open避免把截断的 JSON 原样回显给 harness 而被误判为 Hook 失败退出前冲刷先设置process.exitCode等 stdout/stderr 排空后再process.exit防止大输出被操作系统管道缓冲区截断修复了 harness 将 Hook 判失败的问题路径穿越防护解析脚本路径后校验其必须位于插件根目录之内越界直接拒绝双执行模式优先require()导出run(rawInput)的模块内联执行省去一次 Node 子进程开销约 50–100ms没有run导出的旧式 Hook 则回退到spawnSync子进程方式并通过ECC_HOOK_ID、ECC_HOOK_INPUT_TRUNCATED、ECC_HOOK_INPUT_MAX_BYTES等环境变量向子进程传递上下文。常见 Hook 配方Recipes对 TODO 注释给出警告{ matcher: Edit, hooks: [{ type: command, command: node -e \let d;process.stdin.on(data,cdc);process.stdin.on(end,(){const iJSON.parse(d);const nsi.tool_input?.new_string||;if(/TODO|FIXME|HACK/.test(ns)){console.error([Hook] New TODO/FIXME added - consider creating an issue)}console.log(d)})\ }], description: Warn when adding TODO/FIXME comments }阻止创建超大文件{ matcher: Write, hooks: [{ type: command, command: node -e \let d;process.stdin.on(data,cdc);process.stdin.on(end,(){const iJSON.parse(d);const ci.tool_input?.content||;const linesc.split(\\n).length;if(lines800){console.error([Hook] BLOCKED: File exceeds 800 lines (lines lines));console.error([Hook] Split into smaller, focused modules);process.exit(2)}console.log(d)})\ }], description: Block creation of files larger than 800 lines }用 ruff 自动格式化 Python 文件{ matcher: Edit, hooks: [{ type: command, command: node -e \let d;process.stdin.on(data,cdc);process.stdin.on(end,(){const iJSON.parse(d);const pi.tool_input?.file_path||;if(/\\.py$/.test(p)){const{execFileSync}require(child_process);try{execFileSync(ruff,[format,p],{stdio:pipe})}catch(e){}}console.log(d)})\ }], description: Auto-format Python files with ruff after edits }要求新源码文件配套测试文件{ matcher: Write, hooks: [{ type: command, command: node -e \const fsrequire(fs);let d;process.stdin.on(data,cdc);process.stdin.on(end,(){const iJSON.parse(d);const pi.tool_input?.file_path||;if(/src\\/.*\\.(ts|js)$/.test(p)!/\\.test\\.|\\.spec\\./.test(p)){const testPathp.replace(/\\.(ts|js)$/,.test.$1);if(!fs.existsSync(testPath)){console.error([Hook] No test file found for: p);console.error([Hook] Expected: testPath);console.error([Hook] Consider writing tests first (/tdd))}}console.log(d)})\ }], description: Remind to create tests when adding new source files }跨平台注意事项Hook 逻辑统一用 Node.js 脚本实现以保证 Windows、macOS、Linux 三平台一致运行。文档特别提到持续学习观察器以 Node 模式 Hook 形式暴露通过带 profile 门控的运行器run-with-flags.js委托给已有的observe.sh实现并带有 Windows 安全的回退行为。这意味着在 Windows 上例如%USERPROFILE%\.claude配置根目录、PowerShell 安装路径Hook 仍能正常工作无需为 shell 差异单独维护脚本。相关资源rules/common/hooks.md — Hook 架构指南skills/strategic-compact/ — 战略压缩技能scripts/hooks/ — Hook 脚本实现hooks/hooks.json — 生产环境的 Hook 图谱hooks/memory-persistence/README.md — 内存持久化生命周期契约docs/architecture/observability-readiness.md — 可观测性就绪设计【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
