cairn

Agents

Programs that write code write plans too, and left alone they scatter TODO files in formats of their own devising. The answer is a schema, and tools that enforce it.

Over MCP

cairn mcp --config

That prints the snippet for .mcp.json, .cursor/mcp.json or wherever your client keeps its configuration. cairn mcp then serves the backlog over the Model Context Protocol on standard input and output, with tools covering get_schema, next_items, list_items, search_items, show_item, claim_item, create_item, update_item, add_note, tick_criteria, propose_change, release_item, close_item and check.

The CLI and MCP validate changes against the same project schema. Choose the interface the agent works with well. Generated instructions explain the project; validated writes enforce its structure. These are cooperative workflow rules, not a security boundary against a process that can edit the files directly.

A rejected write teaches

Failures come back in the result rather than as protocol errors, so the model can read what went wrong and correct itself.

$ cairn mcp
update_item {"id": 3, "fields": {"status": "in progress"}}

unknown status `in progress`
known: backlog, planned, doing, blocked, done, dropped

The most common mistake, and the reason for it is worth knowing: a status has a name and a label. Tables show the label; every write takes the name.

The loop an agent follows

  1. get_schema — statuses, fields and milestones are declared per project and are not fixed. Ask first.
  2. next_items — work that is genuinely startable. Anything waiting on unfinished work is excluded, and what is already under way comes first.
  3. claim_item — take it before starting, so two workers do not duplicate each other. Called with no id it takes the top-ranked unclaimed item and returns its body, so work can begin in one call.
  4. add_note — record why something was decided. Distinct from update_item’s body, which replaces: a caller writing down its reasoning must not be able to erase what came before.
  5. close_item, then check before reporting done.

Item responses carry blocked, ready and blockers by default, because dependency state is what an agent most needs and cannot work out from a single item.

Dependency readiness is not an approval to implement every open idea. Scope next_items and claim_item with the project’s approved-work filter, such as status=planned. Search with all=true before proposing a change so completed and dropped decisions are part of the context.

Work is recorded under the caller’s name

Identity comes from CAIRN_USER if set, then the name the client gave in its MCP handshake, then the login.

Without MCP

cairn agent --write AGENTS.md

For a client that speaks no protocol, this writes an instruction block generated from your live schema — the real statuses, the real fields, the real milestones — between markers, so re-running it updates the block and leaves the rest of the file alone.

Because it is generated, it cannot describe a workflow the project does not have. Agents then read with cairn list --json and cairn show <id> --json, and write with cairn new, cairn set and cairn note.

Two agents at once

Mutating commands take a lock; reads never do, so listing never queues behind somebody’s write. Forty processes creating items simultaneously produce forty distinct identifiers, and twelve agents racing for one item produce exactly one owner and eleven refusals that name the holder.

This exclusion holds within one item directory. Across the worktrees of one repository on one machine, cairn reads what each other worktree has claimed: next leaves it out, claim refuses it without --force, and cairn worktrees lists it. Separate clones can still claim the same item independently. Agree on assignments before splitting work across clones, and review the item changes when merging.

Identifiers can also collide across branches. cairn init --git installs merge support once per working copy; validation and review still matter after a merge.