本节摘要:规则告诉 OCR 评审每个文件时应关注什么。本节讲两件事:一是规则的四层优先级链(
--rule参数 → 项目rule.json→ 全局rule.json→ 内嵌系统规则),以及规则文件include/exclude/rules三个字段的语义;二是文件的五重门过滤算法(binary → user_exclude → user_include → unsupported_ext → default_path),决定哪些文件最终进入评审。读完你能用ocr rules check排查「为什么我的规则没触发」和「为什么我的文件没被评审」这两类高频问题。
内容来源:原项目中文文档
pages/src/content/docs/zh/review-rules.md,套用体系化模板改写。
阅读完本节,你应当能够:
include/exclude/rules 的项目级规则文件。**、{a,b}、?)编写匹配模式。ocr rules check 与 ocr review --preview 排查规则与过滤问题。OCR 用一条四层优先级链解析规则。对每个文件路径,按序尝试各层;第一个匹配的模式生效。
| 优先级 | 来源 | 路径 | 说明 |
|---|---|---|---|
| 1(最高) | --rule 参数 |
用户指定 | CLI 覆盖;只要提供就总是生效。 |
| 2 | 项目配置 | <repoDir>/.opencodereview/rule.json |
项目级规则——可安全提交。 |
| 3 | 全局配置 | ~/.opencodereview/rule.json |
用户级偏好。 |
| 4(最低) | 系统默认 | 内嵌 system_rules.json |
覆盖常见语言的内置规则。 |
💡 技巧:若更高优先级层的文件不存在,会被静默跳过——不是错误。因此从未添加
.opencodereview/rule.json的项目会直接落到全局 / 系统层。系统层始终存在(随二进制发布),因此总会解析出某个规则。
{ "include": ["src/**/*.{ts,tsx}", "src/**/*.go"], "exclude": ["**/*.test.ts", "**/generated/**"], "rules": [ { "path": "src/api/**/*.go", "rule": "All exported handlers must validate request bodies before use." }, { "path": "**/*mapper*.xml", "rule": "Check SQL for injection risks, parameter errors, and missing closing tags." } ] }
三个独立字段:
include——可选。glob 模式,用于绕过内置的默认排除模式(测试文件排除——见下文)。它不是白名单:不匹配任何 include 模式的文件仍会经过 unsupported_ext 和 default_path 检查,可能仍被评审。exclude——可选。OCR 不予评审的文件 glob 模式。过滤中优先级最高。rules——{path, rule} 条目数组,按声明顺序求值。第一个 path glob 匹配该文件的条目,决定 OCR 发给模型的 prompt。OCR 用 bmatcuk/doublestar/v4 做匹配:
*——匹配除 / 外的任意字符。**——跨目录边界匹配(src/**/*.go 覆盖任意深度)。{a,b,c}——花括号展开。*.{ts,tsx,js,jsx} 展开为四个模式并依次匹配。?——匹配单个字符。[abc]——字符类。⚠️ 注意:模式匹配不区分大小写(匹配前文件路径会被小写化)。不确定时用
ocr rules check <path>确认。花括号展开对空格敏感——{ts, tsx}(带空格)会静默地无法匹配tsx。
过滤是一个五重门算法。对每个 diff,OCR 依次问:
binary——文件是二进制吗?排除。user_exclude——路径匹配任何用户 exclude 模式吗?排除。user_include——若用户定义了 include,路径匹配吗?若是,立即保留(绕过下面的 unsupported_ext 和 default_path 门)。unsupported_ext——文件扩展名在白名单里吗?不在则排除。default_path——路径匹配某个内置测试文件排除模式(**/*_test.go、**/*.test.{js,jsx,ts,tsx}、**/*_spec.rb……)吗?排除。通过全部五重门的文件才发给 LLM。deleted 原因(不是门——它在 Preview() 中单独计算)标记新路径为 /dev/null 的文件;没有新内容可评审。
┌─────────────────────────────────────────────────────────────────┐ │ diff 文件 │ │ │ │ │ ▼ │ │ ① binary ──是──► 排除 │ │ │否 │ │ ▼ │ │ ② user_exclude ──是──► 排除 │ │ │否 │ │ ▼ │ │ ③ user_include ──匹配──► 立即保留(绕过 ④⑤) │ │ │不匹配 / 无 include │ │ ▼ │ │ ④ unsupported_ext ──不在白名单──► 排除 │ │ │在白名单 │ │ ▼ │ │ ⑤ default_path ──匹配测试模式──► 排除 │ │ │不匹配 │ │ ▼ │ │ 保留 → 发给 LLM │ └─────────────────────────────────────────────────────────────────┘
💡 技巧:用
ocr review --preview可在不花 token 的情况下打印此过滤结果,看到每个文件被保留或丢弃的原因。
内置排除列表匹配测试文件模式:
**/*_test.go**/src/test/java/**/*.java**/src/test/**/*.kt**/*.test.{js,jsx,ts,tsx}**/*.spec.{js,jsx,ts,tsx}**/__tests__/****/test/**/*_test.py、**/tests/**/*_test.py、**/*_test.py**/*_spec.rb、**/spec/**/*_spec.rb**/*Test.java、**/*Tests.java**/*_test.rs**/oh_modules/****/*.test.ets噪声目录过滤(vendor/、node_modules/、target/……)发生在更早的阶段,位于 diff 层,先于 per-file 过滤运行。
⚠️ 注意:要评审一个匹配这些测试文件模式的文件,把它加入用户
include列表——那会覆盖 default-path 门。
过滤决定某文件将被评审后,OCR 选择 agent 应遵循的规则文本:
--rule(custom)层。<repo>/.opencodereview/rule.json。~/.opencodereview/rule.json。内嵌 system_rules.json 自带这些模式(按序):
| 模式 | 规则文档 |
|---|---|
**/*.properties |
properties.md——i18n / 配置文件。 |
**/*{mapper,dao}*.xml |
mapper_dao_xml.md——MyBatis 风格 mapper SQL。 |
**/pom.xml |
pom_xml.md——Maven 依赖。 |
**/build.gradle |
build_gradle.md——Gradle 依赖。 |
**/package.json |
package_json.md——NPM 依赖 / 脚本。 |
**/Cargo.toml |
cargo_toml.md——Rust manifest。 |
**/*.{json,json5} |
json.md——通用 JSON(也匹配 .json5)。 |
.github/workflows/**/*.{yaml,yml} |
github_workflows.md——GitHub Actions 工作流 YAML。 |
.github/**/*.{yaml,yml} |
github_config.md——其他 .github 配置 YAML。 |
**/*.{yaml,yml} |
yaml.md |
**/*.java |
java.md |
**/*.{ftl,ftlh,ftlx} |
freemarker.md——FreeMarker 模板(SSTI / XSS / null 处理)。 |
**/*.ets |
arkts.md——ArkTS / HarmonyOS。 |
**/*.{ts,js,tsx,jsx} |
ts_js_tsx_jsx.md |
**/*.{kt} |
kotlin.md |
**/*.rs |
rust.md |
**/*.{cpp,cc,hpp} |
cpp.md |
**/*.c |
c.md |
| (fallback) | default.md |
解析出的规则正文成为 plan 和 main task prompt 中 {{system_rule}} 占位符的内容(模板与占位符详见本章架构一节)。
ocr rules check$ ocr rules check src/main/java/com/example/UserService.java File: src/main/java/com/example/UserService.java Source: System built-in Pattern: **/*.java Rule: ──────────────────────────────────────── …contents of java.md… ────────────────────────────────────────
$ ocr rules check --rule custom.json src/main/resources/mapper/UserMapper.xml File: src/main/resources/mapper/UserMapper.xml Source: Custom (--rule) Pattern: **/*mapper*.xml Rule: ──────────────────────────────────────── …contents of your custom rule… ────────────────────────────────────────
当某条规则未按预期生效时用它——它会显示生效的层与模式。若层不对(如期望项目规则却显示 System built-in),多半是声明顺序问题——首条匹配模式生效,把更具体的规则在 rules 数组里前移,或修正 glob。
保存为 <repo>/.opencodereview/rule.json 并提交:
{ "rules": [ { "path": "src/api/**/*.go", "rule": "Every public handler must `defer tx.Rollback()` immediately after starting a transaction." }, { "path": "**/*mapper*.xml", "rule": "Check SQL for injection risks, missing parameter binding, and unclosed XML tags." } ] }
{ "include": ["src/**/*.{ts,tsx,js,jsx}"], "exclude": ["**/*.gen.ts", "**/generated/**"] }
设置 include 后,src/ 内的文件即使本会被内置默认排除模式(如测试文件)剔除也会被保留。src/ 之外的文件仍走正常的 ext / default 检查——include 是绕过机制,不是白名单。
ocr review --rule ./.review-rules-only-for-this-pr.json
同时绕过项目层与全局层——当单个 PR 需要完全不同的评审清单(如仅安全评审)时很方便。
放到 ~/.opencodereview/rule.json,你机器上每个仓库都会继承:
{ "rules": [ { "path": "**/*.{ts,tsx,js,jsx}", "rule": "Always check for unhandled promise rejections; warn on `// eslint-disable` without a reason comment." } ] }
💡 技巧:这套项目级 + 全局级的分层与第 2 章的配置分层(
~/.opencodereview/config.json+<repo>/.opencodereview/)是一致的——可安全提交的项目文件放仓库,个人偏好放家目录。
--rule(最高)→ 项目 → 全局 → 系统(最低),首条匹配生效,系统层总在。include(绕过默认排除,非白名单)、exclude(最高优先级排除)、rules(按声明顺序求值的 {path, rule})。* / ** / {a,b} / ? / [abc],匹配不区分大小写,花括号对空格敏感。deleted 单独计算。default.md。ocr rules check <path> 看规则层,ocr review --preview 看过滤原因。include 即可覆盖 default-path 门。规则讲清了。下一节进入架构,看 OCR 从「按下回车」到「JSON 落在终端」的端到端流水线——规则文本如何嵌入 prompt、文件如何被并行评审、记忆如何被压缩。