clines 6.0 — the machine-readable release
Until this release clines could only talk to a person. There was no
--json, no --csv, nothing but formatted tables, three HTML files
and a markdown block written into a README. Exactly one flag could fail a build (ctx --max), and nothing could compare a run against a git ref.
That is a strange shape for a tool whose most distinctive analysis measures what a codebase costs a language model to read. The consumers of that number are pipelines and coding agents, and neither can read a table. 6.0 fixes that.
--json on every command
Every command now takes --json and writes one document to stdout under a
shared envelope, so a consumer parses first and dispatches second.
$ clines ctx --json | jq '.result.totalTokens' 3303084
Three decisions are worth naming. The output carries no timestamp, so two runs of
the same tree diff cleanly and a CI baseline stays stable. --json implies
--no-pager and every progress line already went to stderr, so stdout is only
ever JSON. And --top is ignored — a person wants the top 20, a program wants
all of it.
One exception, made deliberately: dup --json carries every clone group and
every fragment location, but not the snippet text. Including it would make the document
scale with the size of the duplication rather than its shape, and the text is reproducible
from the files. --html still has the snippets.
Exit 2 means "found something"
Before, everything failed with 1: a bad flag, a missing directory, a breached
budget. A pipeline could not tell a finding from a failure. Now a breached threshold exits
2 and errors keep exiting 1.
$ clines dup --max-duplication 5 Duplication exceeded: 5.5% > 5.0% (--max-duplication) $ echo $? 2
dup, cx, comments and refactor gained
threshold flags to go with ctx --max. This is the breaking change behind the
major version: ctx --max used to exit 1.
refactor deliberately did not get a gate on verdict counts. Its
thresholds are quantiles of the repository computed per run, so every repository always
has a top quartile — "fail if more than 50 files say refactor" would measure nothing
across runs. --max-reread gates an absolute number instead.
--diff main
A budget on a whole repository is close to unactionable: it is either already breached or
it is noise. What a team will actually keep is a check on the change. Any command now
takes --diff <ref> and reports only what a branch touched.
$ clines ctx --diff main --max 50k
dup needs different treatment, and gets it. Filtering its input would destroy
detection — a clone needs its other copies to exist. So detection still runs over the
whole tree, and only then does the result narrow to the groups a changed file takes part
in, naming the other copies. The headline percentage is recomputed over the changed files,
so the gate measures the branch rather than the repository.
The shallow clone bug
Building --diff surfaced something worse than a missing feature.
git blame and git log --since both answer a depth-1 clone
without complaint and return truncated history. actions/checkout defaults to
fetch-depth: 1. So refactor and comments have been
quietly reporting near-zero change counts in CI, confidently, with no way to tell.
Shallow clone: git history is truncated here, so these numbers are too low. Fetch the full history (actions/checkout with `fetch-depth: 0`) for a real answer.
The same pass gave git failures distinguishable causes. Every git call used to collapse
into undefined, so a 64 MB buffer overflow on a large
git log was reported to the user as "no git history is available".
clines mcp
clines mcp runs a Model Context Protocol server on stdio, so an agent can ask
what a repository costs to read without shelling out and parsing a table. All six analyses
are exposed as tools.
$ claude mcp add clines -- npx clines mcp
It adds no dependency. The JSON-RPC is hand-rolled — about 120 lines, in a codebase
that already hand-rolls a glob engine, a config validator and a TTY pager — so
commander remains the only runtime dependency.
Its responses are compact and capped at 20 rows by default, which is the opposite of what
--json does on purpose. An agent pays for every token it reads back; a
6,915-file dump would defeat the point of asking.
And the obvious embarrassment
clines did not run clines in its own CI. The flagship CI feature was unused by the only repository guaranteed to have it installed. It now gates itself on token budget, duplication and complexity density, and checks out full history to do it.
Also in 6.0
-
The library API now exports all six analyses.
analyzeCommentsandanalyzeRefactorwere missing entirely, and two of the exported analyses had unexported return types. -
loadConfig,loadGitignoreGlobsandloadGitAttributesare exported, so a library caller can reproduce exactly what the CLI does withclines.json,.gitignoreand.gitattributesinstead of reimplementing it. - Test coverage is still 100%, on 562 tests.