
clean-code-guard
热门在生成或修改的生产代码发布前进行审查,使用整洁代码、SOLID、DRY、KISS、YAGNI 以及针对 LLM 的特定失败模式检查,支持任何编程语言。最适合在智能体编写、编辑、重构或修复代码后、在展示、提交或合并结果之前被动使用。当用户要求“审查这个 PR”、“合并安全吗?”、“让代码更整洁”、“审计这段代码”、“重构这个”、“修复这个 bug”,或编码智能体生成了实现代码后使用。也可以在风险编辑前显式调用以指导编写。在你自己完成非平凡生产代码的编写、编辑或重构后,主动调用它,不要等待被问。不要用于事实/概念性问题、CI/工具配置、git 工作流、运行/调试测试、纯架构讨论、散文写作、数据分析或测试代码审查(请使用 test-guard)。
在生成或修改的生产代码发布前进行审查,使用整洁代码、SOLID、DRY、KISS、YAGNI 以及针对 LLM 的特定失败模式检查,支持任何编程语言。最适合在智能体编写、编辑、重构或修复代码后、在展示、提交或合并结果之前被动使用。当用户要求“审查这个 PR”、“合并安全吗?”、“让代码更整洁”、“审计这段代码”、“重构这个”、“修复这个 bug”,或编码智能体生成了实现代码后使用。也可以在风险编辑前显式调用以指导编写。在你自己完成非平凡生产代码的编写、编辑或重构后,主动调用它,不要等待被问。不要用于事实/概念性问题、CI/工具配置、git 工作流、运行/调试测试、纯架构讨论、散文写作、数据分析或测试代码审查(请使用 test-guard)。
clean-code-guard
你正在审查生成或修改后的代码,确保其在发布前符合质量标准。在第一次实现之后,应用以下规则作为守卫检查——一旦此技能激活,在同一个会话中每次后续代码变更时都要持续应用,并在每次编辑后交付前重新运行自检,而不是因为技能之前已加载而恢复到无守卫的输出。如果用户在编写代码前显式调用此技能,则在编写时应用相同规则,并在交付前仍运行自检。
兼容性
这是一个可移植的指令技能。它不需要 MCP 服务器、网络访问、API 密钥、shell 命令、本地可执行文件或捆绑脚本。它可以在任何支持 SKILL.md 以及直接链接的 references/ 文件的运行时中使用;agents/openai.yaml 是轻量级的显示元数据。
此技能不替代项目的 linter、格式化工具、类型检查器或测试运行器。对于机械验证,请使用项目自身的工具;对于代码质量和审查的判断层,请使用此技能。
如何使用此技能
此技能有三种模式——根据用户的请求选择。
守卫模式(推荐):在代码生成、编辑、重构或修复后,对照始终应用的命令检查 diff 或目标文件。在展示、提交或合并工作之前修复违规。
实时模式(显式):当用户在风险代码编辑前调用此技能时,在编写时应用相同的命令,然后运行交付前自检清单。如果你违反了任何规则,在向用户展示之前修复它。
审查模式(当用户要求你审查、审计、批评或评估代码时触发):对照目标文件执行 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 智能体,请先阅读此文件。 它是技能中杠杆率最高的文件。
- references/review-checklist.md — 审查模式的结构化检查清单。
- references/sources.md — 来源 URL 的中央参考书目。仅当你需要验证或引用外部来源时阅读。
示例
- 编码智能体实现了一个端点:在展示或提交之前对 diff 使用守卫模式。
- 用户要求“审查这个 PR”或“我应该合并这个吗?”:使用审查模式并从 references/review-checklist.md 报告发现;除非被要求,否则不要编辑。
- 用户要求“使用 clean-code-guard 实现这个端点”:在编写时使用实时模式,然后在交付前运行自检。
- 用户要求“重构这个函数,保持相同行为”:精确保留可观察行为,并将任何 bug 修复视为单独的变更。
成功标准
当代码编写任务避免列出的失败模式、代码审查任务产生带有具体证据的优先发现、重构在用户未明确要求行为变更时保留行为时,此技能即生效。对于 frontmatter 排除的概念性、CI、git 工作流、散文、数据分析和测试运行任务,它应保持沉默。
为什么存在此技能
LLM 生成的代码具有可测量的、系统性的失败模式,通用的“遵循整洁代码”指令无法捕获。由已发表研究支持的示例:
- 代码重复在 2021 年至 2024 年间增长了 8 倍(GitClear 2025 报告)。
- 包幻觉率平均为 19.6%,涵盖 16 个模型(Spracklen 等人,USENIX Security '25)。
- LLM 通常将风险操作包裹在宽泛的 catch-all 处理程序中,从而吞没错误(Karpathy)。
- AI 智能体**“尽管测试失败却声明成功”**,通过返回硬编码的 fixture 值(Fowler,Patterns for Reducing Friction)。
- 在 AI 辅助的提交中,函数大小从 142 行增长到 267 行,圈复杂度从 4.2 增长到 8.1(GitClear)。
经典原则(整洁代码、SOLID、DRY/KISS/YAGNI)仍然是基础——但此技能增加了大多数规则包遗漏的AI 特定层。
始终应用的命令
这些是每次代码变更时必须遵循的规则。它们是命令性的,而非建议。
函数和命名
- 名称揭示意图。 永远不要使用
data、data2、result、result_final、item、temp、value、obj、info、helper、manager、utils或handle_*/process_*/do_*而不加限定词。名称必须回答它为什么存在以及它做什么。(整洁代码第 2 章) - 函数保持短小。 目标 ≤20 行,一个抽象层级,做一件事。如果你能提取一个名称不重复函数体的函数,那么父函数做了不止一件事。(整洁代码第 3 章)
- 四个参数是硬上限。 达到五个时,停止并引入一个请求/配置对象(record、struct、DTO 或等效物)。永远不要使用布尔标志参数——应拆分为两个函数。
- 无输出参数。 函数要么返回值(查询),要么有副作用(命令)。不能两者兼有。命令名称使用动词;查询名称使用名词或 getter 风格名称。(CQS)
注释和结构
- 注释解释为什么,从不解释什么。 删除任何解释下面代码行的注释。删除步骤编号的脚手架注释。删除注释掉的代码——版本控制存在。(整洁代码第 4 章)
- 匹配文件现有风格。 在编写之前阅读你要编辑的文件以及至少一个相邻文件。镜像大小写、导入顺序、错误处理、日志记录和 HTTP/DB 客户端选择。不要引入第二种模式。
SOLID
- 每个模块一个角色。 一个类应对一个利益相关者组(会计、认证、报告)负责。如果两个不相关的子系统都访问同一个类,则拆分它。(SRP,Uncle Bob 2014)
- 通过新代码扩展,而非编辑。 如果添加新变体需要在现有函数中增加另一个类型标签分支,则首先重构为注册表、策略或多态分发。(OCP)
- 子类不得拒绝其父类的契约。 永远不要重写方法以表示“未实现”或“不支持的操作”。永远不要在重写中加强前置条件或削弱后置条件。如果你需要这样做,则继承关系是错误的。(LSP)
- 抽象与客户端共存,而非实现。 当你引入接口、协议或抽象契约时,将其放在消费它的包中,而不是放在具体类旁边。(DIP)
DRY、KISS、YAGNI
- 删除重复的知识,而非重复的文本。 两个看起来相似但编码不同规则的函数不是 DRY 违规。一个规则在代码 + 文档 + 模式中表达则是。(Pragmatic Programmer,“DRY”)
- 错误的抽象比重复更糟糕。 如果一个抽象为每个调用者的特殊情况积累了分支,则将其重新内联回调用者,然后删除死分支,再重新抽象。(Sandi Metz,“The Wrong Abstraction”)
- 复杂度上限:圈复杂度 ≤10,嵌套深度 ≤5。 在超出之前重构。(McCabe 1976)
- 无投机性内容。 没有当前调用者的可选参数、配置标志、环境变量、功能开关、接口、工厂或基类。如果你发现自己添加
enable_*、use_*_v2或*_mode,则删除它并交付具体行为。(Fowler,“Yagni”)
AI 特定护栏——杠杆率最高的部分
- 永远不要用宽泛的 catch-all 处理吞没错误。 只捕获你能恢复的特定错误类型。如果你无法恢复,让错误传播。从 catch 处理程序返回 null/none/空成功是被禁止的,除非函数契约记录了该行为。(Karpathy)
- 守卫边界;信任契约。 在信任边界——外部输入、请求/API 负载、反序列化或跨进程数据、任何来自不可信来源的数据——进行验证,即使快乐路径看起来没问题。在边界内部,不要为值的声明类型或调用者契约已排除该情况的值添加 null 检查或运行时类型检查。守卫的测试不是“理论上可能出错”,而是“不可信数据能否到达这里”。(arXiv 2409.19182)
- 验证每个导入和外部调用。 在调用库的方法之前,确认它存在于已安装的版本中(读取包、检查 lockfile 或导入并检查)。不要基于 API“应该”是什么样子来生成代码。(USENIX Security '25)
- 生产代码中无硬编码的“成功”返回或 mock fixture。 永远不要从规范说明执行实际工作的函数返回
{"status": "ok", ...}或预设数据。如果你无法实现,使用语言的未实现或不支持操作机制显式失败并说明。永远不要禁用、跳过或削弱测试以使其通过。(Fowler,Claude Code issue #6984) - 重新推导,而非从相似处复制。 当想复制一个函数并修改它时,停下来。从规范重新推导。差一错误和错误空语义几乎总是通过从相似处复制引入。(arXiv 2411.01414)
- 在编写边界情况之前枚举它们。 对于任何范围、差一、null/empty/one/many、even/odd 或 unicode/byte 边界,先在注释中写出情况列表。在继续之前覆盖代码中的每种情况。
- 交付前清除死代码。 运行 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”返回或 fixture 数据?如果是,替换为真实实现或显式的未实现/不支持操作失败。
- 如果是重构:你是否更改了可观察行为?如果是,你捆绑了一个 bug 修复——拆分它并询问用户。
如果你不能对每个检查回答“是”,在交付前修复。
守卫检查后,将其展示给用户以便他们看到它已运行(守卫模式和实时模式——审查模式通过其自身的发现格式报告)。将每个修复列为 <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 年关于 LLM 代码生成的研究。如果用户有特定上下文原因要覆盖(例如,构造函数确实需要 8 个参数用于配置 DTO),在代码注释中记录异常,说明被覆盖的原则、原因和重新审视触发条件——即应重新考虑的条件。没有重新审视触发条件的异常注释本身在下一次检查中就是一个发现:没有出口的权衡只是延迟的债务。
故障排除
- 如果任务是概念性的而非代码生成,不要应用此技能;直接回答概念。
- 如果审查模式开始产生仅风格反馈,使用 references/review-checklist.md 并优先考虑行为 bug、脆弱性和可维护性风险。
- 如果某条规则与明确的项目约定冲突,遵循项目约定,并仅在否则会令未来维护者惊讶时记录异常。
- 如果技能感觉过于宽泛,首先使用 frontmatter 排除;不要向此通用守卫技能添加运行时特定规则。
此技能不做的事情
- 运行 linter 或静态分析。这些是工具层面的关注点;此技能是关于写什么和寻找什么。
- 强制执行特定语言的格式化或 linter 偏好。遵循项目的风格工具。
- 替代测试。整洁代码通过测试;没有整洁代码测试不会通过,但没有测试的整洁代码也是缺陷。





