vibe-debt
v0.1.0
Published
Measure the AI-flavor of your codebase. Zero-config CLI that scores vibe-coded tech debt 0-100 and mints a README badge.
Maintainers
Readme
vibe-debt
How much of your codebase was typed by a machine?
vibe-debt measures the AI flavor of any repository — the particular brand of code debt that LLM-generated code leaves behind: swallowed errors, phantom imports, result2, comments that restate the code, and helpers pasted six times. It runs with zero config, scores you 0–100 with an A–F grade, and hands you a README badge to brag (or weep) with.
npx vibe-debtNo install. No config. No account. It finishes a 15,000-line repo in about 0.2 seconds.
Sample output
vibe-debt · ~/projects/afternoon-of-vibe-coding
3 files scanned · 0.1 kloc of real code
◉ 100 /100 ██████████ F — the agent wrote this alone
Rule breakdown
● llm-slop 5 ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮
● silent-catch 4 ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮
● hallucinated-deps 3 ▮▮▮▮▮▮▮▮▮▮
● phantom-abstractions 2 ▮▮▮▮▮▮▮▮▮
● comment-restating 2 ▮▮▮▮▮▮▮▮▮
● defensive-bloat 2 ▮▮▮▮▮▮▮▮▮
● dead-code 1 ▮▮▮
● debug-logs 1 ▮▮▮
● generic-names 1 ▮▮▮
Top offenders
16 × src/userRouter.ts
3 × src/pipeline.py
2 × src/orderRouter.tsThe grades
| Grade | Score | Verdict | |:---:|:---:|---| | A | 0–14 | human-grade | | B | 15–34 | mostly clean | | C | 35–54 | ai-flavored | | D | 55–74 | vibe-coded | | F | 75–100 | the agent wrote this alone |
Is the score honest? Calibrate it against real code.
vibe-debt was tuned against mature, human-written open-source projects — not against vibes ( pun intended ):
| Repository | Language | Score | Grade | |---|---|:---:|:---:| | expressjs/express | JS | 7 | A | | pallets/flask | Python | 21 | B | | gin-gonic/gin | Go | 27 | B | | vibe-debt, scanning itself | TS | 0 | A | | an AI-generated slop project | TS+Py | 100 | F |
It also declines to flag things humans do on purpose: Go doc-comment conventions, deliberate exception handling in tests, try/except ImportError shims. False positives on good code are how a tool like this dies, so every rule has a negative-test suite.
What it detects — 12 rules
Run npx vibe-debt explain <rule> for details on any of them.
| Rule | Severity | What it catches |
|---|:---:|---|
| silent-catch | high | catch {} that swallows failures — wrap everything, report nothing |
| hallucinated-deps | high | imports of packages that exist in no package.json / requirements.txt — the model invented them |
| dead-code | medium | statements after return/throw — leftovers from in-function refactors |
| giant-function | medium | functions over 150 lines; the 400-line doEverything handler |
| copy-paste | medium | identical 6-line blocks repeated across files — regurgitation, not reuse |
| phantom-abstractions | medium | unused interfaces and single-purpose Manager/Handler/Wrapper scaffolding |
| comment-restating | low | // increment counter above counter++ |
| llm-slop | low | "in a real app…", "certainly!", emoji logs — fingerprints of model output |
| debug-logs | low | console.log/print density of a debug session that shipped |
| generic-names | low | result, result2, handleData2 — the digit-append naming strategy |
| defensive-bloat | low | !== null && !== undefined, JSON round-trip deep clones, === true |
| comment-flood | low | files where comments outnumber code — JSDoc on every one-line getter |
Languages: TypeScript, JavaScript, Python, Go, Rust, Java, PHP, C#, Ruby. Monorepos work: nested package.json manifests are resolved per-directory, and .gitignore is respected.
Usage
npx vibe-debt # score the current directory
npx vibe-debt path/to/repo # score somewhere else
npx vibe-debt -v # every finding, grouped by rule
npx vibe-debt --json # machine-readable report
npx vibe-debt --badge badge.svg # write a shields-style SVG
npx vibe-debt --fail-on C # exit 1 if grade is C or worse (or --fail-on 40)
npx vibe-debt explain # list all rules
npx vibe-debt grade ./repo # just the letter gradeCI gate
- name: Don't ship pure vibes
uses: xuange-hu/vibe-debt@v1
with:
fail-on: 'C' # fail the build at grade C or worse
badge: .github/vibe-debt.svgOr with a plain script step: npx vibe-debt . --fail-on 40.
Badge
npx vibe-debt --badge .github/vibe-debt.svgThe color scales from green (grade A) to red (F), because a badge you're ashamed of is a badge people notice.
Silence a line
The tool is a heuristic, and heuristics make mistakes. When it's wrong:
do { x() } while (!x) // vibe-debt-ignore defensive-bloat// vibe-debt-ignore [rule,rule]— suppress on this line// vibe-debt-ignore-next-line rule— suppress on the next line- Works in every supported language (any comment style), including
#for Python
How scoring works
Each finding contributes weight × severity × confidence. The total penalty is normalized by √kloc (so a 200-line script isn't executed for having one bad function) and pushed through a saturating curve:
score = 100 × (1 − e^(−penalty / √kloc / 12))Density, not volume: a small file that is pure slop scores higher than a big repo with a few problems. Grade bands are tuned so that mature human-written OSS lands in A–B and agent-only codebases land in F.
vibe-debt is not a linter. It will not tell you your code is wrong — ESLint and your type checker have that job. It tells you what fraction of it reads like it was never actually read by a human.
Development
npm ci
npm run build # tsup → dist/index.js
npm test # vitest: 39 rule + calibration + badge tests
npm run typecheckAdding a rule is one file in src/rules/ plus a registry entry — see src/rules/define.ts.
Star history rationale, in one paragraph
Half of the code written in 2026 was typed by something that has never run it. We have tools for bugs, and tools for style, but no mirror for this. If vibe-debt makes one maintainer paste a grade onto their README and one junior notice their router scored an F — it did its job.
License
MIT
