Codebase Value Audit logo

Codebase Value Audit

Community
Innei
codebase-value-audit

Use when asked whether a codebase's size is justified — "is 800k lines reasonable?", "audit our LOC", "are we bloated?", "值不值" — or when a LOC number is being used in an argument and nobody agrees what it measures. Produces a defensible per-sub-product accounting: strict line counts, a product-surface inventory, every line attributed to exactly one sub-product, and a worth verdict per block.

Overview

PublisherInnei
RepositorySKILL
Skill namecodebase-value-audit
Stars
81
Forks
2
Bundled files
5
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 5 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by Innei on GitHub. Read the source before you install it.

Installation

Install the Codebase Value Audit AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/Innei/SKILL.git /tmp/SKILL
mkdir -p .claude/skills
cp -r /tmp/SKILL/skills/research/codebase-value-audit .claude/skills/codebase-value-audit
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Codebase Value Audit in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Codebase Value Audit on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Codebase Value Audit is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

codebase-value-audit

Turns "our repo is N lines, is that bad?" from a vibes debate into an audit. The core move: a raw LOC number is meaningless until (a) the measurement lens is pinned, (b) the product surface it bought is inventoried, and (c) every line is attributed to one sub-product and judged against what a standalone alternative would cost. The output is a report where the verdict is per-block, not global — because the honest answer is always "these 4 blocks are gold, these 4 deserve a discount."

When to use

  • Someone quotes a repo-wide LOC figure and asks if it's reasonable.
  • Two people quote different LOC figures for the same repo and both are "right" (different lenses) — reconcile before arguing.
  • Deciding where to cut: which subsystems dilute maintenance attention.

Not for: per-PR review, performance work, or dead-code sweeps alone (knip/depcheck do that); this skill tells you which blocks deserve a sweep.

Inputs

  • Repo root (git-tracked; works on monorepos).
  • Optional: the number the requester believes ("we have 800k lines") — you must reconcile your count with theirs, not just assert your own.

Files provided

  • scripts/count-pure-loc.sh — strict source-file list + pure-code line count (3 lenses printed side by side).
  • scripts/bucketize.py — attributes every file to the first matching bucket prefix and sums pure-code lines per bucket.
  • scripts/drill-bucket.py — aggregates one bucket's lines per directory at a chosen depth; mandatory before verdicts (step 4).
  • scripts/render-report.py — renders the final report as a standalone HTML file (light/dark, verdict chips, share bars) from a JSON data file; schema in references/report-data.example.json.

Workflow

text
[1] Pin the lens        3 counts: tracked-total / non-test / pure-code
[2] Inventory surface   parallel read-only agents, one per layer
[3] Attribute lines     bucketize.py: every line -> exactly one bucket
[4] Verdict per block   5 tiers, judged vs standalone-alternative cost
[5] Report              JSON data -> render-report.py -> HTML + open

[1] Pin the lens

Run scripts/count-pure-loc.sh <repo-root>. It prints three numbers:

  1. Tracked total — all git-tracked TS/JS lines.
  2. Non-test physical — minus tests/fixtures/e2e/scripts/mocks/ stories/.d.ts.
  3. Pure code — minus blank and comment-only lines.

These differ by 2x+ on a healthy repo (1.84M / 1.06M / 836k on the repo this skill came from). When the requester's number differs from yours, find which lens produces their number and say so explicitly — "your 800k is lens 3, my 1.84M is lens 1, both correct" ends the argument; a counter-assertion restarts it. All later steps use lens 3.

Also record: test:code ratio, and the largest data-as-code files (model catalogs, locale tables, generated schemas) — they surface in step 4.

[2] Inventory the product surface

Dispatch parallel read-only agents (Explore-type), one per layer, e.g.: web client (routes/stores), server (routers/services/modules), desktop + CLI, shared packages, and docs/changelog (the marketed feature list — this one cross-checks the code-derived inventory against what the product claims to ship; discrepancies are findings). Each agent returns a breadth inventory: surfaces, one-liners, and a "full sub-products" shortlist — no code review, no line counts.

Merge into a sub-product list (typically 15–25 entries). A sub-product is something that could be a standalone company/tool: an eval platform, a bot gateway, a document editor — not a feature like "dark mode".

[3] Attribute every line

Copy scripts/bucketize.py, fill in the bucket → path-prefix table from step 2's inventory, run it against the file list from step 1. Rules:

  • First match wins; order buckets specific → general.
  • One catch-all infra bucket with prefix "" must be last; inspect its breakdown output — anything large hiding in it means a missing prefix.
  • Cross-layer buckets are the point: one sub-product's bucket lists its frontend routes, its stores, its server services, its packages, and its CLI commands together.
  • Expect ±10% precision; say so in the report. Sum must equal lens-3 exactly (the script guarantees it — every file lands somewhere).

[4] Verdict per block

No verdict without a drill-down. Before judging any bucket ≥ ~15k lines, run scripts/drill-bucket.py <file-list> <depth> <prefix...> and scan its top directories for the five water categories:

CategoryWhat it looks like
DEAD-ROUTEDdeprecated pages/components still imported or routed — verify with grep against router configs and import sites, never by name alone
DATA-AS-CODElarge TS files that are pure declarations (catalogs, menus, prompt text)
SQUATTERcontent semantically belonging to another domain living under this bucket's paths (feature pages under a settings route)
PARALLEL-DUPtwo generations/implementations of the same thing coexisting
OVERSIZEDfiles past the repo's own size convention — count and total them
FIXTURE-IN-PRODtest fixtures / dev harnesses living outside test dirs, counted as product code

Bucket-level verdicts issued without this pass systematically miss mixed buckets: a "settings" bucket can be 60% provider forms + squatting feature pages + dead routes, and the whole-bucket verdict ("necessary cost") will be confidently wrong. Parallelize: one read-only subagent per 2–3 buckets, each returning findings with line estimates and file-path evidence; require them to verify DEAD claims and to say "clean" when a category is empty — invented water is worse than missed water.

Then refute before publishing. Every water claim from the first pass gets attacked in a second adversarial round: prompt agents to disprove each claim with import graphs, normalized diffs, and actual-wiring traces. Expect casualties — in the audit this skill came from, 5 of 8 first-round claims fell (a "duplicate subsystem" was a dependency; "two workflow generations" were layers; an unused-keys report was 43% false positives). Publish only claims that survive, and record the refuted ones in the report as corrections — an audit that shows its own overturned accusations is more credible, not less.

Then judge each sub-product's pure-code count against what acquiring that capability standalone would cost (build or adopt), not against zero. Five tiers:

TierCriteria
core assetDirectly implements the product's differentiation; rebuilding or adopting would cost more; high leverage per line
market priceTable-stakes capability at a normal size for what it does
risk betCoherent and well-built, but its value depends on an unproven product thesis — flag "watch usage data"
discountCompetes head-on with dedicated products without an edge, or carries measurable waste (data-as-code, duplicated generations, copy-paste variants)
necessary costSettings, auth, base layer — nobody loves it, nothing works without it; judge only its share (base layer ≤ ~20% is healthy)

Also assemble the squeeze list: concrete removable waste with line estimates (coexisting old/new generations of a subsystem, overlapping sibling services, data-as-code to externalize, convention violations, unused i18n keys, stale packages). This is the actionable output.

[5] Report

Lead with the global verdict and its split (e.g. "70% worth it / 13% core / 18% discounted / 8–10% pure squeeze"). Then: lens reconciliation, the ranked table (lines, share, verdict chip), tier commentary, squeeze list, and a closing that answers the requester's actual question. If they invoked an "AI era = fewer lines" thesis, engage it honestly: writing cost fell, review/maintenance cost didn't; the metric that matters is features per maintenance unit, and a ~1:1 test ratio is agent-era scaffolding, not bloat.

To ship it as a page: fill a JSON data file following references/report-data.example.json (in prose fields [[…]] renders bold, ((…)) renders accent-highlight), then

bash
python3 scripts/render-report.py report-data.json report.html && open report.html

Output is self-contained HTML (inline CSS, system fonts, light/dark). When a verdict gets challenged and revised, keep the row, annotate it (REV note in eyebrow/footer + a breakdown in its sub), and re-render — an audit that silently rewrites itself loses its authority.

Common pitfalls

MistakeFix
xargs wc -l | tail -1 as the totalxargs batches into multiple wc calls; tail -1 returns the last batch only. Sum with awk '$2 != "total" {s+=$1}'.
Counting merge-conflicted files 3xgit ls-files lists each unmerged file once per stage. Always sort -u the file list.
Arguing totals before pinning the lensBoth parties are usually right under different lenses. Reconcile first (step 1), then argue.
Running the counting script from the wrong cwdRelative paths silently open()-fail and count 0 per file; totals become 0 without an error. Run from repo root; treat an all-zero bucket table as this bug, not as truth.
Treating a high test share as waste~1:1 test:code is the agent-era signature — it's the guardrail that lets agents keep writing. Cut discipline debt, not tests.
Data-as-code inflating "logic"Model catalogs, locale tables, generated schemas are declarations. Measure them separately and recommend externalizing, or the density math is wrong.
Inventorying from code onlyAlso sweep docs/changelog/README with an agent — the marketed surface reveals sub-products the directory names hide, and mismatches are findings.
Catch-all bucket swallowing a subsystemOrder prefixes specific → general; always print the infra-bucket breakdown and chase anything unexpectedly large.
Verdict by size aloneA 10k-line block can be the highest-leverage asset (device gateway) and an 80k block half-waste (provider variants). Judge vs standalone-alternative cost.
Global verdict only"Worth it overall" helps nobody decide anything. The per-block table with tiers is the deliverable; the global number is its summary row.
Defending a challenged verdict without drilling downWhen a block's size surprises the requester ("why is settings 20k?"), re-aggregate that bucket one directory level deeper before answering. Route-named buckets often hide squatters: provider forms, feature pages living under a settings route, deprecated-but-routed dead pages. The challenge is usually a real finding.
Trusting a static "unused" reportAn unused-i18n-keys report was 43% false positives: dynamic key construction, string-literal keys inside config objects, and plural suffixes all defeat static detection. Sample-verify against those three mechanisms before acting; a report whose own statistics are self-contradicting (usage rate > 100%) is telling you something.
Convicting by name or shape"workflows/ vs workflows-hono/" looked like two generations — it was business logic + HTTP adapter, layered. "PluginDevModal" looked legacy — it was misnamed MCP UI. Prove duplication with import graphs and normalized diffs; naming is not evidence.
Treating a registry/identifier file as the wiringAn identifiers array turned out cosmetic (tools wired via register.ts and server runtimes); a desktop controllers registry.ts turned out type-only (runtime uses import.meta.glob). Find the mechanism that actually loads things before declaring anything unregistered/dead.
Publishing the first round's water listRun the refutation round (step 4). First-pass water claims are hypotheses; in practice a large fraction die under import-graph scrutiny, and shipping them unverified torches the audit's credibility on the claims that were right.

Verification

  • The three lens counts are internally consistent (lens1 > lens2 > lens3) and the requester's number is mapped to one of them.
  • Bucket sums equal the lens-3 total exactly; file list was sort -u'd.
  • Infra/catch-all breakdown inspected; nothing unexplained > ~5%.
  • Every bucket ≥ ~15k lines went through the drill-down pass; each water finding carries a category, a line estimate, and verified evidence paths.
  • Every sub-product has: lines, share, tier verdict, and a one-line justification referencing a standalone alternative or a concrete waste observation.
  • Squeeze list items each carry a line estimate and a concrete fix.
  • Report states the ±10% attribution caveat and any excluded scopes (e.g. closed-source stubs).
  • render-report.py output opens cleanly in a browser; row count, total, and share bars match the bucketize output.

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the Codebase Value Audit AI skill do?

Use when asked whether a codebase's size is justified — "is 800k lines reasonable?", "audit our LOC", "are we bloated?", "值不值" — or when a LOC number is being used in an argument and nobody agrees what it measures. Produces a defensible per-sub-product accounting: strict line counts, a product-surface inventory, every line attributed to exactly one sub-product, and a worth verdict per block.

Why use Codebase Value Audit on TypingMind?

Because you install it once and use it with any model. Codebase Value Audit is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Codebase Value Audit in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/Innei/SKILL/tree/main/skills/research/codebase-value-audit. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use Codebase Value Audit?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Codebase Value Audit?

As many as you like. As long as a model supports skills, you can use Codebase Value Audit with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Codebase Value Audit AI skill free?

It is published on GitHub by Innei. Check the repository for licensing terms. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇