Spec Driven Development
MCP Server that facilitates spec-driven development workflows, not just Vibe Coding.
作者提供的说明(英文原文)
Twelve tools to inspect CRAP scores, find work, and check edited functions against their ceiling.
这三项永远不会合并成一个分数:意见、测量和人气是不同的东西。
我们还没有为它写通俗的介绍。下面是我们从注册中心读取到的事实。
选择你使用的 AI 应用,然后复制设置。
你需要
你用的是哪个应用?
在上方选择你的应用。我们会记住它,下次按钮会显示“安装到 …”。
打开 Claude Desktop → Settings → Developer → Edit Config,把下面的内容粘贴到 claude_desktop_config.json
{
"mcpServers": {
"crapkit": {
"command": "uvx",
"args": [
"crapkit",
"mcp"
]
}
}
}在终端中运行这条命令
claude mcp add crapkit -- uvx crapkit mcp粘贴到项目中的 .cursor/mcp.json,或 ~/.cursor/mcp.json
{
"mcpServers": {
"crapkit": {
"command": "uvx",
"args": [
"crapkit",
"mcp"
]
}
}
}浏览器会先询问是否打开应用,然后应用会显示设置并请你确认。密钥的值会留空,由你自己填写。
粘贴到项目中的 .vscode/mcp.json
{
"servers": {
"crapkit": {
"type": "stdio",
"command": "uvx",
"args": [
"crapkit",
"mcp"
]
}
}
}浏览器会先询问是否打开应用,然后应用会显示设置并请你确认。密钥的值会留空,由你自己填写。
这个服务器在你的电脑上运行,而 ChatGPT 只能连接互联网上的服务器。请选择其他应用。
你的选择通过 Cookie 保存在这台设备上,无需账户。
这些设置是根据作者在注册中心的条目生成的。如果 README 的写法不同,请以 README 为准。
它在你的电脑上运行;安装后,工具列表会显示在你的 AI 应用中。
我们检查的是任何人都能看到的信息;我们没有阅读代码。不适用的检查项不计入总数。 · 检查于 2026年11月8日
注册名称已通过 GitHub 账户 JeanFrancoisGagne 验证,该账户拥有此仓库
我们还没有从 GitHub 读取这个仓库
我们还没有从 GitHub 读取这个仓库
它在你的电脑上运行,没有互联网端点
在你的电脑上运行,改用本地设置
它在你的电脑上运行;我们只能读取互联网端点的工具列表
与注册中心里这个分类中所有活跃的服务器比较。只有当发布者拥有该仓库时,星标数才计入。
它在 1 项适用的基础检查中通过了 1 项。我们没有阅读代码。在添加密钥或令牌之前,请先看看这个服务器要求哪些权限,并使用只具备所需权限的密钥。
注册中心没有列出必需的密钥,不过有些服务器会在首次使用时要求你登录。
它在你的电脑上运行。你的 AI 应用会在需要时启动它,数据不会经过作者的服务器(除非它自己调用在线服务)。
GitHub 仓库最后更新于–,最新版本(0.8.1)于38天前进入注册中心。
支持 MCP 的应用,例如 Claude Desktop、Claude Code、Cursor 和 VS Code。你的电脑上还需要有 Python (uv)。
同一分类中有:Spec Driven Development, Remote Desktop Commander, Readfirst
同一分类中其他作者的服务器,按星标数排序。
如何看卡片:↓ 每周下载量i★ GitHub 星标i三大支柱:评价 · 检查 · 使用情况i更新 = 最新版本发布到注册中心的时间i
MCP Server that facilitates spec-driven development workflows, not just Vibe Coding.
Remote Desktop Commander: use files, terminal and processes on your own computers from any AI app.
What to read and check before changing a file: project rules, risks, checks and tests per file.
按原文从作者的仓库复制。PopNx MCP 没有审查或背书其内容。HTML、图片和脚本已被移除。链接会离开本站。
crapkit scores every function in your repo on complexity times uncovered risk, ranks the worst ones by how often the file changes, and blocks commits that add more. It reads Python, TypeScript, TSX, JavaScript, Swift, Go, Rust, shell, PowerShell, C and C++, Objective-C, Vue, Java and Zig through lizard, and joins per-function branch coverage from the istanbul or coverage.py artifact your own test command already writes. JSON commands use sorted keys and a versioned schema for scripts, coding agents and the optional MCP server.
CRAP = ccn^2 * (1 - cov)^3 + ccn
The name is not ours: C.R.A.P. (Change Risk Anti-Patterns) was coined for crap4j by Alberto Savoia and Bob Evans in 2007.
ccn is the smaller of standard and modified cyclomatic complexity, both read off one lizard pass. cov is branch coverage inside the function's span; with no branches it falls back to statement coverage, and with no statements to invoked-or-not, so a half-executed straight-line function never reads as fully covered.
Above the ceiling, coverage cannot save you. Decompose. At the default ceiling of 6, a function at ccn 7 with 100% coverage still scores 7 and still fails the gate. The only move that clears it is splitting the function.
Why 6 and not 30. crap4j's conventional threshold of 30 is a CRAP score: it lets an untested ccn 5 through (25 + 5 = 30) and a fully covered ccn 30 too. crapkit's default is a complexity ceiling, because coverage can at best collapse CRAP to ccn, and a function you cannot cover past ccn 6 is one you decompose. Set target = 30 in crapkit.toml if you want the crap4j number. A repo with existing debt does not need to: ratchet seed marks today's over-ceiling functions at today's score, the gate then judges only the functions a change touches, and marks may only fall, so adoption never starts with a wall of red. Next to crap4py, radon, xenon, wily and SonarQube: docs/comparison.md.
crapkit scores git-tracked files only. Source you have not git added is invisible to it; init and verify name the first three such files they find.
| Start with | When |
|---|---|
| Install and the 60-second start | You want the first score in an existing Git repository. |
| Python or TypeScript quickstart | You want a worked example from setup through a passing verify. |
| Adoption | You need to choose scopes, wire tests or introduce a ratchet to existing debt. |
| Upgrading | You already have saved runs, ratchet marks or an installed plugin. |
| Subcommands and JSON/MCP reference | You are scripting commands or connecting a coding agent. |
pip install crapkit
cd your-repo crapkit init # write crapkit.toml and ignore measurement output crapkit doctor # check scopes, test commands and coverage dependencies crapkit coverage # runs the lane, joins coverage, stores a scored run crapkit worklist # the ranked risk map crapkit ratchet seed git add crapkit.toml crapkit-ratchet.tsv .gitignore git commit -m "adopt crapkit" crapkit verify # the first passing verdict
Not a Python repo? uvx crapkit init runs the same commands and adds nothing to your manifest: see A repo that is not Python. A Python repo skips uvx and installs crapkit as above, or with uv tool install or pipx install; that section says why. pip stops with externally-managed-environment? See When pip refuses.
coverage measures a commit, so a fresh git init repo needs its first commit before it. Until then it exits 4 and says so:
$ crapkit coverage
crapkit: the git repository at /repo has no commit yet: crapkit measures a commit, so make the first one (git add, then git commit) and run it again
init detects pytest, Vitest and Jest from the repository's own files. Review the generated config before running its commands. When detection leaves a commented lane, fill it in using the lane recipes. Commit the adoption files, then run crapkit verify to establish a passing verdict. Install the commit gate when the config and ratchet are ready. Each step prints the next one: init names coverage, coverage names worklist, worklist names ratchet seed, and ratchet seed names the commit and verify.
coverage scores, worklist ranks:
$ crapkit coverage
run 1 @ fae4db93108: 2 functions scored: 2 measured, 1 over ceiling 6, CRAP load 41.0, grade F -> next: crapkit worklist
$ crapkit worklist worklist @ fae4db93108 (run 1, floor ccn>=5, churn 12mo) - 1 of 1 active (worklist_top 50), 0 dormant risk 14.0 ccn 14 crap 38.5 cov 50% 1c/1a calc/grade.py:7 classify( score , attempts , late , bonus ) no crapkit-ratchet.tsv yet: seed marks each function over its ceiling at today's score, and from then on a mark may only fall -> next: crapkit ratchet seed
risk 14.0 is ccn times a churn weight of one: a one-commit repo has no spread of commits to weight, so each commit counts once and the ranking is complexity order until the history grows (Risk). crap 38.5 and cov 50% are the score and the coverage behind it.
ratchet seed signs today's debt at today's score. From then on marks only ever fall, so the repo can get better and never worse while you burn it down.
One thing stops most first runs: the coverage plugin. init writes a lane that shells out to your own test runner, and the runner needs its coverage package installed: pytest-cov for pytest, @vitest/coverage-v8 (pinned to your vitest major) for vitest. Without it the lane produces no artifact and coverage exits 5 quoting the runner's own error. A pytest lane also needs coverage.py 7.13.1 or newer, which writes the function start lines crapkit reads; an older one fails the lane at exit 5. For pytest, init probes the python its lane will run and prints the install command when pytest_cov is missing; pip install "crapkit[py]" pulls the plugin alongside crapkit when the two share a venv. On a Windows PATH holding only the py launcher it writes py, not a python3 the lane could never run, and when cmd.exe cannot start the interpreter at all (exit 9009, the Store alias) it names that instead of guessing at pytest-cov. A repo that pins no lockfile and carries its own .venv gets that venv's interpreter in the lane, when that interpreter can import pytest, rather than whichever python the shell answers with. The two quickstarts below walk a real repo end to end.
On Windows a lane command is read by cmd.exe, the shell that will run it, not by sh. Double quotes are the portable quoting. A single-quoted value is refused at config load with exit 3, because cmd.exe would hand pytest five words and the lane would write no artifact:
# the lane in crapkit.toml
command = "python -m pytest -m 'not live and not perf' --cov=calc --cov-branch --cov-report=json:.crapkit/cov/py.json"
$ crapkit doctor crapkit: lane 'py': positional argument 'live' narrows a full-suite coverage run; drop it, attach it to the flag it belongs to (-n8, --numprocesses=8), or set full_suite = false deliberately (cmd.exe does not treat ' as a quote: write the value in double quotes); a suite whose testpaths cannot be collected in one process needs one lane per testpath, each with full_suite = false and its own artifact
Write it -m "not live and not perf". Carets, && and | segments, redirections and empty quoted arguments all read the way the shell reads them, so a chained lane (cd tests && python -m pytest --cov ...) is checked one segment at a time. doctor reads a lane the same way, and FAILs one whose runner will not start.
pip install crapkit
That is the release on PyPI. For the unreleased tip of main, or from a local clone (run at the clone root):
pip install git+https://github.com/JeanFrancoisGagne/crapkit.git
pip install .
Commits on main between two releases carry the same version string, and pip keeps an installed crapkit whose version matches, so running the git line again after a new commit leaves the old code in place. This line replaces it with the tip:
pip install --force-reinstall --no-deps git+https://github.com/JeanFrancoisGagne/crapkit.git
pip install . in a clone rebuilds on every run and needs no flag.
Debian 12, Ubuntu 23.04 and later, Homebrew and uv mark the Python they install as theirs (PEP 668), and pip refuses to write into it with error: externally-managed-environment:
$ pip install crapkit
error: externally-managed-environment
Give crapkit an environment of its own. Either line installs it into one and puts a crapkit command in ~/.local/bin (%USERPROFILE%\.local\bin on Windows), the command the agent plugins start:
pipx install crapkit
uv tool install crapkit
When that directory is not on PATH yet, the installer says so and names the fix: pipx ensurepath, or uv tool update-shell. Open a new shell after either. The python on PATH does not hold this install, and the commit hook runs the crapkit command before it tries python, so it reaches either install as printed.
A Python repo can carry crapkit in its own venv instead, beside the test dependencies its lane runs:
python3 -m venv .venv
. .venv/bin/activate pip install "crapkit[py]"
The same from cmd.exe on Windows:
python -m venv .venv
.venv\Scripts\activate pip install "crapkit[py]"
--break-system-packages makes pip write into the system Python anyway, where the next OS package update can break crapkit or the OS's own tools. None of the routes above needs it.
crapkit is a command-line tool, never a dependency of the code it scores. A TypeScript, Go or Rust repo adds nothing to its own manifest. With uv on the machine, uvx fetches crapkit into a cache of its own and runs it:
$ uvx crapkit init
wrote crapkit.toml with 1 scope(s): src detected 1 lane(s) from this repo's own files: js - next: run uvx crapkit coverage added to .gitignore: .crapkit/
$ uvx crapkit coverage $ uvx crapkit worklist
uvx puts no crapkit on PATH, so every next step crapkit prints under uvx starts with uvx crapkit. The lane still runs your own test runner, so Vitest or Jest and its coverage package come from the repo's node_modules as t
只显示了开头部分;其余内容请在仓库中阅读