A citation has two ends, and both are pinned the same way. The claim is
the page lines the sentence occupies, and a hash of them. The source is
the file, the lines it rests on, a hash of those, and the commit they were
read at. manni cite checks both ends and tells you which sentence stopped
being true, not which page to re-read.
It runs from git alone. No model, no network, one hash per end on a clean run.
A line that gained neighbours above it is moved, and one command fixes that. A
line whose bytes changed is changed, with the commits since, and a person
decides whether the prose or the pin is wrong. Nothing on the page repeats the
sentence, so a copy edit beside it is not a false alarm.
You don’t need to install anything. Say docs/limits.md says on line 9 that
the fetch timeout is 10 seconds, and that sentence rests on line 2 of
lib/limits.ts. Pin both ends:
docs/limits.md: added fetch-timeout to frontmatter (claim at line 15, sha256-c41f09aa…; source lib/limits.ts:2, sha256-78af1d33…, 9265563)
The entry pushed the sentence down the file, and the stored claim line did not
move: it counts the body, not the file. Check it:
Terminal window
npx@hawkeyexl/mannicitecheckdocs/limits.md
✓ docs/limits.md
✓ fetch-timeout :15 current lib/limits.ts:2 current
1 file checked, 1 passed, 0 failed, 0 findings
Then someone raises the timeout to 30 seconds and commits. The page has not
changed, so metadata validation still passes. The citation check does not:
✗ docs/limits.md
✗ fetch-timeout :15 current lib/limits.ts:2 changed since 9265563, 1 commit
1 file checked, 0 passed, 1 failed, 1 finding
The finding is annotated on line 15, the sentence. The exit code is 1, so CI
goes red on the line that needs a person, and nowhere else. That’s the whole
loop: pin, check, read the finding, fix the sentence, re-pin.
Get startedPin your first claim, watch each end move and change, and fix it with one command. Then anchor with a marker and pin a code block.
Public docs, private codeEncrypt a private repository's source paths, so a public docs site can cite it without publishing its paths or a verifier for its lines.
Run it in CIPR annotations, SARIF, JUnit, the exit-code contract, the baseline ramp, and why the checkout needs full history.
Fix a failing checkYour PR's citation check is red? Every status, what it means, and which update flag clears it.
The reference shelf holds the exhaustive detail. The
CLI reference covers every flag of check, add
and update. The configuration reference
covers the cite: keys of manni.config.yaml. The
citations reference covers the entry shape,
the file grammar, the hashing rule, markers and the sidecar manifest.
That the lines a sentence cites are still the bytes they were when the
citation was written, and that the sentence itself is. Where either end
went if it moved. What changed and in which commits if the source did not
survive. That every marker names a real entry, and every entry has one
anchor.
It doesn't
Judge whether the sentence was ever right, read the source for meaning, call
a model, or reach the network. A source-changed finding is a question for
a person; the check only makes sure it is asked about one sentence rather
than a whole page.
Citations are written in the manni:citations vocabulary, which manni meta
publishes and manni cite implements. manni meta validate checks that an entry
is well-formed; only manni cite check can say whether it still holds. Both
tools ship in one package and read one manni.config.yaml, under their own
keys.