Skip to content
lawbook
Esc
↑↓navigate↵open⌘Jpreview
On this page

Baseline

Adopt lawbook on an existing codebase by recording today's findings and failing only on new ones.

A new rule on an old codebase usually finds a lot. A baseline records those findings so check hides them and fails only on what appears afterwards, which lets a team turn a rule on today and pay the debt down over time.

lawbook check --baseline lawbook-baseline.json --update-baseline

--update-baseline runs the check, writes every finding to the file, then reports the run with those findings hidden, so it exits 0 unless a standard rule errored. Commit the file. From then on, run with --baseline alone:

lawbook check --baseline lawbook-baseline.json

Findings the file records are dropped before the status, the summary, and the exit code are computed. The text output counts them under the rule, and the JSON output carries the count as baselined:

FAIL no-console
  src/new.ts:4: console.log("debug");
  12 findings in baseline
PASS has-readme

1 passed, 1 failed, 0 warned, 0 errored, 0 skipped

The GitHub, SARIF, and GitLab formats simply leave hidden findings out.

What identifies a finding

The file keys findings so that edits elsewhere in a file do not resurface them, so no entry carries a line number:

Kind Key Note
forbid rule, path, and message The message is the matched line, or the rule’s message if it sets one, in which case the entry counts all of a file’s matches together.
require, exists, absent rule and path The message is fixed by the rule.
standard rule and path The model’s reason varies between runs. A scope: set finding has no path and is keyed by the rule alone. A provider error is never baselined, so an ERROR rule stays visible.

Each entry has a count. A run hides that many identical findings and shows the rest, so a second console.log in a file that had one still fails.

{
  "version": 1,
  "findings": [
    { "rule": "no-console", "path": "src/old.ts", "message": "console.log(\"x\");", "count": 1 },
    { "rule": "errors-are-actionable", "path": "src/cli.ts", "count": 1 }
  ]
}

Entries are sorted, so regenerating the file produces a readable diff.

Updating the baseline

--update-baseline replaces the file with this run’s findings; it does not merge. Run it with the same --config, --only, and --no-llm flags as the checks that read it, and without --files, --changed, or --since, else the file records only part of the codebase. Shrink it by fixing findings and regenerating; review the diff before committing to make sure nothing new slipped in.

The path given to --baseline is relative to the current directory, like --config. A missing or invalid file is an error with exit code 2, as is --update-baseline without --baseline.

A baseline answers a snapshot question: which findings were already there when the rule was adopted. A gate that runs per change asks a different one, whether the change lowered the bar, and --changed-lines answers it without a file to refresh: a standard rule judges only the lines --since or --changed touched. See Changed lines.

Last updated on October 10, 2026

Was this page helpful?