cairn

Project memory, versioned with the code.

Keep intent, work, and decisions as Markdown in your repository, under a schema you own. People and agents work the same record. Git carries its history. No required server or account.

curl -fsSL https://raw.githubusercontent.com/oddurs/cairn/main/install.sh | sh

Or brew tap oddurs/cairn && brew trust oddurs/cairn && brew install cairn. Linux, macOS and Windows.

Use Harrow beside your editor or agent to watch the work and decide what needs attention. It reads the same files and makes changes through Cairn.

Read the docsSource on GitHub

cairn/items/0003-support-oauth-login.md
---
id: 3
uid: 00000003-0000-4000-8000-000000000003
title: Support OAuth login
type: feature
status: doing
milestone: v0.1
assignee: you
claimed: 2026-09-05
created: 2026-09-05
updated: 2026-09-05
priority: p0
---

## Problem

## Proposal

## Acceptance criteria

- [ ]

See the whole thing at a glance

Columns come from the statuses you declared, in the order you declared them. Width follows content, so an empty column does not take a full share. A leading ! marks work that cannot be started because something else is unfinished.

$ cairn board
backlog 2                      planned 1                           in progress 1            blocked 0
─────────────────────────────  ──────────────────────────────────  ───────────────────────  ─────────
!0004 p1 Rate-limit the publ…   0005 p1 Board shears on narrow t…   0003 p0 Support OAuth…
 0006 p2 Document the export…

3 ready · 1 in progress · 1 blocked

The loop is two commands

$ cairn next
ID    PRIORITY  STATUS       MILESTONE  TITLE
0003  p0        in progress  v0.1       Support OAuth login
0005  p1        planned      v0.1       Board shears on narrow terminals
0006  p2        backlog      v0.2       Document the export format

3 ready · 1 in progress · 1 blocked

Work that is genuinely startable. Anything waiting on unfinished work is excluded, and what is already under way comes first — the most useful next action is usually finishing something.

$ cairn claim --next
claimed 0003  Support OAuth login
  you · doing · cairn/items/0003-support-oauth-login.md

Takes the top-ranked unclaimed item, writes your name into it, and prints its body so work can begin. It refuses an item somebody else holds, and one that is blocked.

Recorded, not illustrated

Every terminal on this page — the file, the board, the listings, the rejected tool call — was captured by running the real thing. So was the session below. All of it is regenerated on each change, and continuous integration fails if any of it stops matching what the program does.

A terminal session: creating two items where the second depends on the first, running cairn next, claiming the top item, closing it, and watching the dependent item become available.

Agents get tools, not instructions

cairn mcp serves the backlog over the Model Context Protocol. A rejected write comes back as something the model can act on, so it corrects itself instead of inventing a format.

How to set it up

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

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

Built to be left alone

Writes cannot be half-finished

Every file is written beside its target, flushed, and renamed over it. A crash leaves the old contents or the new ones, never a mixture. There is a test that kills the program mid-write forty times.

Work travels with the branch

Review the item beside the code it describes. Git integration helps reconcile generated output and identifier collisions; conflicting decisions remain visible for a person to resolve.

The format is specified

The item format is written down independently of this program, versioned, and pinned by a corpus of files that must keep parsing the same way.

Concurrent writers are safe

Writers sharing an item directory take a lock. Forty processes creating items at once produce forty distinct identifiers. Separate branches and worktrees carry their own state, so assignments still need coordination.

Milestones, from the same files

The roadmap is derived from the items, so it cannot describe a plan nobody is working on.

Read the docsThe item format

$ cairn roadmap
Nimbus

v0.1  First usable version
  [--------------------]   0%  0/2   due 2026-12-01

v0.2  Hardening
  [--------------------]   0%  0/2   due 2027-02-01