Cookbook
Every command here is extracted and run against the real program by the test suite, because a manual that claims a flag nobody implemented is worse than no manual.
Short recipes for what people actually arrive wanting. Each is a sequence you can paste.
Every command on this page is extracted by tests/manual.rs and run against the
real binary, which refuses any the program would reject. That test exists
because the manual twice claimed a flag that was never implemented.
Adopt cairn where GitHub issues already exist
cairn init --name Nimbus
cairn import --from github --repo owner/name --dry-run
cairn import --from github --repo owner/name
cairn check --strict
The dry run first, because an import is the one operation that creates a hundred
files at once. GitHub is read through gh, which you have already
authenticated, so cairn never handles a token. Importing again later updates
rather than duplicates — provenance travels in source.
Triage a week’s arrivals without typing an identifier twice
cairn list --filter 'milestone=,category=open' --ids
cairn set --filter 'milestone=,type=bug' milestone=v0.1 priority=p1
The first line is the reading pass. The second changes everything it matched,
after showing you the list and asking. If you run the same query weekly, put it
in cairn.toml as a view and give it a name.
Make the roadmap unable to drift
cairn check --strict --render
One line in CI. --strict makes warnings fail; --render additionally fails
when the committed ROADMAP.md no longer matches what the items say.
Give an agent a scoped slice
cairn agent --write AGENTS.md
cairn next --filter 'milestone=v0.1' --json
cairn claim --next --filter 'type=bug'
The instruction block is generated from your schema, so it cannot describe a workflow you do not have. Scoping the claim rather than the listing is what makes the last line safe: doing it as list-then-claim leaves a gap in which another agent can take the item.
An agent that speaks the Model Context Protocol should be given cairn mcp
instead — the same operations, with no command lines to get wrong.
Move a backlog between two different schemas
cairn export > backlog.json
cairn import --from json backlog.json --dry-run
The document carries the schema alongside the items, so the receiving project
can interpret status names it has never seen. Names that do not exist there map
by category — one project’s shipped is another’s done — which is why
categories are a fixed axis under the names you choose.
Find everything one person is holding
cairn list --assignee alice --filter 'category=active'
cairn list --filter 'assignee=,category=active'
The second line is the more useful one: work in progress and assigned to nobody, which is what a stalled item looks like. An empty value means unset.
Recover after a bad merge
cairn check
cairn render
cairn check --render --strict
A merge the hook did not see — a rebase, a cherry-pick, a forge merge — can leave
two items with one number. cairn renumber repairs it; at a merge it also moves
the references that came with the renumbered item. Resolve conflicting edits,
regenerate the roadmap, and validate.
Keep a personal backlog that is not a code project
cairn init --name Oddur --preset minimal --bare
cairn new now -t horizon
cairn new next -t horizon
cairn new someday -t horizon
cairn new 'Migrate the other projects' -t task --set horizon=now
Cairn needs a cairn.toml and nothing else — not a git repository, not source
code. So a directory in your home is a tracker for the work that belongs to you
rather than to a repository: the thing that spans four projects, the idea with
no home yet, the decision you keep deferring.
The one change worth making to the schema is what work is filed under. A release-numbered milestone is meaningless here, so name the grouping type after the question you actually ask:
[[type]]
name = "horizon"
groups = "one"
Now now, next and someday are what the board columns and the roadmap are
built from, and cairn list heads the column HORIZON. Nothing else in the
schema changes, because cairn looks for the type that says it groups work and
never for the word milestone.
Run it from anywhere with -C, which takes the directory holding the
cairn.toml: cairn -C ~/cairn next. A shell alias is worth the ten seconds.
Keep it out of a remote unless you mean it. An untracked item and a private repository are the same idea; the second one is honest about it.