关于 abcop
abcop 是面向 AI 编写代码和开发团队的独立代码复杂度检查器,可在多种语言中限制函数和模块的 ABC 复杂度,并提供可执行的诊断信息及供 Agent 工作流使用的 MCP 检查工具。
主要功能
- 01限制函数和模块的 ABC 复杂度
- 02用单个二进制文件分析多种语言
- 03输出文本、JSON 或 JSONL 诊断
- 04聚焦扫描变更代码
- 05标记仅使用一次和未使用的局部变量
- 06提供 MCP 检查工具
适用场景
- 01在 CI 中加入复杂度检查
- 02审查代码修改带来的复杂度
- 03为 Agent 提供具体重构线索
- 04在 Agent 编辑时检查代码指标
MCP 相关
运行 `abcop --mcp` 可通过 stdio 提供 MCP 服务。其 `abcop_inspection` 工具向 AI 客户端返回检查结果。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
abcop
AI 生成代码的必备关卡。 Agent 的交付速度比人类重新审阅代码的速度更快;abcop 通过限制函数和模块的 ABC 复杂度,确保每个单元都能装进人类的脑海和 LLM 上下文窗口,让代码始终易于理解。诊断结果也是自动重构的切入点——提取方法、拆分模块——因此 CI 不仅会拒绝糟糕的代码增长,还会为 Agent 指明具体的可维护性改进方向。
一个独立二进制即可支持 Ruby、Rust、Python、Go、PHP、Java、C#、 Dart、JavaScript、TypeScript、C、C++、Objective-C、Swift、Solidity、Zig 和 Haskell — 无需运行时、无需插件,也无需为每种语言单独安装。使用 Rust 编写,速度快:每个文件只解析一次,每项指标只遍历一次,语法均已编译; 整个代码树只需几毫秒。
安装
brew install adrianov/abcop/abcop
cargo install abcop
macOS(从 GitHub Releases 下载 .tar.gz;包含二进制文件和 man 手册):
# Apple Silicon — use the *-x86_64-apple-darwin.tar.gz asset on Intel Macs
curl -LO https://github.com/adrianov/abcop/releases/download/v0.23.0/abcop-0.23.0-aarch64-apple-darwin.tar.gz
tar -xzf abcop-0.23.0-aarch64-apple-darwin.tar.gz
sudo cp abcop-0.23.0-aarch64-apple-darwin/abcop /usr/local/bin/
sudo mkdir -p /usr/local/share/man/man1
sudo cp abcop-0.23.0-aarch64-apple-darwin/abcop.1 /usr/local/share/man/man1/
Ubuntu / Debian(从 GitHub Releases 下载 .deb;支持 amd64、Ubuntu 22.04+ / Debian bookworm+):
# example for v0.23.0 — use the asset name from the release page
curl -LO https://github.com/adrianov/abcop/releases/download/v0.23.0/abcop_0.23.0-1_amd64.deb
sudo dpkg -i abcop_0.23.0-1_amd64.deb
man abcop
运行示例
lib/sinatra/base.rb:1254:0: C: Metrics/AbcSize: Assignment Branch Condition size for `error_block!` is too high. [<7, 14, 9> 18.06/17]
src/main.rs: W: Metrics/ModuleAbcSize: Assignment Branch Condition size for module is too high. [<80, 200, 60> 228.04/120] -- extract a coherent subunit
132 files analysed in 0.09s, 7 abc offenses, 0 used-once offenses, 0 never-used warnings, 14 module-abc warnings
为什么选择 ABC,而不是行数
行数会骗人。ABC 指标
(Jerry Fitzpatrick,C++ Report,1997 年 6 月)统计实际工作量 —
赋值(A)、分支(B)、条件(C)— 公式为 sqrt(A² + B² + C²)。
Fitzpatrick 定义了方法和模块两个范围;abcop 对两者都进行限制:
| 规则 | 严重程度 | 含义 |
|---|---|---|
Metrics/AbcSize | C | 函数 ABC 超过 --max-abc(默认值为 17)。常规扫描会报告相较于 HEAD 的增长;--full 和 --everything 会报告所有超过上限的函数 |
Metrics/ModuleAbcSize | W | 模块 ABC 超过 --max-module-abc(默认值为 120)。常规扫描会报告相较于 HEAD 的增长;--full 和 --everything 会报告所有超过上限的生产模块 |
UsedOnce | W | 在本次编辑所更改的函数中,局部变量只写入一次、读取一次。--full 和 --everything 会报告所有此类局部变量 |
NeverUsed | W | 在本次编辑所更改的函数中,局部变量已写入但从未读取。与 UsedOnce 使用相同的全代码树扫描开关 |
稀疏的包装器和密集的上帝对象可能行数相同;ABC 能将它们区分开来。复杂度才是关卡 — 绝不是行数预算。UsedOnce / NeverUsed 是次要指标。
为 AI 工作流而打造
- 从设计上易于理解。 AbcSize 17 和 ModuleAbcSize 120 让每个新单元都能装进人的脑海和大模型的上下文窗口。如果修改没有提高分数,现有单元可以继续超过此上限。模型能够可靠地修改小单元;出现问题时,影响范围也很小。
- 重构钩子。 退出代码
1加上稳定的 JSON/JSONL 诊断信息(rule、score、vector、message),可供 Agent 和脚本使用:拆分过大的模块,提取热点方法。每条发现都对应一项可执行的可维护性改进,而不是风格上的吹毛求疵。 - 快到每次推送都能运行。 全树扫描只需不到一秒——包括 Agent 明天绝不会重新读取的代码。
- 只提供有效信号。 不做格式或风格检查。默认跳过第三方、生成和测试目录。可调参数:
--max-abc和--max-module-abc。--full和--everything会报告所有问题,而不只是当前修改。 - 使用 MCP 配合大模型。
abcop --mcp是从 Agent 使用 abcop 的最佳方式:模型写入代码后即可获得违规信息,因此能在同一轮中修复复杂度问题和未使用的局部变量,并立即交付有效代码——无需等到之后的 CLI/CI 检查。官方 RustrmcpSDK;工具abcop_inspection。已在 MCP Registry 登记为io.github.adrianov/abcop(crates.io 软件包及每个 GitHubv*标签)。
灵感来自 RuboCop(Ruby AbcSize 的一致性,以及 # rubocop:disable 指令)和 lizard(一个工具,多种语言)。Ruby 方法计数与 RuboCop 1.89 逐字节一致(scripts/compare_parity.py)。方法外的代码块(match do、before do、类级别的 each)会作为独立单元;each / map / select 仍计入包含它们的代码块。
优势
- 约 850k–940k LOC/s(每核心,Apple M1 Pro)。RuboCop 的 lib 树(943 个文件,110k LOC):0.13 s——比
rubocop --only Metrics/AbcSize(关闭缓存)快约 39 倍,比完整的 rubocop 运行快约 140 倍。 - 一个二进制文件,零依赖——语法解析器和内嵌的结果缓存(
cache.redb)均已编译其中;在没有语言工具链的干净 CI 镜像上也能运行。 - 结果确定——每次运行的发现结果相同;文件处理完成后即以文本 / JSON / JSONL 流式输出;
--sort-by-score会缓冲结果,按分数从高到低输出。
用法
abcop [OPTIONS] PATH...
| 选项 | 默认值 | 含义 |
|---|---|---|
[PATH]... | 自动 | 目标;省略时 → 范围选择 |
--max-abc N | 17 | 函数 ABC 上限 |
--max-module-abc N | 120 | 模块 ABC 上限 |
--only abc|used-once|never-used | 全部 | 仅检查一项 |
--full | 关闭 | 整个生产代码树,以及所有超过上限的函数和每个局部变量(仍默认跳过相应内容) |
--everything | 关闭 | 不按 gitignore / 隐藏 / 第三方规则筛选(用户配置中的 ignore 仍然适用);报告范围与 --full 相同 |
--format text|json|jsonl | text | 适用于 CI 的输出 |
--sort-by-score | 关闭 | 按 ABC 分数从高到低排列 |
--mr | 关闭 | MR 范围(未提交内容 + 分支与基准的差异) |
--uncommitted | 关闭 | 仅比较工作树 + 索引 + 未跟踪文件与 HEAD |
--no-cache | 关闭 | 跳过磁盘缓存 |
--mcp | 关闭 | 通过 stdio 启动 MCP 服务(供 AI 客户端使用) |
--dump-tree FILE | — | 调试语法树 |
退出代码:0 表示无问题,1 表示发现问题,2 表示用法错误。
abcop app lib # two trees; rises and edited functions only
abcop --format jsonl lib > abcop.jsonl # streaming CI / agent input
abcop --only used-once src # inline candidates in edited functions
abcop --max-abc 12 --only abc lib # stricter function budget
abcop --full lib # every function over the ceiling, every local
abcop --everything lib # same report, with no default pruning
abcop --max-module-abc 80 lib # stricter module budget
abcop --sort-by-score --only abc lib # worst first
abcop --uncommitted # pre-commit; rises and edited functions only
abcop --mr --only abc # branch files; still only ABC rises vs HEAD
abcop --mcp # MCP server on stdio (for AI clients)
JSON 诊断信息包括 file、line、column、severity、rule、message,以及 ABC 规则对应的 score / vector:
{"rule":"Metrics/AbcSize","score":10.0,"vector":"<6, 8, 0>"}
{"rule":"Metrics/ModuleAbcSize","score":120.5,"vector":"<40, 100, 40>"}
范围选择
指定路径 — 仅扫描这些目标。发现项仍遵循下方的编辑筛选规则。
未指定 — 使用最窄的有效范围,并在 stderr 上说明:
- 如果工作树有改动,则检查未提交的工作与
HEAD的差异 - 否则检查当前 MR(
--mr可强制使用此范围) - 否则检查整个工作树(在仓库外)
默认遍历会跳过测试/fixture 目录、供应商/构建输出目录
(vendor/、node_modules/、target/ 等)、db/migrate/、路由表
(config/routes.rb、config/routes/*.rb)以及生成文件名
(*.min.js、*_pb.go 等)。显式指定路径即可扫描这些内容。
Rails schema dump 文件(db/schema.rb、db/*_schema.rb、
db/schema_*.rb)无论是否显式指定都不会扫描。
第三方代码、路由表和 fixture 路径永远不属于审查范围——即使
vendor/ 或 tests/fixtures/ 中的差异也不会让这些内容变成自有代码。
在工作树有改动时,裸默认范围仅包含未提交内容;--mr 则检查
整个分支并集。直接提交到 main 的提交在没有适用分支基准时使用
36 小时的时间窗口。在仓库外使用 --uncommitted 会报错,而不会
悄悄扩大范围。
常规扫描的报告内容
除 --full 和 --everything 外,每次扫描都会将工作树与
HEAD 进行比较:
- AbcSize 仅当某个方法的分数严格高于
HEAD中同名方法 (按源码顺序)时,才会报告其分数超过--max-abc的情况。 分数持平或下降时不会报告,包括已经超过上限的遗留方法。 仅存在于工作树中的方法视为分数上升。如果HEAD中的分数已经 超过上限,消息会要求恢复到之前的分数(rose from 20 to 21 -- back to 20 or below)。 如果HEAD中的分数低于上限,目标则是上限 (rose from 16.28 to 21.28 -- back to 17 or below)。 - UsedOnce / NeverUsed 仅在文本相对于
HEAD有改动的函数内报告。 编辑未触及的函数中的局部变量不会报告。任何函数之外的局部变量仍会报告。 - ModuleAbcSize 仅当某个模块的整文件分数严格高于
HEAD中 对应文件时,才会报告其分数超过--max-module-abc的情况。 分数持平或下降时不会报告,包括已经超过上限的遗留模块。HEAD中不存在的文件须符合上限要求。如果HEAD中的分数已经 超过上限,消息会要求恢复到之前的分数 (rose from 200 to 210 -- back to 200 or below)。如果HEAD中的分数低于上限,目标则是上限。 - 没有
HEADblob(不是 git 检出,或文件尚未跟踪)时,会报告 所有超过上限的方法、所有局部变量,以及所有超过上限的模块。
--uncommitted 和 --mr 还会忽略差异未触及行上的函数和局部变量发现项。
全工作树报告
--full 和 --everything 会报告所有超过 --max-abc 的方法、
所有局部变量,以及所有超过 --max-module-abc 的生产模块。在这类
运行中,ModuleAbcSize 仍会跳过测试目录。--full 保留默认跳过项。
--everything 会取消 gitignore、隐藏目录以及供应商/生成文件/测试
内容的跳过规则。用户配置中的 ignore 仍适用于两者。
用户配置
用户选项存放在一个文件中。如果设置了 $XDG_CONFIG_HOME,文件路径为
$XDG_CONFIG_HOME/abcop;否则为 ~/.config/abcop。$ABCOP_CONFIG
会替换该路径。项目中不会写入任何内容。
ignore 使用 gitignore 模式,每行一个选项,并在每个项目中相对于该
项目根目录应用。目录模式会匹配其中的所有内容。指定路径、--full
和 --everything 都不会重新纳入匹配项。对匹配路径进行 MCP 检查时,
结果为空。
ignore = app/services/legacy/
ignore = lib/old.rb
指令
除 Rust 外,所有语言都支持 RuboCop 风格的 # / // 抑制指令
(行尾和块注释均可;允许单独使用 Metrics)。与 rubocop 一致,
rubocop:disable-next 会被忽略。
def legacy_path # rubocop:disable Metrics/AbcSize
...
end
MCP(Model Context Protocol)
适用于大模型 / Agent 工作流。 将 abcop 接入为 MCP 服务,让模型在编辑时调用 abcop_inspection:在同一轮中收到反馈,Agent 很快就能修正,并在首次编写时就产出易维护的代码,而不是等到 CI 中才发现 ABC / UsedOnce / NeverUsed 问题。
abcop --mcp 会通过 stdio 启动一个长驻 MCP 服务——理念与 RuboCop 的 MCP 和 rrubocop 相同,且无需 Ruby mcp gem。工具:
| 工具 | 用途 |
|---|---|
abcop_inspection | 通过 path / paths(字符串或数组)和/或内联 source_code 进行分析;返回精简的违规项 JSON(code、line、column、message;ABC 规则还包含 score / vector)。使用与常规扫描相同的编辑筛选条件:只有当 AbcSize 和 ModuleAbcSize 分数相较于 HEAD 上升时才检查;UsedOnce 和 NeverUsed 只在编辑改动过的函数中检查。新模块按模块上限进行检查。始终传入明确的项目路径——省略目标会报错(避免 MCP cwd 设置有误时扫描 $HOME)。 |
- MCP Registry 名称:
mcp-name: io.github.adrianov/abcop
元数据位于 server.json 中,该文件包含在 crates.io 上的 Cargo 包内。每个 GitHub v* 发布标签都会在上传至 crates.io 后,将该条目发布到 MCP Registry。
客户端配置示例(Cursor / VS Code / Windsurf):
{
"mcpServers": {
"abcop": {
"type": "stdio",
"command": "abcop",
"args": ["--mcp"],
"cwd": "/path/to/your/project"
}
}
}
Claude Code:
claude mcp add abcop -- abcop --mcp
用于 MCP 客户端,不用于交互式操作。
缓存
基于内容寻址的缓存位于 $XDG_CACHE_HOME/abcop(或 ~/.cache/abcop;可通过 ABCOP_CACHE_DIR 覆盖)。缓存预热后,重复运行速度约快 5 倍。键涵盖内容、版本、规则修订、阈值、检查项和路径——不同项目之间不会发生冲突。自动清理至 20 000 个条目;--no-cache 可禁用缓存。项目内部不会写入任何内容。
支持的语言
支持 17 种语言,以及 HTML / 模板中的嵌入式 JS;每种语言支持 4 条规则,共用一个 CI 门禁。
| 语言 | 文件 | 备注 |
|---|---|---|
| Ruby | .rb .rake .ru .gemspec、Gemfile、Rakefile、…… | 与 RuboCop 行为一致的方法 AbcSize;方法外的块作为独立单元 |
| Rust | .rs | |
| Python | .py .pyi .pyw | |
| Go | .go | |
| PHP | .php | |
| Java | .java | |
| C# | .cs | |
| Solidity | .sol | |
| Dart | .dart | |
| Zig | .zig | |
| Haskell | .hs .lhs | |
| JavaScript | .js .mjs .cjs .jsx | 也支持 HTML / 模板中的 <script> |
| TypeScript | .ts .tsx .mts .cts | lang="ts" / typescript 脚本类型 |
| 嵌入式 JS | .html .htm .xhtml .erb .slim .haml .pug .vue .svelte .ejs .njk .jinja .j2 .twig .liquid .hbs …、*.js.erb | 提取脚本;将 <% %>、{{ }}、{% %} 占位片段留空 |
| C / C++ | .c .h .cc .cpp .cxx .hpp .hxx .hh | .h 使用 C++ 语法 |
| Objective-C | .m .mm | |
| Swift | .swift |
具名声明作为测量单元;匿名函数类结构计入其外层单元;嵌套单元不会重复计数。C 系列语言:单文件分析无法触及文件作用域的全局变量;循环头部的局部变量遵循协议规则;字段写入也会读取对象;导出宏类形式(class UTIL_EXPORT Foo)不参与变量规则检查。
基准测试
Apple M1 Pro,缓存预热后:
| 代码库 | 规模 | abcop | rubocop --only AbcSize¹ | 完整 rubocop |
|---|---|---|---|---|
| rubocop/lib | 943 个文件,110k LOC | 0.13 s | 5.1 s(约 39 倍) | 18.3 s |
| cargo registry 样本 | 6,603 个文件,2.6M LOC | 约 2.8 s | — | — |
¹ --cache false——否则 rubocop 自带的缓存会让重复运行看起来无需耗时。
开发
cargo test
cargo build --all-targets # zero warnings
abcop src # dogfood
共享引擎:src/scope_model/(backend、walk、eval);语言收集器位于各自后端旁(clike/、sollang/、……)。使用 abcop --dump-tree FILE 探查语法节点。行为一致性:
scripts/compare_parity.py。
许可证
GNU GPL v3 或更高版本(SPDX:GPL-3.0-or-later)。请参阅 LICENSE。
版权所有 © 2026 Peter Adrianov。保留所有权利。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。