开源 Agent 套件 ECC 的四份示例工程拆解:哪些段落该抄,哪些只属于你的栈
本文基于 ECC 仓库 commit 591ab5c(2026-07-29)梳理,该项目仍在高频迭代,具体行为以仓库 https://github.com/affaan-m/ECC 最新代码与文档为准。
四份技术栈完全不同的示例文件,把 H2 一级标题抽出来排在一起,是一模一样的八段——这说明作者写这些示例时手里有一份骨架模板,而不是每次现编。 你要抄的就是那份骨架,不是里面的 Python 或 Ruby 内容。
ECC 是一套装在编码 Agent 之上的增强件,MIT 许可证。它的 examples/ 目录里有一批项目级 CLAUDE.md 的样板,覆盖 Django REST API、Go 微服务、Rust Axum 服务、Rails 单体应用等几种栈。这些文件的开头都写着同一句话:把它复制到你的项目根目录,然后按你的服务改。问题是改什么、留什么,样板本身没说。把四份放在一起读,答案就浮出来了。
站内已经有两篇讲通用方法的文章:怎么写 CLAUDE.md 讲规则文件的写法原则,上下文工程 讲怎么给模型组织信息。那两篇讲的是”应该怎么做”,本篇讲的是”一个真实开源项目实际是怎么做的”——具体到目录、文件名和它踩过的不一致。三篇分工不重叠,方法论看那两篇,落地样本看这篇。
一、先把骨架抽出来
四份文件的 H2 标题序列完全一致,顺序都不差:
Project Overview → Critical Rules → File Structure → Key Patterns → Environment Variables → Testing Strategy → ECC Workflow → Git Workflow。
八段,一个不多一个不少。Django 那份从第 6 行的 Project Overview 到第 303 行的 Git Workflow,Rails 那份从第 6 行到第 380 行,Rust 那份从第 6 行到第 280 行——起始行号都是 6,因为前面固定是一级标题加一句”复制到项目根目录”的引用块。
这个顺序不是随手排的。它的排列逻辑是从”这是什么”走到”你怎么改它”:先让读的一方知道栈和架构(Overview),再给死规矩(Critical Rules),然后给目录地图(File Structure),再给可以照抄的写法样例(Key Patterns),接着是运行时需要的外部输入(Environment Variables),最后三段是操作层——怎么跑测试、用哪些命令、怎么提交。
还有一份可以拿来交叉验证:examples/saas-nextjs-CLAUDE.md 的 H2 序列跟这四份一模一样,同样八段、同样顺序、同样从第 6 行起。也就是说这个骨架被五份技术栈互不相干的文件独立复用了一次,它是模板不是巧合,可以放心当骨架用。
反过来,examples/ 目录里同一批文件并不都遵守它。HarmonyOS 那份用的是 Core Rules 而不是 Critical Rules,而且没有 Key Patterns、Environment Variables、Testing Strategy 三段,末尾用的是 Available Commands 而不是 ECC Workflow;Laravel 那份写到 Key Patterns 就结束了,后面四段都缺。所以”八段骨架”是写全的那几份的共性,不是仓库的强制约定。你参照的时候,参照写全的那几份。
二、仓库里这些东西各在哪
| 组成部分 | 它负责什么 | 仓库位置 | 你什么时候会碰到它 |
|---|---|---|---|
| 四份主力栈示例 | 完整八段骨架的项目级规则样板 | examples/django-api-CLAUDE.md、examples/go-microservice-CLAUDE.md、examples/rust-api-CLAUDE.md、examples/rails-app-CLAUDE.md | 起一个新项目,要写规则文件时 |
| 通用起步模板 | 带占位符的空白骨架,开头额外有一段 Prompt Defense Baseline | examples/CLAUDE.md | 你的栈不在示例里,只想要空模板时 |
| 用户级模板 | 放在个人配置目录的全局偏好样板 | examples/user-CLAUDE.md | 想把跨项目的习惯抽出来时 |
| 命令目录 | 94 个斜杠命令定义 | commands/ | 示例的 ECC Workflow 段落引用命令时,回这里核对 |
| 技能目录 | 281 个技能 | skills/,如 skills/tdd-workflow/SKILL.md、skills/verification-loop/SKILL.md | 示例里的命令查不到、要找它现在的正主时 |
| agent 目录 | 67 个 agent 定义 | agents/ | 想知道哪些角色可以被派活时 |
| 遗留命令归档 | 已从默认命令面下线的旧入口 | legacy-command-shims/commands/ | 示例引用了 commands/ 里没有的命令时 |
| 多语言文档 | 含中文在内的翻译版文档与示例 | docs/zh-CN/,如 docs/zh-CN/examples/ | 读英文原文吃力时(注意可能滞后,下文有说明) |
examples/ 目录下还混着几样不是 CLAUDE.md 的东西:两个子目录 examples/gan-harness/ 和 examples/evaluator-rag-prototype/,外加 examples/hud-status-contract.json、examples/statusline.json 两份 JSON。evaluator-rag-prototype/ 里面是 scenario.json、trace.json、report.json、verifier-result.json 这类评测过程产物,跟规则文件不是一类;两份 JSON 是状态栏相关的配置样例,也跟规则文件无关。你去找模板时别被 examples/ 这个目录名误导,认准文件名里带 -CLAUDE.md 的那几份。
三、四份都有的那四条
Critical Rules 是八段里规则条目最密的一段——论行数它不是最长的(堆代码样例的 Key Patterns 才是),但它下面按主题分了三级小节,每个小节都是一串短句硬规矩。把四份的三级标题做交集,只有四个:
<语言> Conventions——Python Conventions、Go Conventions、Rust Conventions、Ruby ConventionsDatabaseError HandlingCode Style
这四条就是硬交集。它们能成为交集,是因为这四类规则恰好对应模型最容易出岔子的四个方向:写出不符合本语言习惯的代码、写出会打垮数据库的查询、错误处理层次错乱、格式和命名飘。
Database 这一小节在四份里的落点惊人地一致。Django 那份写”用 select_related() 和 prefetch_related() 防 N+1”,Rails 那份写”用 .includes、.preload 或 .eager_load,按需要选”;Go 那份写”所有查询用参数化占位符 $1、$2,绝不用字符串拼接”,Rust 那份写的几乎是同一句,只差一个情态动词。这两件事——N+1 和 SQL 注入——是 ORM 类栈和裸 SQL 类栈各自的头号陷阱,示例把它们提到了同一个位置。
Django 那份为 N+1 专门放了对照片段:
# BAD: N+1 query
orders = Order.objects.all()
for order in orders:
print(order.customer.name) # hits DB for each order
# GOOD: Single query with join
orders = Order.objects.select_related("customer").all()
值得抄的是这个 BAD/GOOD 对照的形式本身。只写”要用 select_related”是一句抽象规则,配上错误写法,判断边界就固定住了。Rust 那份用同样的形式写了 SQL 注入的对照,Rails 那份用同样的形式写了 includes。
Code Style 里还有一条四份逐字相同的规则:“No emojis in code or comments”(代码和注释里不要用表情符号)。Laravel 和 HarmonyOS 那两份没写全骨架,这条也照样在。这种跨栈完全一致的规则,说明它约束的不是语言,是模型的默认输出习惯。你的项目规则文件里,这类”矫正模型习惯”的条目值得单独归一处。
四、栈相关的部分长什么样
交集之外的部分,才是每份示例真正花力气的地方,而且分布很不均匀。
Go 那份的 Critical Rules 只有四个小节,就是那四条交集。Rust 那份多了一个 Testing。Django 那份多了 Authentication 和 Serializers——Serializers 是 DRF 特有的概念,它在别的栈里根本无处安放。Rails 那份最多,九个小节,多出来的是 Authentication and Authorization、Background Jobs、Views and Hotwire、Real-time and ActionCable、Deployment Setup 这五节。
这个不均匀本身有信息量:框架管的事越多,你要在规则文件里交代的约定就越多。 Rails 那份的 Overview 里列了 SolidQueue、SolidCache、SolidCable、Hotwire、ViewComponent、Kamal 一长串框架自带件,每一样都带一套默认行为和一套容易做错的用法,所以规则文件必须逐个交代——后台任务、视图、实时通道、部署各占一个小节,正好对应这串东西。Go 那份没有这些,因为 Go 微服务里这些能力是你自己拼的,规则文件管不到。
Key Patterns 段落也一样。Django 给的是 Service Layer / View Pattern / Test Pattern,Rust 给的是 Handler / Service / Repository / Integration Test,Rails 给的是 Service Object / Skinny Controller / Query Object / Background Job / Test Pattern。三份的共同结构是:一个业务逻辑层样例 + 一个入口层样例 + 一个测试样例。Go 那份稍有不同,它给的是 Repository Interface + Service with Dependency Injection + Table-Driven Tests,把入口层换成了接口定义——因为 Go 的重点在接口契约,不在 handler 长什么样。
Rails 那份的后台任务样例很值得单独看:
def perform(invoice_id)
invoice = Invoice.find(invoice_id)
return if invoice.exported_at.present? # local idempotency check
idempotency_key = "invoice-export-#{invoice.id}"
AccountingApi.export(invoice, idempotency_key: idempotency_key)
invoice.update!(exported_at: Time.current)
end
它同时演示了本地幂等检查和外部 API 幂等键,而对应的规则条目写的是”传 ID 不传记录”和”perform 必须幂等,假定它会跑不止一次”。规则和样例互相印证,这是这几份示例里质量最高的写法。你写自己那份的时候,凡是能配一段真实代码的规则,都配上。
五、边界与代价
这套示例明确不管几件事。
它不管你的项目实际长什么样。四份示例里的 File Structure 都是理想目录树——Django 那份写的是按业务域分 app(accounts、orders、products),业务逻辑放各 app 下的 services.py;Rails 那份在框架默认目录之外又加了 app/services/、app/queries/、app/policies/、app/errors/、app/forms/、app/components/ 一批目录。如果你的老项目不长这样,照抄这段会让规则文件描述的目录和真实目录对不上。规则文件里写错的目录,比不写更糟:模型会照着写错的路径去建文件。
它不管新旧一致性。示例的 ECC Workflow 段落里,Django、Rust、Rails 三份都写了 /tdd 和 /verify。这两个命令在 commands/ 目录里查不到,它们躺在 legacy-command-shims/commands/ 下面。那个目录的 README 第一句就是:这些斜杠入口已经不再由默认命令面加载。两个 shim 文件的描述字段也写得很清楚,/tdd 的正主是 skills/tdd-workflow/SKILL.md,/verify 的正主是 skills/verification-loop/SKILL.md。也就是说,你照抄示例里的 ECC Workflow 段落,写进去的是一组默认不可用的命令名。
同一段落里还有另一处不对齐:Rust 那份的 Review 步骤写的是通用的 /code-review,但 commands/ 目录里明明有 rust-review.md、rust-build.md、rust-test.md 三个 Rust 专用命令,一个都没被引到。Go 那份就引了 /go-test 和 /go-review,而且它压根没写 /tdd、/verify 这两个已下线入口,收尾直接给的是两条真实的 shell 命令。同一批示例,栈专用命令有的引了有的没引,Go 那份是四份里唯一没踩下线命令坑的。
它不管翻译同步。docs/zh-CN/examples/ 下面只有 CLAUDE.md、django、go、laravel、rust、saas、user 七份,Rails 和 HarmonyOS 两份没有对应的中文版。中文文档在这个仓库里是滞后于英文原文的,你拿中文版当唯一依据会漏东西。
还有一层代价要说清楚:这类套件会往你的机器里写文件、挂钩子、按配置连外部服务。仓库根目录同时存在 hooks/、install.sh、install.ps1、mcp-configs/、integrations/ 这些东西。示例里的 CLAUDE.md 本身只是文本,风险很低;但你如果顺手跑了安装脚本,装进去的就不只是这几份 Markdown。这两件事要分开决定。
六、上手与避坑
先只拿骨架,不拿内容。 会踩的原因是:示例读起来很完整,容易整份复制然后逐行删。删不干净的部分会变成对你的项目撒谎的规则。避法是反过来做——新建空文件,先敲那八个 H2 标题,再一段段用你自己项目的事实填。
Critical Rules 从四条交集起步。 会踩的原因是:一上来就想把所有约定写全,写到第三条就开始编。避法是先只写语言习惯、数据库、错误处理、代码风格这四小节,每小节三到六条,全都是你团队真的在执行的规矩。跑一周,把模型实际犯的错补进去。
ECC Workflow 段落逐条回 commands/ 核。 会踩的原因是上面说过的 /tdd、/verify 那件事——示例里的命令名不保证在当前命令面里存在。避法是把你打算写进去的每个命令名,在 commands/ 目录下确认有同名 .md 文件;查不到就去 skills/ 下找对应技能,写技能名,或者干脆写清楚这一步该跑什么脚本。斜杠命令与技能的差别可以看斜杠命令和技能机制这两篇。
File Structure 拿真实目录树生成,别手写。 会踩的原因是手写目录树时人会不自觉地写成”应该有的样子”。避法是用列目录的命令导出实际结构,再删掉噪音、补上注释。四份示例的目录树里,凡是名字看不出用途的条目都跟了一句行内注释,说明这里放什么、不放什么(比如 Rails 那份在 controllers/ 后面写”只做薄编排”,在 views/ 后面写”不放业务逻辑”),一望而知的条目就不注释。这个习惯值得学——对模型来说,注释比路径本身更有用,路径只告诉它文件放哪,注释才告诉它什么该写进去。
Environment Variables 里绝不出现真实凭据。 四份示例给的要么是明显的假占位串,要么干脆是空值:Rust 那份写 JWT_SECRET=your-secret-key-min-32-chars,一眼看得出是占位;Go 那份把等号后面留空,跟一句”生产环境从 vault 加载”;Rails 那份在这段结尾专门解释了什么时候用环境变量、什么时候用 Rails 加密凭据,并建议应用级密钥优先走加密凭据。会踩的原因是随手把本地 .env 粘进来。避法是只留键名加一行注释,值统一写成空或占位。
别把示例里的语言与框架版本当成你的版本。 四份示例的 Overview 段都在 Stack 那一行钉死了具体的语言最低版本和框架大版本,那是示例作者写作当时的选择,跟你的项目没有任何关系。Overview 里的版本必须来自你项目真实的依赖清单——pyproject.toml、go.mod、Cargo.toml、Gemfile.lock 里写的是什么就抄什么,而且升级依赖时要顺手改这一行。这一行写错的后果比目录写错更隐蔽:模型会按照它以为的版本去用 API,生成的代码在你的运行时里直接报错。
收束
写完你自己那份之后,对着这五条过一遍:八个 H2 是否齐全;Critical Rules 里那四条交集是否都在;File Structure 是否与真实目录一致;引用的每个命令名是否在 commands/ 里查得到;Environment Variables 里是否混进了真实值。
接下来该读哪个文件,取决于你卡在哪。骨架不确定,读 examples/CLAUDE.md,它是带占位符的空模板,还多一段 Prompt Defense Baseline 可以参考。想抽全局偏好,读 examples/user-CLAUDE.md,它演示了怎么把规则拆成多个模块文件再从主文件链过去。想搞清楚某个命令现在的正主是谁,去 commands/ 和 skills/ 两个目录下对着文件名找,legacy-command-shims/README.md 会告诉你哪些入口已经不在默认面上了。
规则文件写完不是终点。它的价值取决于模型实际改动时有没有遵守,这件事需要另一套约束——改动边界约定那篇讲的就是这个。
本文属于 ECC 开源 Agent 套件专题(共 40 篇,从选择性安装一直拆到内部机制)。同一批还写了另一种取向的项目——不给你资产、只给你纪律的 superpowers 方法论专题。