
Checkpoint Resume
- 144 installs
- 213 repo stars
- Updated August 4, 2026
- yonatangross/orchestkit
Persist long-running agent task state, recover after interruption, and resume multi-step workflows without redoing completed orchestration steps.
About
Checkpoint-resume in yonatangross/orchestkit enables Claude Code agents to save orchestration progress and continue later—recording completed steps, pending work, and context so lengthy build, research, or migration flows survive restarts without redundant execution.
- Durable checkpoints for long agent jobs
- Safe resume after failure or pause
- OrchestKit workflow continuity patterns
- Reduces duplicated tool calls and cost
- Supports multi-phase autonomous runs
Checkpoint Resume by the numbers
- 144 all-time installs (skills.sh)
- +1 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #3,422 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/yonatangross/orchestkit --skill checkpoint-resumeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 144 |
|---|---|
| repo stars | ★ 213 |
| Last updated | August 4, 2026 |
| Repository | yonatangross/orchestkit ↗ |
What it does
Persist long-running agent task state, recover after interruption, and resume multi-step workflows without redoing completed orchestration steps.
Files
Checkpoint Resume
Rate-limit-resilient pipeline orchestrator. Saves progress to .claude/pipeline-state.json after every phase so long sessions survive interruptions.
Quick Reference
| Category | Rule | Impact | Key Pattern |
|---|---|---|---|
| Phase Ordering | ${CLAUDE_SKILL_DIR}/rules/ordering-priority.md | CRITICAL | GitHub issues/commits first, file-heavy phases last |
| State Writes | ${CLAUDE_SKILL_DIR}/rules/state-write-timing.md | CRITICAL | Write after every phase, never batch |
| Mini-Commits | ${CLAUDE_SKILL_DIR}/rules/checkpoint-mini-commit.md | HIGH | Every 3 phases, checkpoint commit format |
Total: 3 rules across 3 categories
On Invocation
If `.claude/pipeline-state.json` exists: run scripts/show-status.sh to display progress, then ask to resume, pick a different phase, or restart. Load Read("${CLAUDE_SKILL_DIR}/references/resume-decision-tree.md") for the full decision tree.
If no state file exists: ask the user to describe the task, build an execution plan, write initial state via scripts/init-pipeline.sh <branch>, begin Phase 1.
Execution Plan Structure
{
"phases": [
{ "id": "create-issues", "name": "Create GitHub Issues", "dependencies": [], "status": "pending" },
{ "id": "commit-scaffold", "name": "Commit Scaffold", "dependencies": [], "status": "pending" },
{ "id": "write-source", "name": "Write Source Files", "dependencies": ["commit-scaffold"], "status": "pending" }
]
}Phases with empty dependencies may run in parallel via Task sub-agents (when they don't share file writes).
After Each Phase
1. Update .claude/pipeline-state.json — see Read("${CLAUDE_SKILL_DIR}/rules/state-write-timing.md") 2. Every 3 phases: create a mini-commit — see Read("${CLAUDE_SKILL_DIR}/rules/checkpoint-mini-commit.md")
References
Load on demand with Read("${CLAUDE_SKILL_DIR}/references/<file>"):
| File | Content |
|---|---|
references/pipeline-state-schema.md | Full field-by-field schema with examples |
references/pipeline-state.schema.json | Machine-readable JSON Schema for validation |
references/resume-decision-tree.md | Logic for resuming, picking phases, or restarting |
Scripts
scripts/init-pipeline.sh <branch>— print skeleton state JSON to stdoutscripts/show-status.sh [path]— print human-readable pipeline status (requiresjq)
Key Decisions
| Decision | Recommendation |
|---|---|
| Phase granularity | One meaningful deliverable per phase (a commit, a set of issues, a feature) |
| Parallelism | Task sub-agents only for phases with empty dependencies that don't share file writes |
| Rate limit recovery | State is already saved — re-invoke /checkpoint-resume to continue |
Plan mode preserved across--resume(CC 2.1.132+) —--permission-mode planis honored on resume, andExitPlanModere-applies plan mode for the rest of the session. Seeconfigure/references/cc-version-settings.md(## CC 2.1.132 Settings).
Claude-managed worktrees are unlocked on finish (CC 2.1.157+) andEnterWorktreecan switch worktrees mid-session — a resumed session can clean up prior worktrees with plaingit worktree remove/prune.
/cd (CC 2.1.169+) moves the session to a new working directory WITHOUT breaking the prompt cache — prefer it over restarting when a checkpointed task continues in a different directory (e.g. hopping into a manually created worktree).Self-hosted runners: thepost-sessionlifecycle hook (CC 2.1.169+) runs after session end and before workspace deletion — the right place to snapshot uncommitted checkpoint state or export.claude/chain/handoffs that would otherwise be destroyed with the workspace.
Pipeline State Schema
The pipeline state file (.claude/pipeline-state.json) is the source of truth for checkpoint/resume. It is validated against .claude/schemas/pipeline-state.schema.json.
Top-Level Shape
{
"completed_phases": [...],
"current_phase": {...},
"remaining_phases": [...],
"context_summary": {...},
"created_at": "2026-02-19T10:00:00Z",
"updated_at": "2026-02-19T10:45:00Z"
}completed_phases
Array of phases that finished successfully. Append-only — never remove entries.
{
"id": "create-issues",
"name": "Create GitHub Issues",
"timestamp": "2026-02-19T10:05:00Z",
"commit_sha": "a1b2c3d" // optional — only if phase produced a commit
}current_phase
The phase actively being executed. progress_description is a free-text note describing partial work done so far within this phase — helps resume after interruption.
{
"id": "write-source",
"name": "Write Source Files",
"progress_description": "Completed auth module, starting billing module"
}Set current_phase to null when all phases are done.
remaining_phases
Ordered list of phases not yet started. Remove a phase from here when it moves to current_phase.
{
"id": "final-commit",
"name": "Final Commit",
"dependencies": ["write-source", "write-tests"]
}dependencies: IDs of phases that must complete before this one. Empty array = can run immediately or in parallel.
context_summary
Compact context snapshot for restoring session state after interruption.
{
"branch": "feat/issue-42-new-feature",
"key_decisions": [
"Used postgres not mongo for user storage",
"Chose REST over GraphQL for external API"
],
"file_paths": [
"/Users/dev/project/src/auth/login.ts",
"/Users/dev/project/src/billing/invoice.ts"
]
}Update file_paths each time a phase creates or significantly modifies files.
Full Example
{
"completed_phases": [
{
"id": "create-issues",
"name": "Create GitHub Issues",
"timestamp": "2026-02-19T10:05:00Z"
},
{
"id": "scaffold-commit",
"name": "Commit Initial Scaffold",
"timestamp": "2026-02-19T10:20:00Z",
"commit_sha": "a1b2c3d"
}
],
"current_phase": {
"id": "write-source",
"name": "Write Source Files",
"progress_description": "auth module done, starting billing"
},
"remaining_phases": [
{
"id": "write-tests",
"name": "Write Tests",
"dependencies": ["write-source"]
},
{
"id": "final-commit",
"name": "Final Commit",
"dependencies": ["write-source", "write-tests"]
}
],
"context_summary": {
"branch": "feat/issue-42-dashboard",
"key_decisions": ["REST over GraphQL", "Postgres for storage"],
"file_paths": ["/project/src/auth/login.ts"]
},
"created_at": "2026-02-19T10:00:00Z",
"updated_at": "2026-02-19T10:22:00Z"
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "pipeline-state.schema.json",
"title": "PipelineState",
"description": "Checkpoint state for the checkpoint-resume skill. Written to .claude/pipeline-state.json after each phase completes.",
"type": "object",
"required": ["completed_phases", "current_phase", "remaining_phases", "context_summary", "created_at", "updated_at"],
"additionalProperties": false,
"properties": {
"completed_phases": {
"type": "array",
"description": "Phases that have finished successfully, in completion order.",
"items": {
"type": "object",
"required": ["id", "name", "timestamp"],
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"description": "Unique phase identifier (e.g. 'phase-1', 'create-issues')."
},
"name": {
"type": "string",
"description": "Human-readable phase name."
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 UTC timestamp when the phase completed."
},
"commit_sha": {
"type": "string",
"pattern": "^[0-9a-f]{7,40}$",
"description": "Git commit SHA produced by this phase, if any."
}
}
}
},
"current_phase": {
"type": "object",
"description": "The phase currently being executed. Null when the pipeline is complete.",
"required": ["id", "name", "progress_description"],
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"description": "Unique phase identifier."
},
"name": {
"type": "string",
"description": "Human-readable phase name."
},
"progress_description": {
"type": "string",
"description": "Free-text description of what has been done so far within this phase."
}
}
},
"remaining_phases": {
"type": "array",
"description": "Phases not yet started, in intended execution order.",
"items": {
"type": "object",
"required": ["id", "name", "dependencies"],
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"description": "Unique phase identifier."
},
"name": {
"type": "string",
"description": "Human-readable phase name."
},
"dependencies": {
"type": "array",
"description": "IDs of phases that must complete before this phase can start.",
"items": {
"type": "string"
},
"uniqueItems": true
}
}
}
},
"context_summary": {
"type": "object",
"description": "Snapshot of key context to restore after a rate-limit interruption.",
"required": ["branch", "key_decisions", "file_paths"],
"additionalProperties": false,
"properties": {
"branch": {
"type": "string",
"description": "Git branch the pipeline is running on."
},
"key_decisions": {
"type": "array",
"description": "Important decisions made during the pipeline (e.g. 'used postgres not mongo').",
"items": {
"type": "string"
}
},
"file_paths": {
"type": "array",
"description": "Absolute paths of files created or significantly modified so far.",
"items": {
"type": "string"
}
}
}
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 UTC timestamp when the pipeline was first created."
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "ISO 8601 UTC timestamp of the most recent state write."
}
}
}
Resume Decision Tree
Use this decision tree when /checkpoint-resume is invoked to determine the correct action.
On Invocation
Does .claude/pipeline-state.json exist?
│
├── NO → Ask user to describe the multi-phase task
│ → Build execution plan
│ → Write initial state file
│ → Begin Phase 1
│
└── YES → Read the state file
→ Show resume summary (see format below)
→ Ask: "Resume from [current_phase.name]? (y/n/restart)"
│
├── y → Continue from current_phase
│ (respect progress_description for partial phases)
│
├── n → Ask: "Abandon pipeline or pick a different phase?"
│ ├── abandon → Delete state file, start fresh
│ └── pick → List remaining_phases, let user choose
│
└── restart → Confirm with user → Delete state file → restartResume Summary Format
Show this before asking the user to confirm:
Pipeline: <task description from context_summary or phases>
Branch: <context_summary.branch>
Completed (N phases):
✓ Phase 1: Create GitHub Issues (10:05)
✓ Phase 2: Commit Scaffold (10:20, sha: a1b2c3d)
In progress:
→ Phase 3: Write Source Files
Progress: auth module done, starting billing
Remaining (M phases):
· Phase 4: Write Tests
· Phase 5: Final Commit
Resume from "Write Source Files"? (y/n/restart)When State File is Corrupted
If .claude/pipeline-state.json fails JSON parse or schema validation:
1. Warn the user: "State file is malformed" 2. Show raw content so user can assess what was completed 3. Ask: "Attempt manual recovery or start fresh?" 4. Do NOT silently overwrite — the file may contain the only record of completed work
Parallel Phase Execution
Phases with empty dependencies arrays can run concurrently via Task sub-agents:
Phase A (dependencies: []) ─┐
Phase B (dependencies: []) ─┤─ Run in parallel via Task
Phase C (dependencies: [A]) ─┘─ Wait for A, then runOnly parallelize when:
- Both phases have empty or satisfied
dependencies - Phases do NOT write to the same files
- Phases do NOT both run
git commit(would cause conflicts)
Rule Categories
1. Phase Ordering Priority (ordering) — CRITICAL — 1 rule
Schedule phases so the highest-value, hardest-to-reconstruct work (GitHub issues, commits) completes before file-heavy phases — minimizing loss when a rate limit hits mid-session.
ordering-priority.md— Priority ranking, incorrect vs. correct phase ordering examples, parallelization guidance
2. State Write Timing (state-timing) — CRITICAL — 1 rule
Write .claude/pipeline-state.json immediately after every phase completes — never accumulate updates — so a rate-limit hit always leaves a valid resume point.
state-write-timing.md— Correct write-after-phase pattern, state write checklist, fields to update on each write
3. Checkpoint Mini-Commit (checkpoint-commit) — HIGH — 1 rule
Every 3 completed phases, create a mini-commit that captures work in progress and provides a git recovery point if later phases fail.
checkpoint-mini-commit.md— Cadence rule, mini-commit format with Co-Authored-By, staging command, anti-pattern examples
[Rule Name]
[Brief description — 1-2 sentences.]
Incorrect:
// Bad patternCorrect:
// Good patternKey rules:
- [Rule 1]
- [Rule 2]
- [Rule 3]
Reference: [link]
Checkpoint Mini-Commit
Every 3 completed phases, create a mini-commit that captures work in progress. This provides a git recovery point even if later phases fail.
When to commit:
Phase 1 done → state write only
Phase 2 done → state write only
Phase 3 done → state write + mini-commit ← checkpoint
Phase 4 done → state write only
Phase 5 done → state write only
Phase 6 done → state write + mini-commit ← checkpointMini-commit format:
git add -A
git commit -m "checkpoint: phases N-M complete
Completed:
- Phase N: <name>
- Phase N+1: <name>
- Phase N+2: <name>
Remaining: <count> phases
Co-Authored-By: Claude <noreply@anthropic.com>"Incorrect — one giant commit at the end:
# Do 12 phases of work...
git add -A
git commit -m "feat: complete all pipeline work"
# If phases 10-12 fail, no checkpoint existsCorrect — checkpoint every 3 phases:
# After phase 3
git commit -m "checkpoint: phases 1-3 complete\n\nCo-Authored-By: Claude <noreply@anthropic.com>"
# After phase 6
git commit -m "checkpoint: phases 4-6 complete\n\nCo-Authored-By: Claude <noreply@anthropic.com>"Key rules:
- Count is based on completed phases in the current pipeline run, not total commits
- Stage everything (
git add -A) — the checkpoint captures full work-in-progress state - Never skip a checkpoint because "almost done" — rate limits don't warn first
- Include Co-Authored-By attribution in every checkpoint commit
Phase Ordering Priority
When a rate limit hits, work done in the current session is lost. Order phases so the hardest-to-reconstruct work finishes first.
Priority order (highest → lowest value if lost):
1. GitHub issue creation (lost = no tracking, no auto-close links) 2. Git commits with code changes (lost = untracked work) 3. File creation / large edits (recoverable from context) 4. Documentation / reference updates (lowest risk to lose last)
Incorrect — file-heavy phases scheduled before issue creation:
{
"phases": [
{ "id": "write-files", "name": "Write all source files" },
{ "id": "create-issues", "name": "Create GitHub issues" },
{ "id": "commit", "name": "Commit changes" }
]
}Correct — issues and commits scheduled first:
{
"phases": [
{ "id": "create-issues", "name": "Create GitHub issues" },
{ "id": "commit-scaffold", "name": "Commit initial scaffold" },
{ "id": "write-files", "name": "Write all source files" },
{ "id": "commit-final", "name": "Commit completed work" }
]
}Key rules:
- Always schedule
gh issue createcalls in the first phase - Commits with
Closes #Nreferences come second — they link issues - Independent phases with no shared dependencies run in parallel via Task sub-agents
- Never defer issue creation to "after the code is done"
State Write Timing
Write .claude/pipeline-state.json immediately after every phase completes. Never accumulate updates.
Incorrect — batching state writes to the end:
// Run all phases, then save state once
for (const phase of phases) {
await runPhase(phase);
}
await writeState({ completed_phases: phases }); // Lost if interrupted!Correct — write state after every phase:
for (const phase of phases) {
await runPhase(phase);
// Write immediately — before starting next phase
await writeState({
completed_phases: [...prev.completed_phases, { ...phase, timestamp: new Date().toISOString() }],
current_phase: nextPhase,
remaining_phases: phasesAfterNext,
updated_at: new Date().toISOString()
});
}State write checklist (after each phase):
- [ ] Move completed phase into
completed_phaseswithtimestamp - [ ] Add
commit_shaif the phase produced a git commit - [ ] Set
current_phaseto the next pending phase - [ ] Remove completed phase from
remaining_phases - [ ] Update
updated_at - [ ] Update
context_summary.file_pathswith any new files created
Key rules:
- Write state BEFORE starting the next phase, not after
- Never batch multiple phase completions into one write
- If a phase produces a commit, capture the SHA:
git rev-parse --short HEAD - The state file is the source of truth for resume — it must be current
#!/usr/bin/env bash
# Generated by OrchestKit Claude Plugin
# Created: 2026-02-19
# init-pipeline.sh — Initialize a fresh pipeline-state.json
# Usage: scripts/init-pipeline.sh [branch]
# Output: prints JSON to stdout; redirect to .claude/pipeline-state.json
set -euo pipefail
if [[ "${1:-}" == "--help" ]]; then
echo "Usage: scripts/init-pipeline.sh [branch]"
echo "Prints a skeleton pipeline-state.json to stdout."
echo "Redirect to .claude/pipeline-state.json to initialize."
exit 0
fi
BRANCH="${1:-$(git branch --show-current 2>/dev/null || echo "unknown")}"
NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
cat <<EOF
{
"completed_phases": [],
"current_phase": {
"id": "",
"name": "",
"progress_description": ""
},
"remaining_phases": [],
"context_summary": {
"branch": "${BRANCH}",
"key_decisions": [],
"file_paths": []
},
"created_at": "${NOW}",
"updated_at": "${NOW}"
}
EOF
#!/usr/bin/env bash
# Generated by OrchestKit Claude Plugin
# Created: 2026-02-19
# show-status.sh — Print a human-readable pipeline status summary
# Usage: scripts/show-status.sh [path/to/pipeline-state.json]
# Requires: jq
set -euo pipefail
if [[ "${1:-}" == "--help" ]]; then
echo "Usage: scripts/show-status.sh [path/to/pipeline-state.json]"
echo "Prints a human-readable summary of the pipeline state."
exit 0
fi
STATE_FILE="${1:-.claude/pipeline-state.json}"
if [[ ! -f "$STATE_FILE" ]]; then
echo "No pipeline state found at: $STATE_FILE"
echo "Run /checkpoint-resume to start a new pipeline."
exit 0
fi
if ! jq empty "$STATE_FILE" 2>/dev/null; then
echo "ERROR: $STATE_FILE is not valid JSON"
exit 1
fi
BRANCH=$(jq -r '.context_summary.branch // "unknown"' "$STATE_FILE")
COMPLETED=$(jq -r '.completed_phases | length' "$STATE_FILE")
REMAINING=$(jq -r '.remaining_phases | length' "$STATE_FILE")
CURRENT_NAME=$(jq -r '.current_phase.name // "none"' "$STATE_FILE")
CURRENT_PROGRESS=$(jq -r '.current_phase.progress_description // ""' "$STATE_FILE")
UPDATED=$(jq -r '.updated_at' "$STATE_FILE")
echo "Pipeline Status"
echo "==============="
echo "Branch: $BRANCH"
echo "Updated: $UPDATED"
echo ""
echo "Completed ($COMPLETED phases):"
jq -r '.completed_phases[] | " \u2713 \(.name) (\(.timestamp | split("T")[1] | split("Z")[0]))\(if .commit_sha then " sha:\(.commit_sha)" else "" end)"' "$STATE_FILE" 2>/dev/null || true
echo ""
echo "In progress:"
if [[ "$CURRENT_NAME" != "none" && "$CURRENT_NAME" != "" ]]; then
echo " -> $CURRENT_NAME"
[[ -n "$CURRENT_PROGRESS" ]] && echo " $CURRENT_PROGRESS"
else
echo " (none)"
fi
echo ""
echo "Remaining ($REMAINING phases):"
jq -r '.remaining_phases[] | " . \(.name)\(if (.dependencies | length) > 0 then " [needs: \(.dependencies | join(", "))]" else "" end)"' "$STATE_FILE" 2>/dev/null || true
{
"skill": "checkpoint-resume",
"version": "2.0.0",
"testCases": [
{
"id": "fresh-start-no-state-file",
"rule": null,
"query": "I need to implement a large feature spanning 10+ files and several GitHub issues",
"expectedBehavior": [
"Detects no .claude/pipeline-state.json exists and prompts for task description",
"Asks the user to describe all phases of the task",
"Runs scripts/init-pipeline.sh <branch> to write initial state with all phases set to pending",
"Begins Phase 1 after state is initialized, following phase-ordering rules"
]
},
{
"id": "resume-from-existing-state",
"rule": "state-write-timing",
"query": "Resume my interrupted migration pipeline",
"expectedBehavior": [
"Detects .claude/pipeline-state.json exists and runs scripts/show-status.sh",
"Displays human-readable progress summary showing completed, in-progress, and pending phases",
"Asks whether to resume from the last incomplete phase, pick a different phase, or restart",
"Continues from the correct phase after user confirmation, not from Phase 1"
]
},
{
"id": "phase-failed-mid-execution",
"rule": "ordering-priority",
"query": "The pipeline stopped mid-way through the file-writing phase due to a rate limit",
"expectedBehavior": [
"State file shows the failed phase as in-progress or failed, not completed",
"Reads resume-decision-tree references/resume-decision-tree.md to determine recovery path",
"Does not rerun already-completed earlier phases (GitHub issues, commits)",
"Resumes from the failed phase, re-attempting only incomplete work within that phase"
]
},
{
"id": "all-phases-complete",
"rule": "state-write-timing",
"query": "Check the pipeline status \u2014 I think everything is done",
"expectedBehavior": [
"Runs scripts/show-status.sh and finds all phases marked as completed",
"Reports the pipeline as fully complete with a summary of all phases executed",
"Does not prompt for resume or additional phases",
"Optionally suggests cleaning up .claude/pipeline-state.json or archiving it"
]
},
{
"id": "checkpoint-mini-commit",
"rule": "checkpoint-mini-commit",
"query": "How often should I create checkpoint commits during a long pipeline to avoid losing work?",
"expectedBehavior": [
"Creates a mini-commit every 3 completed phases as a git recovery point for the pipeline",
"Uses checkpoint commit format to distinguish recovery points from regular feature commits",
"Provides git recovery point even if later phases fail due to rate limits or errors",
"Combines state writes after every phase with periodic mini-commits for defense in depth"
]
}
]
}