Repository navigation
klode 0.4.1
⚠️ Upgrading from 0.3.0? Start here.
0.4.0 was prepared but never published, so v0.4.1 carries everything since v0.3.0.
The change most likely to break you
Commands that could not do their work now exit 2 instead of 0.
| command | condition | was | now |
|---|---|---|---|
check |
corpus absent, or any card's source not installed | OK, 0 |
ABSTAINED, 2 |
check --entail |
the entailment backend could not load | OK, 0 |
ABSTAINED, 2 |
build |
nothing to build | 0 | 2 |
normalize --check |
no file matched, or files were unreadable | 0 | 2 |
zoom --level content |
the source is not installed | 0 | 2 |
eval/extract_bakeoff.py |
nothing could be ranked | 0 | 2 |
If your CI runs klode check on a machine without the corpus installed, it will now fail.
That is deliberate. klode check --strict used to print OK: 0 errors and exit 0 on a library
whose citation-rot check never ran — and a fresh clone has no corpus, because the corpus is
git-ignored. Every anchor could have rotted while the build stayed green. CI reads exit codes, not
notes.
The convention is now uniform: 1 = measured and failed · 2 = could not measure · 0 = the work
happened. Pass --allow-unmeasured to check, build, or normalize to accept a gap
knowingly — the difference between an accepted limitation and a silent one.
Also breaking
- A card's
file:is confined to<lib>/<shelf>/<name>.txt. It was confined only to the
library root, so a card could point atlibrary/.envorlibrary.tomlandzoom --grepwould
print the matching lines. Cards travel through the registry, so that field is untrusted input. - Settings-backed CLI flags default to
Nonerather than to their value;--maxrequires
--grep;normalize --applyand--checkare mutually exclusive;--jsonon a command that
cannot emit it now refuses instead of printing prose.
What's new
- Extraction integrity — an ingest can say whether the text it wrote represents the document,
and refuses the shelf when it does not. Containment, inflation and per-page reading order, plus
rendered-page ground truth (pdftoppm+tesseract) — the only signal not downstream of another
extractor. Four states, andabstainedis neververified. ~/.klode/settings.toml— argument → environment → file → default, with the winning source
recorded.klode settings --explaindescribes every key;--lintvalidates the file including
shadowed values. Credentials can never be settings, and a test enforces it.- Remote layout backends — point
[ingest].docling_url/marker_urlatdocling-serveor
marker_server. The GPU runs server-side, so klode keeps zero runtime dependencies. Preferred
over a local install: remote conversions have a deadline that scales with the document, while the
in-process backends have no wall-clock bound. klode review --live-judge— the real rubric judge, behind an explicit flag. A config file is
consent to choose a model, not to spend money; without the flag klode makes no network call
whatever the settings say.eval/extract_bakeoff.py— ranks backends against the rendered page by a paired comparison,
and refuses to rank when no viable pairing exists. The committed result over 20 two-column papers
is what earns docling its tier-3 slot and keeps marker out of theautoladder.
How it was checked
Two audits, 137 findings. The second audited the code written to close the first, and found five
rows that claimed closure the behaviour had not reached. Every fix was mutation-checked — reverted,
and the new test confirmed to fail. Full notes in CHANGELOG.md.
Known limit, stated rather than implied: local in-process OCR has no wall-clock bound. Bounding
it needs a worker process that re-imports torch in the child; that was built and not shipped,
because it could not be tested against backends absent from the environment. Use a remote endpoint
where a deadline matters.