Install in Claude Code
Copygit clone --depth 1 https://github.com/asfbay-bit/opchain-skills /tmp/oc-checkpoint-protocol && cp -r /tmp/oc-checkpoint-protocol/skills/oc-checkpoint-protocol ~/.claude/skills/oc-checkpoint-protocolThen start a new Claude Code session; the skill loads automatically.
Definition
SKILL.md
# Checkpoint Protocol
A cross-skill convention for session persistence. Any skill that runs multi-step
workflows across conversations adopts this protocol to save, resume, and recover
state without the user re-explaining context.
This is a **protocol**, not a skill. It defines a file format, naming convention,
resume behavior, and integration contract that individual skills implement. Think
of it like HTTP — the spec lives here, the implementations live in each skill.
### Two versions, don't confuse them
- **`protocol_version`** — the **on-disk schema version**, currently `"1.0"`. It
lives inside every checkpoint file and only changes when the file *shape* changes
in a way the validator must know about. The validator (`scripts/checkpoint.mjs`)
enforces it.
- **Skill release version** — the `version` in this file's YAML frontmatter. It
tracks the evolution of the *docs and tooling* (the `pm_refs` extension, the
`doctor`/`next` commands, etc.) and moves independently. oc-release-ops bumps it.
A new field like `pm_refs` is an **optional, additive extension** under schema
`1.0` — old checkpoints stay valid, new ones may include it. The schema version
does **not** bump just because the tooling grew a feature.
---
## Problem Statement
Claude's context resets between conversations. Multi-step skills (oc-app-architect,
tri-dev, oc-reverse-spec, oc-stack-forge, oc-code-auditor, oc-deploy-ops, oc-git-ops) lose all
progress when a session ends. Today:
- **oc-reverse-spec** has a bespoke `checkpoint.md` — the most mature implementation
- **tri-dev** has file-based state (contracts, eval reports) but no formal resume
- **oc-app-architect** has gates but zero session persistence
- **oc-stack-forge**, **life-architect**, and others have no continuity at all
Each skill reinvents (or doesn't) its own persistence. The user pays the cost:
re-explaining context, re-reading files, and hoping Claude picks up where it left off.
---
## Core Concepts
### 1. The Checkpoint File
Every checkpoint-aware skill writes a single `checkpoint.json` file to its project
directory. JSON (not markdown) because it's machine-parseable for cross-skill reads.
**Location:** `{project-dir}/.checkpoints/{skill-name}.checkpoint.json`
Example paths:
```
/home/claude/gtrack/.checkpoints/oc-app-architect.checkpoint.json
/home/claude/gtrack/.checkpoints/oc-code-auditor.checkpoint.json
/home/claude/gtrack/.checkpoints/oc-reverse-spec.checkpoint.json
```
Multiple skills can checkpoint the same project simultaneously without collision.
### 2. Checkpoint Schema
```jsonc
{
// === HEADER (required) ===
"protocol_version": "1.0", // On-disk schema version (not the skill release version)
"skill": "oc-app-architect", // Skill that owns this checkpoint
"project": "gtrack", // Human-readable project name
"project_dir": "/home/claude/gtrack", // Absolute path
"created_at": "2026-03-31T14:00:00Z",
"updated_at": "2026-03-31T15:30:00Z",
// === PROGRESS (required) ===
"phase": "build-loop", // Current phase name (skill-defined)
"step": "sprint-2-eval-round-1", // Current step within phase
"status": "in_progress", // in_progress | blocked | complete | failed
"progress_summary": "Sprint 1 passed (8.2/10). Sprint 2 generator built, evaluator running.",
// === PROGRESS TABLE (recommended; validator warns if missing while in_progress) ===
// Ordered list of all phases/steps with completion status
"progress_table": [
{ "id": "planning", "label": "Planner", "status": "complete" },
{ "id": "sprint-1", "label": "Sprint 1: Auth", "status": "complete" },
{ "id": "sprint-2", "label": "Sprint 2: CRUD", "status": "in_progress" },
{ "id": "sprint-3", "label": "Sprint 3: UI", "status": "not_started" }
],
// === CONTEXT PRIMER (recommended — this is what lets resume skip a full re-read) ===
// Dense, self-contained summary. A new session reads ONLY this + generated files
// to resume work. Must be complete enough that re-reading the full codebase or
// re-running prior phases is unnecessary.
"context_primer": {
"key_decisions": [
"Stack: Hono + D1 + Workers. Auth: WebAuthn passkeys.",
"Two users: Aidan (admin), Dan (viewer). User IDs in D1.",
"Sprint 1 delivered auth + session middleware. All tests pass."
],
"generated_files": [
"spec.md",
"sprint-plan.md",
"sprints/sprint-1/contract.md",
"sprints/sprint-1/eval-round-1.md",
"sprints/sprint-1/eval-round-2.md",
"src/auth/passkey.ts",
"src/middleware/session.ts"
],
"user_preferences": [
"Prefers table-based layouts",
"Terminal/dark aesthetic",
"Direct, concise communication"
]
},
// === BLOCKERS & OPEN QUESTIONS (optional) ===
"blockers": [
{
"id": "b1",
"description": "Evaluator flagged missing rate limiting on auth endpoints",
"blocking": "sprint-2",
"needs": "user_decision", // user_decision | code_fix | external_dep
"proposed_resolution": "Add rate-limit middleware in sprint 2 scope"
}
],
// === NEXT ACTIONS (required while status is in_progress — resume reads [0] first) ===
// What the next session should do FIRST. Ordered by priority.
// Each item is a string, or { "text": "...", "done_when": "<shell cmd>" } so a
// session can self-verify completion. `checkpoint done <skill>` pops item [0].
"next_actions": [
"Read evaluator report: sprints/sprint-2/eval-round-1.md",
"Fix rate limiting gap flagged in blocker b1",
{ "text": "Re-run evaluator on sprint 2", "done_when": "npm test" }
],
// === SKILL-SPECIFIC STATE (optional) ===
// Freeform object for skill-internal state that doesn't fit the schema above.
// Other skills should NOT read this section — it's private to the owning skill.
"skill_state": {
"current_sprint": 2,
"