
核心观点:ECC 的真正价值不在于装了多少规则,而在于理解其分层架构和 Agent 编排体系后的系统化调优能力。
如果你已经在用 Claude Code 写代码,大概率听说过 ECC(Everything Claude Code)。这个由 affaan-m 创建、拿下 Anthropic x Forum Ventures 黑客松冠军的项目,在 GitHub 上已经积累了 220K+ Stars。但很多人对它的理解停留在"一套 Claude Code 配置文件"的层面——这就像把 Kubernetes 理解为"一组 YAML 文件"一样,不能说错,但远远不够。
ECC 的官方定位是 Claude Code 的工程化增强系统。它不是"一个配置",而是一整套工程化体系,包含五个核心层次:
层次 | 作用 | 通俗理解 |
|---|---|---|
Rules | 编码规范、安全策略、工作流标准 | 告诉 AI 什么是对的、什么是错的 |
Agents | 可复用的专家角色(审查员、测试员、架构师等) | 你有了一队可以随时调用的同事 |
Skills | 特定场景的深度知识包 + 旧版 Commands 的快捷入口 | 每个技能就是一个领域的"专家大脑" |
Hooks | 自动化的前后置触发器 | 把检查变成自动化门禁 |
MCP | 外部工具连接协议 | 让 AI 能调用数据库、浏览器等真实工具 |
这篇文章不会面面俱到。我会把火力集中在理解 ECC 最关键的 Rules、Agents、Hooks 三层——这三层是 ECC 的核心工程化能力,也是我在实际项目中踩坑最深、收获最大的地方。Skills 是 Agents 的能力扩展(旧版的 Commands 已归入 Skills 作为兼容层),MCP 则是另一个可以单独展开的话题。
如果你已经在用 ECC 但感觉"好像没什么变化",或者装了之后反而觉得 Claude Code 变慢了,那这篇文章就是为你写的。
ECC 的 Rules 分为两层——common/ 放语言无关的通用规则(编码规范、安全、测试、Git 工作流等),语言层(typescript/、python/、golang/、web/ 等几十套)放各自专属的规则。
语言层文件通过一行引用关联到通用层:
> This file extends [common/coding-style.md](../common/coding-style.md) with Go-specific content.这个 extends 不只是装饰。读一个语言层文件时,必须同时读它引用的通用层,才能理解完整的规则体系。
两条规则:语言层覆盖通用层,项目级覆盖全局级。
举个例子。common/coding-style.md 的核心原则是不可变性——所有操作返回新对象,不修改原对象。但 Go 习惯用指针接收器做 mutation,强行不可变反而写不出地道代码。所以 golang/coding-style.md 可以覆盖这条规则,优先采用 Go 的惯用方式。
Rules 定义了"应该怎么做",而 Agents 定义了"谁来做"。这是 ECC 真正拉开差距的地方。
这一章是全文的核心,请耐心看完。
先看一个贯穿全章的案例:你接到一个需求,要给一个 Python 服务加 Redis 缓存层。
在没有 ECC 的世界里,你打开 Claude Code,输入需求,AI 直接开始写代码。你 review,发现有问题,让它改,改完提交。全靠你一个人盯着。
在 ECC 的世界里,整个过程是这样的:
你:需求描述 → planner(规划)→ tdd-guide(写测试)
→ 你写代码 → code-reviewer(审查)→ build-error-resolver(修构建)
→ security-reviewer(安全审查)→ 你确认 → 提交每个环节都有专门的 Agent 介入,而且大部分是自动触发的。你不用在每一步去想要不要检查、怎么检查——Agent 自己跳出来了。
这就是 ECC Agent 编排的核心价值。
ECC 目前内置了 67 个 Agent(具体列表随版本变化,以下是日常最常用的一组):
Agent | 用途 | 什么时候用 |
|---|---|---|
planner | 实施规划 | 复杂功能、重构 |
architect | 系统设计 | 架构决策 |
tdd-guide | TDD 引导 | 新功能、bug fix |
code-reviewer | 代码审查 | 写完代码后 |
security-reviewer | 安全分析 | 提交前 |
build-error-resolver | 构建错误修复 | 构建失败时 |
e2e-runner | E2E 测试 | 关键用户流程 |
refactor-cleaner | 死代码清理 | 代码维护 |
doc-updater | 文档更新 | 更新文档时 |
rust-reviewer | Rust 代码审查 | Rust 项目 |
每个 Agent 本质上是一个预定义的 Prompt,告诉 Claude Code 以某种角色执行某种任务。planner 的 Prompt 是"请你作为实施规划专家……",code-reviewer 的 Prompt 是"请审查以下代码变更……"。
ECC 在 agents.md 规则文件中定义了四个自动触发场景。你不用手动调用,当满足条件时,Claude Code 会主动建议使用对应的 Agent:
场景 | 触发条件 | 建议的 Agent |
|---|---|---|
你提了一个复杂需求 | 需求涉及多个文件、多个步骤 | planner |
你刚写完/修改了代码 | Write/Edit 操作完成 | code-reviewer |
你在修 bug 或加新功能 | 需求描述包含"fix/bug/new feature" | tdd-guide |
你在做架构决策 | 涉及系统设计、技术选型 | architect |
这个机制的实现方式并不神秘——agents.md 规则文件里写了类似这样的指令:
No user prompt needed:
1. Complex feature requests - Use **planner** agent
2. Code just written/modified - Use **code-reviewer** agent
3. Bug fix or new feature - Use **tdd-guide** agent
4. Architectural decision - Use **architect** agentClaude Code 读到了这条规则,就会在执行完代码修改后主动建议:"要不要用 code-reviewer 审查一下?"
实际体验:你刚提交了一段代码修改,Claude Code 说"需要我对刚改的代码做个审查吗?"你说"好",它就会启动 code-reviewer Agent,拉取变更 diff,逐行审查,输出审查结果。整个过程就像团队里有个 senior 一直在旁边盯着。
子 Agent 之间默认是独立的。这意味着你可以同时启动多个不冲突的 Agent。
场景:你准备对一个前端模块做大规模重构。同一时间你可以做两件事:
两个任务没有依赖关系,可以平行跑。这在 ECC 的 rules 里有明确的指导:
# GOOD: Parallel execution
Launch 3 agents in parallel:
1. Agent 1: Security analysis of auth module
2. Agent 2: Performance review of cache system
3. Agent 3: Type checking of utilities
# BAD: Sequential when unnecessary
First agent 1, then agent 2, then agent 3但注意:有依赖关系的任务不能平行。典型的场景是 TDD 流程——你不能一边让 tdd-guide 写测试、一边让 implementer 写实现代码,因为实现要以测试为驱动。
我踩过的坑:有一次在做数据库迁移,我同时启动了 schema-reviewer(审查数据库变更)和 code-reviewer(审查代码变更)。两个 Agent 各自修改了不同的 ORM 文件,但一个改了字段名,另一个用了旧字段名——结果冲突了。
平行执行的原则:
这是 ECC Agent 体系里最有意思的设计——也可能是最容易被忽略的。
子 Agent 零上下文启动。这意味着什么?当你调用 code-reviewer 时,它不会继承主会话里前面几万字的所有对话历史。它只看到它需要看到的东西:代码变更 diff、相关的规则配置、以及你显式传给它的上下文。
这不是缺陷,这是有意为之的设计。三个好处:
当然,代价也很明显:子 Agent 不知道你已经讨论过的决策。
场景:你在主会话里已经和 Claude Code 讨论决定了用 Redis 而不是 Memcached。然后你启动了 code-reviewer。code-reviewer 看到代码里有 Redis 的依赖,可能会建议"考虑用 Memcached"—它不知道你已经做出了选择。
解决方案:在调用子 Agent 时,显式传递关键上下文。
"请审查这段代码。已经确认的技术选型:Redis(已决定,不再讨论)、Docker Compose 本地开发。不需要审查这些决定。"这种"显式传递"机制迫使你做一件好事:把关键决策写清楚。好过把几万字对话历史一股脑丢给子 Agent,让它自己猜什么是重要的。
不是所有任务都需要 Sonnet 或 Opus 级别的模型。code-reviewer 审查一个简单的 bug fix、tdd-guide 写基础的测试脚手架、build-error-resolver 看编译错误——这些任务用 Haiku 完全够用。
Claude Code 原生支持通过环境变量 CLAUDE_CODE_SUBAGENT_MODEL 控制子 Agent 的模型选择(这不是 ECC 独有的特性,但 ECC 的文档中记录了这一配置):
# 子 Agent 全部使用 Haiku 4.5
export CLAUDE_CODE_SUBAGENT_MODEL=claude-haiku-4-5
# 子 Agent 使用 Sonnet 4.6
export CLAUDE_CODE_SUBAGENT_MODEL=claude-sonnet-4-6注意需要使用完整的模型 ID(如 claude-haiku-4-5),不能用简写 haiku。
实际效果:如果你的主会话用 Opus,子 Agent 全切到 Haiku,相对于 Sonnet 4.6 在简单审查任务上单次调用可节省约 80% Token 成本。按我的使用量,一个月省下来的 token 够跑额外的 50-100 次子任务。
但要注意匹配任务复杂度:
子任务类型 | 推荐模型 | 原因 |
|---|---|---|
简单的代码审查(< 100 行 diff) | Haiku | 足够了 |
复杂的架构审查(跨多个文件) | Sonnet | 需要理解全局 |
build 错误修复(典型错误) | Haiku | 模式识别为主 |
安全审查 | Sonnet 或 Opus | 安全不容有失 |
实施规划(复杂功能) | Sonnet | 需要深度推理 |
我个人的习惯:日常开发 CLAUDE_CODE_SUBAGENT_MODEL 设成 Haiku,遇到关键的安全审查或架构决策时,临时切回 Sonnet。
ECC 的 Agent 不只是一个"功能列表",它们可以串联成流水线。比如一次完整的 feature 开发流程:
planner(出方案)
→ tdd-guide(写测试)
→ 你写实现代码
→ code-reviewer(审查代码)
→ build-error-resolver(如果有构建错误)
→ security-reviewer(安全审查)
→ doc-updater(如果需要更新文档)
→ 你最终确认 → 提交每个 Agent 的输出是否触发下一个,取决于具体场景和你设置的规则。不一定每个环节都要走——如果你的功能不涉及安全敏感操作,security-reviewer 可以跳过。
这种链式编排在 ECC 的 development-workflow.md 里有明确的流程定义:
Research → Plan → TDD (RED → GREEN → IMPROVE)
→ Code Review → Commit & Push每步都有对应的 Agent 负责。
坑 1:上下文膨胀——Agent 虽然零上下文启动,但 Agent 的输出还是会回到主会话里的。如果你在一个会话里连续调了十几次 Agent,每次产生几百行输出,会话照样会迅速膨胀到接近上下文窗口上限。
我犯过的错误:一天下午在做全栈功能,连续用了 planner → code-reviewer → security-reviewer → code-reviewer(修改后再次审查)→ e2e-runner。到 e2e-runner 跑完的时候,会话已经接近上下文上限,后续的响应明显变慢。
应对:在关键节点开启新会话。planner 输出方案后,评审通过就开新会话开始实现,不把规划阶段所有讨论都带到实现阶段。
坑 2:平行错用——前面提到过。两个 Agent 各自改不同文件,但一个改了接口、另一个还在用旧接口。这个在平行执行时很难靠自动机制检测,因为每个 Agent 只看到自己的任务。
应对:给平行的 Agent 划定明确边界。如果两个任务有共享文件,就不要平行。
坑 3:权限冲突——子 Agent 默认继承了主会话的工具权限。如果主会话有文件写入权限,子 Agent 也能写文件。但有时候子 Agent 会操作到你没想到的文件——比如 code-reviewer 审查代码时发现格式问题,自动触发了格式化,改了 10 个本不该改的文件。
ECC 现在已经有了更细粒度的权限控制(通过 hooks 系统的 PreToolUse 做守卫),但在老版本里这是确实让人头疼的问题。
应对:在关键文件或目录上设置 PreToolUse 钩子做守卫。后面第三章会详细讲。
理想情况下 Agent 自动触发,但现实不一定。
第一步:检查规则文件是否存在
Claude Code 是读 rules 文件才知道要建议 Agent 的。如果 agents.md 文件不在正确的位置,自动触发就不会发生。
ls ~/.claude/rules/ecc/common/agents.md
# 如果不存在,说明安装有问题,重新安装第二步:检查触发条件是否匹配
规则里写的是"complex feature requests"触发 planner。如果你的需求是"把按钮颜色从蓝色改成红色",这不属于 complex feature,planner 不会自动跳出来——这是对的。但如果你的需求是"加一个完整的用户认证系统"planner 也没出来,那需要检查你的 rules 配置。
第三步:检查是否有其他规则在静默拦截
如果你装了多个规则包,优先级冲突可能导致某条规则被静默覆盖。去 ~/.claude/rules/ 目录看看有没有非 ECC 的规则包以同名文件覆盖了 ECC 的 agents.md。
第四步:手动调用
如果自动触发怎么都调不通,直接手动调用 Agent 永远是备选方案。这也是 ECC 的设计理念——Agent 是工具,不是约束:
请用 code-reviewer Agent 审查这段代码
请用 planner Agent 帮我规划这个功能自动触发是锦上添花,不是唯一路径。
Rules 是标准,Agents 是人,Hooks 是自动化流水线。
ECC 的 Hooks 分三种类型:
Hook 类型 | 触发时机 | 典型用途 |
|---|---|---|
PreToolUse | 工具执行之前 | 校验、守卫、拦截 |
PostToolUse | 工具执行之后 | 格式化、lint、类型检查 |
Stop | 会话结束时 | 最终构建验证 |
最实用的链条是 PostToolUse 的自动化检查。配置好之后,整个流程是这样的:
你写文件 → Write/Edit 完成
→ PostToolUse 触发 prettier 格式化
→ PostToolUse 触发 eslint --fix
→ PostToolUse 触发 tsc --incremental 类型检查
→ 如果有问题,立即提示你每次编辑后自动触发,不需要你手动运行任何命令。
配置示例(来自 ECC web/hooks.md):
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"command": "pnpm prettier --write \"$FILE_PATH\"",
"description": "Format edited frontend files"
},
{
"matcher": "Write|Edit",
"command": "pnpm eslint --fix \"$FILE_PATH\"",
"description": "Run ESLint on edited frontend files"
},
{
"matcher": "Write|Edit",
"command": "timeout 60 pnpm tsc --noEmit --pretty false --incremental --tsBuildInfoFile node_modules/.cache/tsc-hook.tsbuildinfo",
"description": "Type-check after frontend edits (incremental + timeout-capped)"
}
]
}
}注意 tsc 那行配置,两个细节值得展开。
--incremental 为什么重要?
没有 --incremental,每次 PostToolUse 触发 tsc 时,都会从头开始全量类型检查。在一个中型 Next.js 项目上实测(1000+ 文件),全量类型检查需要 30-60 秒。而你的编辑周期是 5-10 秒一次。结果就是:N 个 tsc 进程同时跑,每个都在全量检查,机器越来越慢,最后你可能直接把 hook 关掉了。
--incremental 会缓存上次的编译结果,只重新检查改动的文件。在一两次编辑后的增量检查,通常只需要 1-3 秒。
但注意:--noEmit 模式下,tsc 默认不会写 build info 文件。你必须用 --tsBuildInfoFile 显式指定路径,增量检查才生效。
timeout 60 为什么重要?
tsc 可能卡住。比如依赖图里有循环引用、某个类型递归过深、或者缓存文件损坏——tsc 可能跑几分钟都不结束。如果没有 timeout,PostToolUse 的 tsc 进程会一直挂在那里。多个挂起的 tsc 进程叠加,就是在吃你的内存。
timeout 60 确保任何一个 tsc 进程最多运行 60 秒。超时了,杀掉,下次编辑重新跑。这比一个永远不结束的进程要好得多。
这个 PreToolUse 钩子很实用——在文件写入之前检查行数。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write",
"command": "node -e \"...检查文件行数...\"",
"description": "Block writes that exceed 800 lines"
}
]
}
}场景:你正在重构一个模块,从一个大文件里提取函数。AI 可能在一个文件里继续追加代码,让文件膨胀到 1000+ 行。PreToolUse 检查到写入的文件超过 800 行,直接阻止写入,提示你需要拆分。
这条规则强制你遵循 ECC 的"文件不超过 800 行"标准。拦截不是惩罚,是防止你(和 AI)无意间制造技术债务。
1. 命令路径不对
pnpm、npm、npx 容易混用。项目用 pnpm,但 hook 里写的是 npm。或者在 monorepo 里,子包用的包管理器跟根目录不一样。
# 错误:在 pnpm 项目里用 npm
"command": "npm run lint"
# 正确:匹配项目的包管理器
"command": "pnpm lint"2. 环境变量不一致
Hook 在 Claude Code 的宿主进程中执行,不一定加载了你 shell 的 .zshrc/.bashrc。如果你的 lint 脚本依赖了 NODE_ENV 或 API_URL 这类环境变量,而 Claude Code 进程没有这些变量,命令可能失败。
3. 超时太短
timeout 60 对大多数项目足够。但如果你有个特别大的 monorepo(10000+ 文件),--incremental 缓存过期后的首次类型检查可能需要 2-3 分钟。这时候 60 秒 timeout 可能不够。调整时间阈值,或者安排定时清理缓存。
Hook 排障的通用框架:
Hook 失败了
→ 命令能独立运行吗?
→ 不能:命令或路径问题
→ 能:进下一步
→ 文件路径权限有问题吗?
→ 有:修复路径或权限
→ 没有:进下一步
→ 超时了?
→ 是:调整 timeout 阈值
→ 否:看报错日志具体分析ECC 的调试主要是三件事:规则覆盖链、Hook 行为、Agent 触发。
当你发现某条规则没有生效时,90% 的情况是覆盖链出了问题。
检查方法 1:确认规则文件位置
ls -la ~/.claude/rules/ecc/common/testing.md
ls -la .claude/rules/ecc/common/testing.md # 项目级可能覆盖了两个地方都有?项目级覆盖全局级。
检查方法 2:确认没有非 ECC 规则包冲突
ls ~/.claude/rules/正常情况下应该只有 ecc/ 一个目录(如果你也只装了 ECC)。如果还有其他规则包,检查它们的文件名是否与 ECC 冲突。两个规则包都有 coding-style.md,那就看谁在目录里的排序更靠前。
检查方法 3:用实际需求验证
如果你不确定 testing.md 是否生效,可以试着让 Claude Code 帮你写测试,看它是否遵循了 ECC 定义的 AAA 模式、80% 覆盖率等要求。
Hook 失败的根因诊断可以用这个框架快速定位:
现象:Hook 执行报错
├─ 命令本身能跑吗?
│ ├─ 终端单独跑 → 正常 → 环境差异问题
│ └─ 终端跑也报错 → 命令或参数写错了
├─ 路径问题?
│ ├─ $FILE_PATH 包含空格?
│ └─ 项目在 WSL 路径下?
├─ 超时?
│ └─ 调整 timeout 值、检查 --incremental 是否生效
└─ 权限?
└─ 文件只读?目录没有写入权限?Agent 没有自动触发,走这个排查路径:
ls ~/.claude/rules/ecc/common/agents.md.claude/rules/ 有没有同名文件提前返回MCP 的问题比较特殊,因为涉及外部服务注册。
常见失败场景:
MCP 服务注册失败:MCP 配置指向了一个不存在的路径,或者命令找不到。检查 MCP 配置中的 command 路径。如果用的是 npx,确保 npx 在 PATH 中。
Token 膨胀:MCP 工具调用的输入输出数据量大(比如数据库查询返回了 10000 行结果),导致上下文被迅速填满。在 MCP 配置中加上结果大小限制,或者配置只在必要时才调用。
权限模型边界:MCP 工具默认与主会话共享相同的权限集。如果 MCP 工具需要访问本地数据库,但会话权限只配置了 GitHub,API 调用会失败。确保 MCP 工具的权限与使用场景匹配。
ECC 的 README 有句被反复强调的话:
Important: Copy entire directories — do NOT flatten with
/*.
如果你用 cp -r rules/common/* ~/.claude/rules/ 平铺安装,三个问题会同时出现:
coding-style.md,平铺后后装的覆盖先装的,你以为两层叠加,实际只剩最后一层../common/ 相对路径指向全断正确做法是用命名空间目录:
mkdir -p ~/.claude/rules/ecc
cp -r rules/common ~/.claude/rules/ecc/
cp -r rules/typescript ~/.claude/rules/ecc/这样 ~/.claude/rules/ecc/ 下保持 common/ 和 typescript/ 各自独立的目录结构,互不干扰。
铁律:永远不在全局规则文件里做定制。 否则下次 git pull ECC 上游,你的修改可能被覆盖或产生冲突。
正确路径是项目级覆盖——在项目根目录的 .claude/rules/ecc/ 里放同名文件,它天然比全局规则优先级高。项目没放 common/ 目录也没关系,它会回退到全局的 common。
同步策略也很简单:全局规则保持纯上游不做修改,所有定制放项目级。每次升级 ECC 后,用 diff 对比上游新增内容,挑跟项目相关的 2-3 条同步过来就行。
ECC 从早期版本到 v2.0 的变化非常大。以下数据来自 GitHub API(2026 年 6 月 23 日查询):
对比早期只有几十个 Skill 和几个 Agent 的版本,规模已经是两个数量级的差异。
这种快速演化意味着:你三个月前的配置,可能已经不是最优解了。定期做三件事:
ls ~/.claude/rules/ecc/ 查看已安装的规则集,确认每条规则还在发挥作用。第一章介绍了规则的分层架构,可以用来检查覆盖链是否合理。git pull ECC 上游,用 diff 对比变化,挑跟项目相关的 2-3 条同步过来。第五章详细讲了同步方法。ECC 是个工具集,不是固定配置。你的使用方式应该随着你对它的理解和项目的变化而调整。这也是"从入门到精通"的最后一步:从"我该怎么配置 ECC"变成"我现在的项目最需要 ECC 的哪部分能力"。
当你开始主动选择装哪些规则、不装哪些规则;当你知道什么时候该用 Agent、什么时候手动写代码更快、什么时候多层检查是过度设计——那时候你就是老用户了。
这篇文章的经验来自我在多个项目中使用 ECC 的实际经历。如果你在阅读过程中有不同看法或更好的实践,欢迎交流。ECC 本身也在不断迭代,文中的具体数字和 Agent 列表可能在你读到时有变化,建议以 ECC GitHub 仓库的最新版本为准。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。