JSON output
The schema of --format json — diagnostics, spans, fixes, and stats.
lawlint draft.md --format json
{
"diagnostics": [
{
"ruleId": "no-em-dash",
"severity": "warning",
"tier": "static",
"intent": "detection",
"span": { "start": 42, "end": 45 },
"message": "An em dash where a comma would do.",
"line": 3,
"column": 12,
"endLine": 3,
"endColumn": 15,
"excerpt": "The clause — which we drafted — is void.",
"suggestion": "Use a comma.",
"weight": 1,
"fix": {
"edits": [{ "range": { "start": 42, "end": 45 }, "replacement": "," }],
"applicability": "machineApplicable"
}
}
],
"stats": { "wordCount": 812, "sentenceCount": 41, "score": 73 }
}
Optional fields are omitted rather than emitted as null.
diagnostics[]
ruleIdstring
Namespaced for package rules: <package>/<id>.
stringseverity"error" | "warning" | "suggestion"
"info" is accepted on input as an alias for "suggestion".
"error" | "warning" | "suggestion"tier"static" | "statistical" | "inferential"
The stable kind contract. static and statistical are hard rules; inferential is soft.
"static" | "statistical" | "inferential"intent?"detection" | "style"
Only detection findings charge the score. Absent in results serialized before intent existed.
"detection" | "style""detection"span{ start, end }
Byte offsets into the linted text.
{ start, end }messagestring
What the rule found.
stringlinenumber
1-based.
numbercolumnnumber
1-based, in UTF-16 code units.
numberendLine?number
1-based. Omitted for single-position findings.
numberendColumn?number
1-based, UTF-16 code units.
numberexcerptstring
The trimmed source line the finding sits on.
stringsuggestion?string
Prose advice. Present even when there is no applicable fix.
stringweight?number
Score penalty multiplier. Density rules scale it by how far past threshold the text runs.
numberconfidence?number
Inferential (soft-rule) findings only.
numberfix?Fix
Present only when the rule produced one.
Fixfix
edits{ range: { start, end }, replacement: string }[]
Byte ranges to replace. A fix may carry more than one edit.
{ range: { start, end }, replacement: string }[]applicability"machineApplicable" | "maybeIncorrect"
--fix applies machineApplicable edits only.
"machineApplicable" | "maybeIncorrect"See Fixes and tracked changes.
stats
wordCountnumber
Words in the linted text — the denominator for score normalization.
numbersentenceCountnumber
numberscorenumber
Human-likeness score, 0–100.
numberjudge
Present only when the AI judge ran, carrying that run’s judging statistics. A “chunk” here is one judge request.
chunksnumber
Requests the run planned. Depends on the backend's batching — one per rule for hosted models, one per section for local ones.
numbercacheHitsnumber
Requests answered from the on-disk cache instead of the provider.
numberchunksFailednumber
Requests that failed after a retry. Those chunks contributed no findings and fell back to the deterministic tiers.
numbergroundednumber
Findings whose quote was matched back to a source span. Only these become diagnostics.
numberhallucinatedRecord<string, number>
Discarded findings per rule id: an ungroundable quote, or a rule the request never asked about.
Record<string, number>firstFailure?string
Why the first failed chunk failed. Absent when chunksFailed is 0.
string{
"chunks": 2,
"cacheHits": 0,
"chunksFailed": 0,
"grounded": 3,
"hallucinated": { "empty-hedge": 1 }
}
Rule metadata
lawlint rules --json prints the loaded rule set rather than a lint result:
[
{
"id": "empty-hedge",
"meta": {
"tier": "inferential",
"scope": "text",
"severity": "warning",
"description": "Flags hedges that carry no information about actual uncertainty.",
"docsUrl": "https://lawlint.com/rules/empty-hedge",
"examples": [],
"rationale": "A hedge earns its place only when it tells the reader what is uncertain and why."
}
}
]
This is what generates the rule reference.
Compatibility
Key off tier, not the hard/soft terminology — tier is the serialized
contract and will not change. New optional fields may be added; parse
permissively.