cairnkit check
Failing the build when a tour breaks, and cairnkit status for reading what is there.
Running it
npx cairnkit checkThe path defaults to src. Pass one or more directories if your code lives elsewhere or spans several roots — everything is scanned as a single project, so a flow in one directory can point at a component in another:
npx cairnkit check src
npx cairnkit check src app packages/uiIt exits 0 when clean and 1 on any finding.
Reading the output
✗ cairnkit check failed
• 1 anchor(s) are registered but never applied to an element [anchors-applied]
- questions.save (breaks "create-questions") src/walkthrough/flows.ts:35
Spread {...anchor(...)} on the element, or remove the anchor and the step pointing at it.Four things: which anchor, which tour it breaks, a clickable location, and what to do.
The rules
| Prop | Type | Default | Description |
|---|---|---|---|
anchors-applied | error | — | An anchor is registered and referenced by a flow, but never applied to an element. |
anchors-registered | error | — | A data-cairn attribute whose value is not in the registry — usually a typo or a leftover. |
route-conflicts | error | — | A route in both pauseRoutes and handoffRoutes, or a flow handing off to itself. Overlap is judged with the engine's own matcher, so pausing /projects/:slug while handing off /projects/acme is caught too. |
Seeing what is there
check answers “is anything wrong”. status answers “what is there”, which is the question you have first in a project you did not write: every anchor, whether an element carries it, where it was declared, and which flows point at it.
npx cairnkit statuscairnkit status · 21 anchors, 4 flow(s)
✓ compose.prompt write-question src/walkthrough/anchors.ts:8
✓ invite.send invite-candidate src/walkthrough/anchors.ts:6
✓ nav.pipeline src/walkthrough/anchors.ts:4
! questions.export src/walkthrough/anchors.ts:9
1 registered but not applied, 0 applied but not registered.
Run cairnkit check for the detail.A tick means an element carries it. An exclamation means the registry declares it and nothing applies it, which is the state check fails on. An anchor with no flow beside it is simply not used by a tour yet, which is fine.
It always exits 0. Describing a project is not a verdict on it, and a command that fails for telling you something is a command nobody runs.
In CI
"scripts": { "lint": "eslint . && cairnkit check src" }- run: npx cairnkit check srcAround 0.1s across 700 source files, so it belongs in the fast lane next to your linter rather than in a nightly job.
What it does not do
- It never executes your code. It reads files as text, so it is safe to run on untrusted branches and needs no build step first.
- It cannot see rendering. An element that exists in source but never renders passes — that is the browser audit’s job.
- It ignores quoted code. Comments and string literals are stripped first, so a docs page showing a
defineAnchorssample will not register phantom anchors.