longthread
← all plugins

programme

A Claude Code plugin that carries multi-session work across session boundaries: a durable ledger, a pointer that teaches a session when to write to it, an interviewed handoff, and a guard that fires when a session changes code without moving the record.

plugin install programme@longthread

What it is

Long-running work spans many sessions. Each one ends with context exhausted and its findings in scrollback; the next re-derives position from the code, repeats settled decisions, and loses the expensive lessons — the ones a defect taught, not a design. programme gives a repo a place to put that: docs/programmes/<slug>/ledger.md, kept under ~250 lines, read in full at the start of every session.

It does not summarize your work for you. /programme:handoff interviews — "what did you measure", "what did you get wrong", "which claims in the ledger are now false" — because a prompt that asks "what did you do?" produces a changelog, and a changelog is not what makes a handoff worth reading.

The evidence that the artifact is the mechanism, not the command

This plugin was extracted from a repo that solved session continuity over roughly fifteen sessions before any of this existed. Measured against docs/programme-ledger.md's git history, 2026-08-06 → 2026-08-12:

measure value
commits touching the ledger 58 in 7 days
per session (~15 sessions) ~4
growth 150 → 2322 lines, monotonic, 122 headers
commands that existed to trigger a write none
hooks that existed to trigger a write none
skills that existed to trigger a write none

Four writes per session, at phase boundaries, with no hook and no skill in existence, and no command that ever triggered one — a read-only precursor to /programme:resume existed for 42 of the 58 commits (added 2026-08-07) but only ever read the ledger, never wrote to it. What drove the writes was two pieces of prose that were always loaded: the ledger header, which states its own maintenance rule and is re-read every time the file is opened, and a CLAUDE.md pointer with a precedence rule. This plugin's first job is to install those two things — a ledger that teaches its own upkeep, and the pointer that carries the cadence — giving a new repo in minutes what took the source repo several sessions to grow on its own. The commands are conveniences layered on top of that artifact, not the mechanism itself.

Install

/plugin marketplace add longthread/claude-plugins
/plugin install programme@longthread

Verified 2026-08-14: installs, enables, and the hooks resolve a real programme. /programme:init was run against a 2710-line ledger, and the Stop guard was confirmed to fire when code moves and the ledger does not, then latch silent.

To install from a local clone instead — edits go live on the next session start, which is what you want while developing — give marketplace add the path to the marketplace root (the one holding .claude-plugin/marketplace.json), not this plugin's directory:

/plugin marketplace add /abs/path/to/claude-plugins

A local marketplace is read in place, never copied. The recorded installLocation is the path you gave. Point it at a clone that stays put — never at a directory inside a repo whose branch you switch, or the plugin vanishes globally on the first checkout that predates it.

The four commands

The config file

.claude/session-continuity.json, created by /programme:init if absent, with docsRoot and compareBranch only:

{
  "docsRoot": "docs",
  "compareBranch": "origin/main"
}

A dedicated file rather than settings.json: the gate list is structured, which rules out env, and unknown keys in settings.json are not a contract worth relying on.

When NOT to use it

This fits multi-session programme work with a running thread — the kind where a session would ever have to ask "where were we?" It does not fit a repo that is a series of unrelated tickets. Point it at one of those and the ledger goes stale, and a stale ledger is worse than no ledger: it actively misleads, the way a comment describing behaviour the code no longer has misleads. /programme:init asks before bootstrapping for exactly this reason, and will refuse on silence.

With no .claude/session-continuity.json and no docs/programmes/ directory, every hook exits 0 silently — a repo that hasn't opted in feels nothing.

Deliberately not built

PreCompact is unverified

hooks/pre-compact.sh warns when the ledger hasn't moved and a compaction is about to discard whatever hasn't been written. This channel is unverified: PreCompact is not a confirmed member of Claude Code's hookSpecificOutput union and does not support prompt-type hooks, so its output may reach only the user, never the model. Nothing in this design depends on it. The load-bearing mechanism is the ledger header and the CLAUDE.md pointer (see above); SessionStart's additionalContext re-injection after compaction is confirmed and does the real work of post-compaction recovery.

Where each rule lives — exactly one home

Every rule below has exactly one home, in prose where the rule is about when or why, and as a table schema where the rule can be a column instead. tests/test-templates.sh reads the six markdown templates and tests/test-commands.sh reads the four commands; both assert that a rule appears in its home and that it does not appear anywhere else. Neither reaches the hooks.

Both readers fold newlines to spaces before matching. Without that, a rule restated across a formatter's line wrap satisfies the negative assertion while the duplication is right there — the guard passes precisely when it should fire. That hole was live until 2026-08-14.

session-start.sh restates two of these rules (the ledger-outranks-handoff precedence and "verify, don't trust") when it re-injects the ledger position after compaction; whether that is duplication or the only thing carrying those two rules across a compaction boundary is open (the live-run checklist's Question 2, in the repo this was extracted from).

rule home form
when to write (the cadence) CLAUDE.md pointer prose — needed away from the file
ledger outranks every handoff CLAUDE.md pointer prose — the only file above both
correct in place ledger.md header prose — genuinely about that file
cite or flag UNVERIFIED ledger.md header prose — governs its narrative
absolute dates ledger.md header prose
archive past 250 lines ledger.md header prose — about its own size
who decided, and why ledger.md schema — who | why columns
gate trust ledger.md Gates table schema — trust column
don't trust a figure, re-derive NEXT-SESSION.md schema — verify with column
terminal conditions as observables NEXT-SESSION.md schema — command + expected
fix shape, not a title both deferred tables schema — current behaviour | fix shape
promotion before close deferred.md header prose — that file's lifecycle
verify against the tree commands/resume.md procedure
resolve which programme is active commands/resume.md procedure — the others defer to it
report without repairing commands/status.md procedure
the four interview questions commands/handoff.md procedure

fix shape appears in two tables — deferred.md and deferred-work.md — because deferred work has two lifetimes: some items die with the programme, some outlive it. That is one schema definition shared by two tables, not a rationale stated twice.

One pair is prose on both sides deliberately: deferred.md's header says an item that outlives the programme belongs in deferred-work.md, and deferred-work.md's header says an item scoped to one programme belongs back in deferred.md. Each file states its own scope, which is unique per file; the routing half is the same rule read from the opposite side, and both halves have to exist so a maintainer who opens only one of the two files can still find the door.

Full rationale for every design decision here, including the three corrections made against measured evidence: docs/tooling/2026-08-12-session-continuity-plugin-design.md in the repo this plugin was extracted from.