Skip to main content
Glama

Cairn

A local MCP server that checkpoints AI coding sessions and — when things go wrong — recovers them with context. Not just a rollback. An informed restart.

See DESIGN.md for the full design document.

Install

pip install cairn-mcp          # heuristic-only
pip install cairn-mcp[ai]      # with LiteLLM for auto-labels, handoffs, embeddings

Related MCP server: Total Recall

Setup

cd your-project
cairn init                     # writes cairn.toml, gitignores .cairn/, installs ~/.cairn
claude mcp add cairn -- cairn start

Then add @~/.cairn/cairn_agent.md to your tool's always-loaded context file (CLAUDE.md, .cursorrules, .windsurfrules, or .roo/rules/cairn.md).

Full requirements and per-tool setup (Claude Code, Codex CLI, OpenCode, Roo Code, and others) are in INSTALL.md.

CLI

Command

What it does

cairn start

Run the MCP server (stdio); a session starts on connect

cairn stop

Mark active sessions for this directory as ended

cairn history [--archived]

List sessions and checkpoints (or purged sessions)

cairn dismiss

Dismiss current drift signals (false positive)

cairn init

Set up cairn.toml, .gitignore, and ~/.cairn

cairn eval run [--judge]

Score drift detection against synthetic scenarios

cairn eval results

List past eval runs

MCP tools

Cairn exposes exactly six tools. Descriptions are terse and responses are compact JSON — the whole Cairn footprint in the model's context is budgeted at under 300 tokens.

Tool

Mode

What it does

Returns

cairn_checkpoint(label?, trigger?)

async, fire-and-forget

Snapshot the working tree onto a shadow branch; trigger is "manual" (user asked) or "ai" (model judged, default)

{"status":"queued","id":"..."}

cairn_rollback(checkpoint_id, inspect?)

sync, atomic

Auto-stash, reset to checkpoint, write handoff + recovery gate (inspect=true creates a cairn/recovery/* branch instead)

{"status":"restored","checkpoint":"...","stash_ref":"stash@{0}","handoff_written":true}

cairn_check_drift()

sync (drains queue first)

Run all drift signals: scope drift, write loops, error recurrence, semantic shift, token pressure

{"drift":false} or {"drift":true,"evidence":[...],"suggested_restore":"...","label":"..."}

cairn_log_usage(tokens, limit)

async

Record reported context usage for the token-pressure signal

{"status":"logged"}

cairn_log_event(type, data)

async

Record a write/error/decision event for drift analysis

{"status":"logged"}

cairn_acknowledge_handoff()

sync

Delete the RECOVERY_ACTIVE gate and archive HANDOFF.md

{"status":"acknowledged","archived":"..."}

How an MCP call flows

flowchart TD
    AI["AI coding tool<br/>(Claude Code / Cursor / Roo / Windsurf)"] -->|MCP protocol| SRV["Cairn MCP server<br/>(session starts on connect)"]

    SRV --> CP["cairn_checkpoint(label?)"]
    SRV --> LOG["cairn_log_event / cairn_log_usage"]
    SRV --> DRIFT["cairn_check_drift()"]
    SRV --> RB["cairn_rollback(checkpoint_id)"]
    SRV --> ACK["cairn_acknowledge_handoff()"]

    %% checkpoint path (async)
    CP -->|"ACK immediately: {status: queued, id}"| AI
    CP -.enqueue.-> Q["operation queue<br/>(worker thread)"]
    Q --> SNAP["git snapshot on shadow branch<br/>cairn/snapshots/{session}/{checkpoint}"]
    SNAP --> ROW["insert checkpoint row in SQLite"]
    ROW -->|"on failure: revert git ref"| Q

    %% logging path
    LOG --> DB[("SQLite<br/>.cairn/cairn.db")]

    %% drift path
    DRIFT --> DET{"drift signals?<br/>scope drift · write loops ·<br/>error recurrence · semantic shift"}
    DET -->|no| CLEAN["{drift: false}"] --> AI
    DET -->|yes| EV["{drift: true, evidence, suggested_restore}"] --> AI
    EV --> USER{"user decides"}
    USER -->|dismiss| DISMISS["cairn dismiss<br/>(signals reset)"]
    USER -->|inspect| INSPECT["rollback with inspect=true<br/>creates cairn/recovery/* branch"]
    USER -->|rollback| RB

    %% rollback path (sync)
    RB --> STASH["git stash push -u<br/>(uncommitted work preserved)"]
    STASH --> RESET["git reset --hard to checkpoint<br/>(user stays on their branch)"]
    RESET --> HANDOFF["generate HANDOFF.md<br/>(LiteLLM or heuristic)"]
    HANDOFF --> GATE["write .cairn/RECOVERY_ACTIVE gate"]
    GATE -->|"{status: restored, stash_ref}"| AI

    %% recovery path (next session)
    GATE -.next session, branch matches.-> ACK
    ACK --> ARCHIVE["delete gate, archive handoff,<br/>AI reads HANDOFF.md and resumes informed"]

Development

pip install -e .[dev]
pytest

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Provides AI coding assistants with persistent project memory by capturing development checkpoints during git commits, branch switches, and inactivity. It enables seamless task resumption through tools that retrieve session history, momentum, and synthesized re-entry briefings.
    28 npm
    3
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Persistent cross-session memory for AI coding assistants, automatically capturing and injecting context across sessions via MCP tools.
    9 npm
    11
    AGPL 3.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI coding agents to checkpoint workspace state, branch parallel attempts, inspect diffs, and roll back to known-good states mid-task through MCP tools, with automatic safety checkpoints to prevent data loss.
    4 npm
    MIT