关于 clean-code-guard
clean-code-guard 是用于审查生成或修改代码的便携式指令 Skill,适用于编码 Agent 和代码审查场景。它将通用代码质量原则与针对 AI 生成代码的检查结合,不依赖 MCP 服务或本地工具。
主要功能
- 01生成代码的守护式检查
- 02编写时应用质量规则
- 03结构化代码审查报告
- 04提供 SOLID 与 DRY 等参考
- 05交付前自检
适用场景
- 01提交或合并前检查代码改动
- 02按规则审查代码并报告问题
- 03编写代码时持续遵循质量约束
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ amelnagdy/ guard-skills --skill clean-code-guard安装后在 Claude Code 中输入/clean-code-guard确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlreferences/ai-failure-modes.mdcomments-and-formatting.mddry-kiss-yagni.mdnaming-and-functions.mdreview-checklist.mdsolid.mdsources.md详细介绍
clean-code-guard
你正在审查即将发布的生成代码或变更代码。请在首次实现后将以下规则作为守护检查来应用;一旦此技能启用,在同一会话中后续的每次代码变更都要继续应用这些规则,并在每次编辑后重新运行交付前自检,而不要因为技能先前已加载就退回到未经守护检查的输出。如果用户在编写代码之前明确调用此技能,编写代码时也要遵循相同规则,并在交付前运行自检。
兼容性
这是一项可移植的指令技能。它不需要 MCP 服务、网络访问、API 密钥、Shell 命令、本地可执行文件或捆绑脚本。它可用于任何支持 SKILL.md 和直接链接的 references/ 文件的运行时;agents/openai.yaml 是轻量级显示元数据。
此技能不能替代项目的代码检查工具、格式化工具、类型检查器或测试运行器。请使用项目自带工具进行机械式验证;使用此技能对代码质量和审查进行判断。
如何使用此技能
此技能有三种模式——根据用户的请求选择。
守护检查模式(推荐):生成、编辑、重构或修复代码后,根据以下始终适用的规范检查差异或目标文件。提交、合并或展示工作成果前,先修复违规之处。
实时模式(明确调用):用户在进行高风险代码编辑前调用此技能时,编写代码的同时应用相同规范,然后运行交付前自检清单。如果违反任何规则,在向用户展示之前先修复。
审查模式(用户要求审查、审计、批评或评价代码时触发):根据 references/review-checklist.md 检查目标文件,并生成结构化的问题报告。除非用户要求,否则在审查模式下不要编辑代码。
在以上所有模式中,规则正文都位于 references/ 中。遇到以下情况时,请阅读相关参考文件:
- 遇到自己不完全记得缘由的规则。
- 用户对某条规则提出异议,而你需要引用其来源。
- 处于审查模式,需要完整清单。
- 正在审查的代码涉及某项具体原则(例如,子类化 → references/solid.md;去重 → references/dry-kiss-yagni.md)。
参考文件如下:
- references/naming-and-functions.md — 命名、函数长度、参数、命令与查询分离。
- references/comments-and-formatting.md — 何时添加注释、何时删除注释、与相邻代码风格保持一致。
- references/solid.md — SRP、OCP、LSP、ISP、DIP,采用现代表述和识别异味的方法。
- references/dry-kiss-yagni.md — 知识与代码重复、Sandi Metz 的重新内联规则、McCabe 复杂度、Fowler 对 YAGNI 成本类别的划分。
- references/ai-failure-modes.md — LLM 生成糟糕代码的 14 种系统性方式。**如果你是正在阅读此技能的 AI Agent,请先阅读此文件。**这是此技能中价值最高的文件。
- references/review-checklist.md — 审查模式的结构化检查流程。
- references/sources.md — 来源 URL 的集中参考书目。只有在需要核实或引用外部来源时才阅读。
示例
- 编码 Agent 实现一个端点:在成果被展示或提交之前,对 diff 使用 guard-pass 模式。
- 用户问"审查这个 PR"或"我应该合并这个吗?":使用审查模式,并报告来自 references/review-checklist.md 的发现;除非被要求,否则不要编辑。
- 用户问"用 clean-code-guard 实现这个端点":在编写过程中使用实时模式,然后在交付前运行自检。
- 用户问"重构这个函数,保持行为不变":完全保留可观察行为,并将任何缺陷修复视为单独的变更。
成功标准
当编写代码的任务避开了所列的失败模式,代码审查任务产出带有具体证据的按优先级排序的发现,并且重构在用户未明确要求行为变更时保持行为不变,此技能即为生效。对于 frontmatter 排除项所涵盖的概念性、CI、git 工作流、散文、数据分析和测试运行任务,它应保持沉默。
此技能为何存在
大模型生成的代码具有可衡量的、系统性的失败模式,通用的"遵循整洁代码"指令无法捕捉到。以下是有已发表研究支持的示例:
- 代码重复增长了 8 倍,在被跟踪的代码库中,2021 年至 2024 年间(GitClear 2025 报告)。
- 包幻觉率平均为 19.6%,跨越 16 个模型(Spracklen 等,USENIX Security '25)。
- 大模型经常将高风险操作包裹在宽泛的 catch-all 处理程序中,从而吞掉错误(Karpathy)。
- AI Agent "尽管测试失败仍宣称成功",通过返回硬编码的 fixture 值(Fowler,Patterns for Reducing Friction)。
- 在 AI 辅助的提交中,函数规模从 142 增至 267 LoC,圈复杂度从 4.2 增至 8.1(GitClear)。
经典原则(Clean Code、SOLID、DRY/KISS/YAGNI)仍然是基础——但此技能增加了大多数规则包所遗漏的AI 专属层。
始终适用的强制要求
以下是每次代码变更时都要遵循的规则。它们是强制性的,而非建议。
函数与命名
- 名称揭示意图。 在没有限定词的情况下,绝不使用
data、data2、result、result_final、item、temp、value、obj、info、helper、manager、utils或handle_*/process_*/do_*。名称必须回答它为何存在以及它做什么。(Clean Code 第 2 章) - 函数保持小巧。 目标 ≤20 行,一个抽象层级,只做一件事。如果你能提取出一个名称不会重述其函数体的函数,那么父函数就在做不止一件事。(Clean Code 第 3 章)
- 四个参数是硬性上限。 到了五个,停下来并引入请求/配置对象(record、struct、DTO 或等效物)。绝不使用布尔标志参数——改为拆分成两个函数。
- 没有输出参数。 一个函数要么返回值(查询),要么有副作用(命令)。绝不两者兼有。命令名称使用动词;查询名称使用名词或 getter 风格的名称。(CQS)
注释与结构
- 注释解释为什么,绝不解释是什么。 删除任何对其下方代码行进行转述的注释。删除步骤编号脚手架注释。删除被注释掉的代码——版本控制是存在的。(Clean Code 第 4 章)
- 匹配文件现有的风格。 在编写之前,阅读你正在编辑的文件以及至少一个相邻文件。镜像其大小写、导入顺序、错误处理、日志记录以及 HTTP/DB 客户端的选择。不要引入第二种模式。
SOLID
- 每个模块只服务一个参与者。 一个类应当只对一个利益相关方群体(会计、认证、报表)负责。如果两个不相关的子系统都伸手进入同一个类,就把它拆开。(SRP,Uncle Bob 2014)
- 通过新增代码扩展,而非修改代码。 如果新增一个变体需要在现有函数中再加一个类型标签分支,那就要先重构成注册表、策略或[多态]分派。(OCP)
- 子类不得拒绝父类的契约。 绝不要通过重写方法来表示"未实现"或"不支持的操作"。绝不要在重写中加强前置条件或削弱后置条件。如果你需要那样做,说明继承关系是错的。(LSP)
- 抽象应随客户端而居,而非随实现而居。 当你引入接口、协议或抽象契约时,把它放在消费它的包中,而不是放在具体类旁边。(DIP)
DRY、KISS、YAGNI
- 删除重复的 知识,而非重复的 文本。 两个看起来相似但编码了不同规则的函数并不违反 DRY。同一条规则在代码 + 文档 + schema 中被表达出来才算违反。(Pragmatic Programmer,"DRY")
- 错误的抽象比重复更糟。 如果一个抽象已经为每个调用方的特殊情况累积了分支,就把它重新内联回调用方,然后删除死分支,再重新抽象。(Sandi Metz,"The Wrong Abstraction")
- 复杂度上限:圈复杂度 ≤10,嵌套深度 ≤5。 在超出之前先重构。(McCabe 1976)
- 不要任何推测性的东西。 没有当下调用方,就不要可选参数、配置标志、环境变量、功能开关、接口、工厂或基类。如果你发现自己正在添加
enable_*、use_*_v2或*_mode,删掉它,直接交付具体行为。(Fowler,"Yagni")
AI 专属护栏 —— 最高杠杆的部分
- 绝不用宽泛的兜底处理吞掉错误。 只捕获你能从中恢复的特定错误类型。如果无法恢复,就让错误向上传播。禁止在 catch 处理程序中返回 null/none/空成功,除非函数契约明确记载了该行为。(Karpathy)
- 守住边界;信任契约。 在信任边界处 —— 外部输入、请求/API 载荷、反序列化或跨进程数据、任何来自不可信来源的内容 —— 都要校验,即使正常路径看起来没问题。在边界内部,不要为声明类型或调用方契约已排除该情况的值添加 null 检查或运行时类型检查。判断是否需要防护的标准不是“这理论上会不会出错”,而是“不可信数据能否到达这里”。(arXiv 2409.19182)
- 验证每一个导入和外部调用。 在调用某个库的方法之前,确认它存在于所安装的版本中(阅读包源码、检查 lockfile,或导入并检查)。不要基于 API “应该”长什么样来生成代码。(USENIX Security '25)
- 生产代码中不得硬编码“成功”返回或 mock 数据。 绝不要从规格说明其执行真实工作的函数中返回
{"status": "ok", ...}或预制数据。如果无法实现,就用该语言的未实现或不受支持操作机制显式失败,并如实说明。绝不要为了让测试通过而禁用、跳过或削弱测试。(Fowler,Claude Code issue #6984) - 重新推导,不要从相似代码复制。 当你想复制一个函数再修改时,停下来。从规格说明重新推导。差一错误和错误 null 语义的缺陷几乎总是通过从相似代码复制引入的。(arXiv 2411.01414)
- 在编写之前先枚举边界情况。 对于任何范围、差一、null/空/单元素/多元素、奇偶或 unicode/字节边界,先在注释中写出情况列表。在继续之前,在代码中覆盖每一种情况。
- 交付前清除死代码。 运行 linter 或 grep 检查未使用的导入、未使用的符号、不可达分支和“以防万一”的导出。移除它们。今天没有任何东西调用的函数不能为了“将来某天”而保留。
- 先读后写。 在不熟悉的仓库中写入之前,阅读你将编辑的文件、一个相邻文件,以及任何项目规则文件(CLAUDE.md、AGENTS.md、README 的“约定”部分)。使用项目现有的辅助函数、错误类型和日志。
- 几行代码能覆盖的,不要新增依赖。 在添加包之前,检查标准库、已安装的依赖,以及几行本地代码能否完成任务。新依赖是永久的维护和供应链暴露面;只有当它承载你不应重新实现的真正复杂性(密码学、解析、时区 —— 仅为示例,并非穷举)时才添加,绝不要为了省十行代码而添加。参见 references/dry-kiss-yagni.md。
底线 —— 绝不要为了简单而削减这些
第 16 条规则在边界内部信任契约;即使你删除了推测(14)、防御性防护(16)和死代码(21),以下条目仍然保留。移除其中任何一条都是行为变更,而不是清理 —— 保留它,或标记出来并询问。
- 每个信任边界处的校验与净化 —— 外部输入、请求/API 载荷、反序列化或跨进程数据。
- 防止数据丢失的错误处理。
- 安全措施 —— 授权、输出转义、参数化查询、密钥处理。
- 用户明确要求的行为。 随口提及 ≠ 要求,但不要丢弃已被要求的内容。
重构纪律
- 重构时保持可观察行为不变。 当用户要求你清理、简化或重构现有代码时,不要改变契约——相同的输入产生相同的输出,抛出相同的异常,产生相同的副作用,保持相同的顺序保证。如果你在重构时发现了一个 bug,单独标记出来,并在修改前先询问。重构的定义是*“对软件内部结构的修改,使其更易于理解、修改成本更低,同时不改变其可观察行为”*(Fowler,《重构》)。Bug 修复和重构是两种操作——绝不要把它们捆绑到同一次修改中。
交付前自检
在向用户展示你编写或编辑的代码之前:
- 将准则 1–24 逐条对照你的 diff 检查。修正每一处违规。
- 对于新函数,清点:行数 ≤ 20?参数 ≤ 4?复杂度感觉 ≤ 10?命名是否揭示意图?
- 对于新注释,问自己:它解释的是为什么吗?如果它解释的是是什么,删掉它。
- 对于新的错误处理:捕获的错误类型是否具体?处理逻辑除了静默返回之外,是否还做了别的事情?
- 对于新的抽象(接口、工厂、基类、注册表):今天是否存在第二个具体的使用者?如果没有,就内联它。
- 你是否阅读了你所编辑的文件以及至少一个相邻文件?你的风格是否匹配?
- 是否存在任何硬编码的 "ok" 返回值或桩数据?如果有,替换为真实实现,或显式返回未实现/不支持操作的失败。
- 如果这是一次重构:你是否改变了可观察行为?如果是,你捆绑了一个 bug 修复——把它拆分出来并询问用户。
如果你无法对每项检查都回答“是”,请在交付前修正。
在守卫检查通过后,将其展示出来,让用户能看到它已运行(守卫通过模式和实时模式——review 模式通过其自身的发现格式报告)。将每项修正列为 <file>[:<line>] — <what changed>,如果行号不稳定则省略行号,然后以一行收尾:clean-code-guard: <N> fixed, <M> flagged for author——如果没有任何触发,则为 clean-code-guard: clean。只报告你实际做出的修改;绝不要估算质量分数或百分比——不存在基准,因此这样的数字是凭空捏造的。这只是在报告本次检查;它不会阻止展示或提交。
当用户对某条规则提出异议时
引导他们查看相关 references/ 文件中的来源名称,仅在需要 URL 时才使用 references/sources.md。这些规则是站得住脚的——它们来自一手来源(Uncle Bob、Fowler、Hunt & Thomas、McCabe、Metz),以及 2024–2026 年关于大模型代码生成的已发表研究。如果用户有特定于其情境的理由要覆盖某条规则(例如某个构造函数确实需要 8 个参数来处理一个配置 DTO),请在代码注释中记录该例外,注明被覆盖的原则、原因以及重新审视的触发条件——即应重新考虑它的情形。没有重新审视触发条件的例外注释,本身就会成为下一次检查中的一项发现:没有出口的权衡只是被推迟的债务。
故障排除
- 如果任务是概念性的而非产出代码的,不要应用此技能; 直接回答该概念。
- 如果 review 模式开始产生仅针对风格的反馈,请使用 references/review-checklist.md,并优先关注行为 bug、脆弱性 和可维护性风险。
- 如果某条规则与某个明确的项目约定冲突,请遵循项目 约定,并且仅当该例外会让未来的维护者感到意外时,才记录它。
- 如果该技能感觉过于宽泛,请优先使用 frontmatter 中的排除项;不要向这个通用守卫技能中添加 特定于运行时的规则。
本技能不做什么
- 运行 linter 或静态分析。这些是工具层面的关注点;本技能关注的是写什么和看什么。
- 强制执行特定语言的格式化工具或 linter 偏好。以项目的样式工具为准。
- 替代测试。整洁的代码能通过测试;没有整洁的代码测试就无法通过,但没有测试的整洁代码同样是一种缺陷。