adit-code

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 22, 2026 License: MIT

README

adit-code

CI Go Report Card

Finds the files in your codebase that are structurally expensive to work with — for humans and AI agents alike — and tells you exactly what to fix.

wc -l tells you a file is big. adit tells you it has 51 parameters on one function, nesting 16 levels deep, and 8 ambiguous names that pollute every grep. Each finding maps to a specific refactoring action.

An adit is a horizontal tunnel driven into a hillside to provide access to a mine. adit-code tunnels into your codebase to find the structural hot spots.

What It Reports

$ adit score --pretty .

adit v0.1.0

  File              Lines  Size   Nest  Reads  Unneeded  Noise  Blast
  ────────────────────────────────────────────────────────────────────
  engine.py          3200    D       8     12        4      8      8
  handlers.py         890    B       5      7        3      2      3
  utils.py            420    A       3      2        0      0     15

  Co-locate (single-consumer imports):
    TRUST_HINTS (const)   constants.py:15 -> handlers.py

  Ambiguous names:
    _validate   3 defs: engine.py:42 handlers.py:88 auth.py:15

  Uncommented (large files, 0 comments — AI agents benefit from comments):
    engine.py (3200 lines)

  Import cycles: none

Every finding is actionable:

Metric What to do
Lines (Grade D/F) Split this file
Max Nesting (>6) Extract nested logic into helpers
Max Params (>10) Use a config object
Grep Noise Rename _validate — 5 other files define the same name
Unnecessary Reads Move X from constants.py to handlers.py — only consumer
Import Cycles Break the A→B→A cycle
Blast Radius 30 files import from here — verify edits carefully
No Comments Add comments — agents benefit from intent documentation

Validated Against Real Agent Behavior

Correlated against SWE-bench agent trajectories — 1,840 files across 49 repos, 10,000 agent runs. File size is the strongest predictor of agent tool call cost (median Spearman +0.474, positive on all 49 repos). The structural metrics tell you what specifically to fix:

Metric Median per-repo Positive repos
Lines +0.474 49/49
Max Nesting +0.344 48/49
Max Params +0.311 46/49
Grep Noise +0.241 38/49
Blast Radius +0.165 40/49
Unnecessary Reads +0.135 39/49

File size does most of the predictive work. The structural metrics don't predict better — they tell you why a file is expensive and what to change. wc -l says "this file is 3,200 lines." adit says "split it, and while you're at it, that function with 15 parameters needs a config object and those 8 levels of nesting need extracting."

Install

go install github.com/justinstimatze/adit-code/cmd/adit@latest

Or build from source:

git clone https://github.com/justinstimatze/adit-code.git
cd adit-code
go build ./cmd/adit

Single binary. Analyzes Python, TypeScript, and Go with one tool — no need for separate linters per language. Uses tree-sitter for parsing. No runtime dependencies.

Some of what adit checks (nesting depth, parameter count) overlaps with language-specific linters like pylint or eslint. adit's value is the cross-language consistency, the co-location and grep noise metrics that no linter checks, and the --diff mode for CI regression gates.

Quick Start

adit score .                          # JSON (default — for CI and AI tools)
adit score --pretty .                 # Human-readable table
adit score --diff HEAD~1 --pretty .   # What changed and what got worse
adit enforce .                        # CI gate — exit 1 if thresholds exceeded
adit enforce --diff HEAD~1 .          # Only enforce on changed files
adit mcp                              # MCP server for Claude Code / Codex

What It Measures

Five metrics. No composite score — each answers a different question.

Context Reads — How many files must the AI read to understand this file? Flags single-consumer imports (names imported by only one file) that should be co-located. Each unnecessary import is a wasted Read tool call.

Grep Noise — How much search noise surrounds this file? Counts ambiguous names this file defines or imports that are also defined elsewhere. _validate in 5 files = 4 extra grep results to wade through.

File Size — How many reads and re-reads does this file cost? AI tools read files in chunks, not all at once. Larger files require more reads and the AI loses coherence across distant methods. Grades A (<500 lines) through F (5000+) based on empirically validated thresholds.

Blast Radius — How many files reference this one? High-blast files are central definitions that get read often for context.

Import Cycles — Circular dependencies that waste AI context (A reads B, B reads A, loop).

Configuration

Create adit.toml in your project root:

[thresholds]
max_file_lines = 3000
max_context_reads = 10
max_unnecessary_reads = 3
max_ambiguity_defs = 3
max_blast_radius = 20
max_cycle_length = 0           # 0 = no cycles allowed

[scan]
languages = ["python", "typescript"]
exclude = ["test_*.py", "*.test.ts", "**/__pycache__/**", "**/node_modules/**"]

# Looser thresholds for specific paths
[per-path."test_*.py"]
max_file_lines = 5000

Also reads [tool.adit] from pyproject.toml. Config is auto-discovered by walking up from the target path.

AI Agent Integration

MCP Server (Claude Code, Codex, any MCP-compatible agent)
{
  "mcpServers": {
    "adit": { "command": "adit", "args": ["mcp"] }
  }
}

7 tools: adit_score_repo, adit_score_file, adit_relocatable, adit_ambiguous, adit_blast_radius, adit_cycles, adit_diff.

CLI + JSON (any agent that shells out)

JSON-default output. Any agent that can run commands and parse JSON works:

adit score .              # full analysis
adit enforce --diff $REF  # PR gate
CLAUDE.md / AGENTS.md

Add to your project's AI instruction file:

## Structural Health
This project uses adit for code structure analysis.
- Before committing: run `adit enforce .` — fix violations, don't skip.
- When adit reports relocatable imports: move the definition to the consumer file.
- When adit reports ambiguous names: rename to be more distinctive.
Pre-commit Hook
repos:
  - repo: local
    hooks:
      - id: adit
        name: adit enforce
        entry: adit enforce
        language: system
        types_or: [python, ts, tsx, go]

CLI Reference

adit score [PATHS...]                  # JSON (default)
adit score --pretty [PATHS...]         # Human table
adit score --diff REF [PATHS...]       # Compare against git ref
adit score --min-grade C .             # Only files at grade C or worse
adit score --sort blast .              # Sort: blast|reads|noise|size|name
adit score --quiet .                   # Metrics only, no recommendations
adit score --silent .                  # No output, exit code only

adit enforce [PATHS...]                # Exit 1 if thresholds exceeded
adit enforce --diff REF .              # Only enforce on changed files
adit enforce --silent .                # Exit code only

adit mcp                               # MCP server (stdio)

Exit codes: 0 = pass, 1 = issues found, 2 = tool error.

Performance

Fast on most repos: ~150 files/sec. Cross-file analysis (co-location, blast radius, grep noise) is O(n²) and dominates on large repos:

Repo size Time
<200 files <1s
~500 files ~3s
~1,000 files ~15s
~4,500 files (Sentry) ~5 min

Deeper Validation

Beyond the headline correlations, session-level analysis reveals:

File size effect — AI tool calls by file size grade:

Grade Avg Tool Calls vs Grade A
A (<500 lines) 41 1x
B (500-1500) 204 5x
C (1500-3000) 2,059 50x
F (5000+) 6,710 163x

Re-reads per session — The AI re-reads large files repeatedly within a single session. Avg reads-per-session by grade: A=5.8, B=13.2, C=29.6, F=54.0.

Edit success rate — Files with more imports have higher re-edit rates (r=+0.437). Re-edit rates by grade: A=59%, B=77%, D=87%, F=89%. More coupled files are harder to get right on the first try.

Across open source projects

adit scored against 33 open source projects across Python, TypeScript, and Go. Generated files (migrations, protobuf, etc.) are auto-detected and excluded.

Python

Project Files A B C D F Nest Params
Sentry 4,226 3,932 268 21 4 1 13 29
PyTorch 2,142 1,608 375 104 33 22 11 53
yt-dlp 1,125 1,056 55 10 3 1 11 15
CPython stdlib 1,110 903 147 45 9 6 11 26
SymPy 923 640 189 67 22 5 13 22
Salt 910 646 198 45 15 6 16 51
Django 853 774 65 13 1 - 11 25
OpenStack Nova 776 681 64 23 5 3 10 47
Ansible 577 498 68 10 1 - 12 25
pandas 452 333 74 26 13 6 10 35
scikit-learn 383 239 108 29 6 1 9 24
Odoo 344 292 39 10 2 1 12 15
Scrapy 177 165 12 - - - 8 15
Celery 161 138 21 2 - - 11 30
matplotlib 156 87 38 21 8 2 9 24
FastAPI 48 41 4 1 2 - 11 38
Flask 24 17 6 1 - - 7 10

TypeScript

Project Files A B C D F Nest Params
TypeScript compiler 709 557 96 31 12 13 18 26
TypeORM 491 441 34 8 6 2 19 4
Prisma client 422 414 7 - - 1 8 6
Hono 208 192 14 2 - - 13 6
Deno std path 98 97 1 - - - 21 4
tRPC server 82 77 5 - - - 8 3
React Router 68 53 10 3 1 1 9 21

Go

Project Files A B C D F Nest Params
CockroachDB sql 2,231 1,826 325 52 16 12 13 22
Kubernetes pkg 1,980 1,804 148 24 2 2 9 40
Terraform 1,201 1,087 105 7 2 - 11 8
Docker daemon 944 866 74 4 - - 10 9
GitHub CLI 389 366 22 1 - - 8 10
geppetto 220 206 14 - - - 11 8
glazed 210 197 13 - - - 9 6
TiDB executor 193 128 53 9 2 1 11 16
go-go-mcp 144 137 7 - - - 9 5

Key findings:

  • Salt has the worst parameter complexity (51 params) and deepest nesting (16 levels). PyTorch follows with 53 max params. Nova has 47.
  • TypeScript compiler and TypeORM have the deepest nesting in TS (18-19). Deno std reaches 21 despite tiny file sizes.
  • Go projects have lower max params (5-40) and moderate nesting (8-13). CockroachDB is the exception with 12 Grade F files.

Reproduce on your own repos:

adit score --pretty /path/to/project

License

MIT. All dependencies MIT or BSD-2. See INFLUENCES.md for full citation record, prior art search, and license audit.

Directories

Path Synopsis
cmd
adit command
adit-validate command
adit-validate: Correlate adit metrics with git history to validate that the metrics predict actual editing cost.
adit-validate: Correlate adit metrics with git history to validate that the metrics predict actual editing cost.
internal
mcp

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL