Claude-skill-registry checkpoint-protocol

Human interaction protocol with automation-first rule. Defines checkpoint types and when to use them.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/checkpoint-protocol" ~/.claude/skills/majiayu000-claude-skill-registry-checkpoint-protocol && rm -rf "$T"
manifest: skills/data/checkpoint-protocol/SKILL.md
source content

Checkpoint Protocol

// Project Autopilot - Checkpoint Protocol Skill // Copyright (c) 2026 Jeremy McSpadden jeremy@fluxlabs.net

Golden Rule: If it has CLI/API, Claude does it. Humans only do what requires judgment.


Checkpoint Types

Distribution

TypeFrequencyWhen to Use
checkpoint:human-verify
90%User confirms it works
checkpoint:decision
9%User chooses between options
checkpoint:human-action
1%Truly unavoidable manual step

Type 1: Human-Verify (90%)

Claude automates everything, human just confirms it works.

When to Use

  • Visual verification (UI looks right)
  • Interactive flows (click through app)
  • Functional verification (feature works as expected)

Format

<task type="auto">
  <name>Start dev server</name>
  <action>Run `npm run dev` in background</action>
  <verify>curl localhost:3000 returns 200</verify>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <what-built>Dashboard - server at http://localhost:3000</what-built>
  <how-to-verify>
    Visit http://localhost:3000/dashboard and verify:
    1. Desktop (>1024px): sidebar visible, cards display data
    2. Mobile (375px): single column, bottom nav visible
    3. Click "Settings" - modal opens
  </how-to-verify>
  <resume-signal>Type "approved" or describe issues</resume-signal>
</task>

Key Rules

  • Claude starts servers - User never runs
    npm run dev
  • Claude sets up data - User never creates test data
  • Claude provides URLs - User just clicks links
  • User only looks - Visual/functional confirmation

Example Output

🟢 checkpoint:human-verify

## Built: User Dashboard

**Server running:** http://localhost:3000/dashboard

### Please verify:
1. ✅ Page loads without errors
2. ✅ User data displays correctly
3. ✅ Sidebar navigation works
4. ✅ Mobile view is responsive

**Resume:** Type "approved" or describe issues

Type 2: Decision (9%)

Human must make a choice affecting implementation.

When to Use

  • Technology selection (which library)
  • Architecture decisions (approach A vs B)
  • Design choices (layout, color, UX)
  • Business logic (pricing, limits, rules)

Format

<task type="checkpoint:decision" gate="blocking">
  <decision>Select authentication provider</decision>
  <context>
    Need user auth for the app. Three options with tradeoffs.
  </context>
  <options>
    <option id="supabase">
      <name>Supabase Auth</name>
      <pros>Built-in with DB, free tier generous, email templates</pros>
      <cons>Less customizable UI, vendor lock-in</cons>
    </option>
    <option id="clerk">
      <name>Clerk</name>
      <pros>Best DX, beautiful UI, social logins easy</pros>
      <cons>Paid after 10k MAU, another vendor</cons>
    </option>
    <option id="custom">
      <name>Custom JWT</name>
      <pros>Full control, no external dependencies</pros>
      <cons>More implementation work, security responsibility</cons>
    </option>
  </options>
  <resume-signal>Select: supabase, clerk, or custom</resume-signal>
</task>

Key Rules

  • Present balanced options - No prescriptive recommendation
  • Include context - Why this decision matters
  • Show tradeoffs - Pros AND cons for each
  • No "correct" answer - All options are valid

Example Output

🟡 checkpoint:decision

## Decision Required: Authentication Provider

**Context:** Need user auth. Three approaches available.

| Option | Pros | Cons |
|--------|------|------|
| **Supabase** | Built-in, free tier | Less customizable |
| **Clerk** | Best DX, beautiful UI | Paid after 10k users |
| **Custom JWT** | Full control | More work |

**Select:** supabase, clerk, or custom

Type 3: Human-Action (1% - RARE)

Truly unavoidable manual step. Exhaust all automation first.

When to Use (Only These Cases)

  • Email verification clicks (can't automate)
  • 3D Secure / MFA in payment flow
  • OAuth consent screens in browser
  • Physical hardware interaction
  • Captcha solving

When NOT to Use

  • ❌ Running CLI commands (Claude runs them)
  • ❌ Creating accounts (Claude uses API/CLI)
  • ❌ Starting servers (Claude runs them)
  • ❌ Creating files (Claude creates them)
  • ❌ Configuration (Claude edits files)
  • ❌ Database setup (Claude runs migrations)

Format

<task type="auto">
  <name>Create SendGrid account</name>
  <action>Use API to create account, request verification email</action>
</task>

<task type="checkpoint:human-action">
  <action>Complete email verification</action>
  <why-manual>Email verification requires clicking link in your inbox</why-manual>
  <instructions>
    1. Check your inbox for email from SendGrid
    2. Click the verification link
    3. Return here when done
  </instructions>
  <resume-signal>Type "done" when verified</resume-signal>
</task>

Key Rules

  • Try automation FIRST - Only ask for help when blocked
  • Explain why manual - User should know why this can't be automated
  • Minimize steps - Do everything possible before/after the manual step
  • Golden rule: If it has CLI/API, Claude MUST do it

Example Output

🔴 checkpoint:human-action

## Manual Step Required: Email Verification

**Why manual:** Email verification links can't be automated

### Instructions:
1. Check your inbox for email from SendGrid
2. Click "Verify Email" button
3. Return here when done

**Resume:** Type "done" when verified

Automation-First Checklist

Before using ANY checkpoint, ask:

□ Can I do this with a CLI command?
□ Can I do this with an API call?
□ Can I do this by editing a file?
□ Can I start/stop a server myself?
□ Can I create test data myself?
□ Can I run a script for this?

If ANY answer is YES → Don't ask user to do it.


Common Anti-Patterns

❌ Wrong: Asking User to Run Commands

Please run: npm run dev

✅ Right: Claude Runs Commands

# Claude executes
npm run dev &
# Then presents checkpoint
Visit http://localhost:3000 to verify

❌ Wrong: Asking User to Create Files

Please create a file at src/config.ts with:
[content]

✅ Right: Claude Creates Files

# Claude creates the file
Write src/config.ts
# Done - no checkpoint needed

❌ Wrong: Asking User to Set Up Database

Please create a PostgreSQL database called "myapp"

✅ Right: Claude Uses CLI

# Claude executes
createdb myapp
psql myapp < schema.sql
# Done - no checkpoint needed

❌ Wrong: Decision as Human-Action

Should I use React or Vue?
Please choose and let me know.

✅ Right: Use Decision Checkpoint

<task type="checkpoint:decision">
  <decision>Frontend framework</decision>
  <options>
    <option id="react">React - Larger ecosystem</option>
    <option id="vue">Vue - Simpler learning curve</option>
  </options>
</task>

Checkpoint Flow in Execution

FOR each plan:
    IF plan.autonomous == true:
        Execute all tasks automatically
        Generate LOGBOOK.md

    ELSE IF plan has checkpoint:
        Execute tasks up to checkpoint

        SWITCH checkpoint.type:
            CASE human-verify:
                Present what was built
                Show verification steps
                WAIT for "approved" or issues

            CASE decision:
                Present options with tradeoffs
                WAIT for selection
                Continue with selected option

            CASE human-action:
                Present instructions
                WAIT for "done"

        Continue remaining tasks
        Generate LOGBOOK.md

Integration with Wave Execution

# Plan with checkpoint (runs sequentially, not parallel)
---
phase: 3
plan: 06
wave: 3
autonomous: false
checkpoint:
  type: human-verify
  after_task: 4
  what: "Integration tests pass, dashboard functional"
depends_on: ["04", "05"]
---
  • Plans with checkpoints are NOT spawned in parallel
  • They run sequentially after parallel wave completes
  • Checkpoint pauses execution until user responds

Three-Level Threshold System

Threshold Levels

thresholds:
  warning:
    cost: 10.00        # Log warning, continue
    context: 30        # Log warning, continue (percentage)
    variance: 20       # Log warning, continue (percentage)
    errors: 2          # Log warning, continue (count)

  alert:
    cost: 25.00        # Pause for acknowledgment
    context: 40        # Prepare checkpoint
    variance: 30       # Pause for review
    errors: 3          # Pause for investigation

  stop:
    cost: 50.00        # Hard stop, require user action
    context: 50        # Must checkpoint, terminate
    variance: 50       # Escalate to user
    errors: 5          # Hard stop, likely systemic issue

Threshold Actions

LevelActionUser Impact
WarningLog message, continueNo interruption
AlertPause until acknowledgedOne-time acknowledgment
StopHard stop, checkpointMust address issue

Threshold Handling Protocol

FUNCTION handleThreshold(type, level, value, state):
    """
    Handle threshold breach based on level.
    """
    LOG "⚠️ Threshold triggered: {type} at {level} ({value})"

    SWITCH level:
        CASE "warning":
            # Log and continue
            LOG "📝 Warning: {type} reached {value}"
            logToMetrics(type, level, value)
            CONTINUE

        CASE "alert":
            # Check if already acknowledged
            IF state.acknowledged[type]:
                LOG "⏩ Alert acknowledged previously, continuing..."
                CONTINUE
            ELSE:
                # Pause for acknowledgment
                LOG "🔶 ALERT: {type} at {value}"
                LOG ""
                LOG "This threshold requires acknowledgment to continue."
                LOG "Type 'ack' to acknowledge and continue, or 'stop' to halt."

                response = waitForUserResponse()

                IF response == "ack":
                    state.acknowledged[type] = {
                        value: value,
                        acknowledged_at: now(),
                        session_id: getCurrentSessionId()
                    }
                    saveState(state)
                    LOG "✅ Acknowledged. Continuing..."
                    CONTINUE
                ELSE:
                    createCheckpoint("alert_stop")
                    EXIT

        CASE "stop":
            # Hard stop
            LOG "🛑 STOP: {type} at {value}"
            LOG ""
            LOG "This threshold requires immediate action."
            LOG "Execution cannot continue until issue is resolved."

            createCheckpoint("threshold_stop", {
                type: type,
                value: value,
                reason: "Threshold exceeded"
            })

            EXIT_WITH_CHECKPOINT

Threshold Monitoring

FUNCTION monitorThresholds(execution_state):
    """
    Continuously monitor thresholds during execution.
    """
    thresholds = loadThresholds()

    # Cost threshold
    IF execution_state.total_cost >= thresholds.stop.cost:
        handleThreshold("cost", "stop", execution_state.total_cost, execution_state)
    ELSE IF execution_state.total_cost >= thresholds.alert.cost:
        handleThreshold("cost", "alert", execution_state.total_cost, execution_state)
    ELSE IF execution_state.total_cost >= thresholds.warning.cost:
        handleThreshold("cost", "warning", execution_state.total_cost, execution_state)

    # Context usage threshold
    context_percent = calculateContextUsage()
    IF context_percent >= thresholds.stop.context:
        handleThreshold("context", "stop", context_percent, execution_state)
    ELSE IF context_percent >= thresholds.alert.context:
        handleThreshold("context", "alert", context_percent, execution_state)
    ELSE IF context_percent >= thresholds.warning.context:
        handleThreshold("context", "warning", context_percent, execution_state)

    # Variance threshold
    variance = calculateVariance(execution_state.estimated, execution_state.actual)
    IF variance >= thresholds.stop.variance:
        handleThreshold("variance", "stop", variance, execution_state)
    ELSE IF variance >= thresholds.alert.variance:
        handleThreshold("variance", "alert", variance, execution_state)
    ELSE IF variance >= thresholds.warning.variance:
        handleThreshold("variance", "warning", variance, execution_state)

    # Error count threshold
    IF execution_state.error_count >= thresholds.stop.errors:
        handleThreshold("errors", "stop", execution_state.error_count, execution_state)
    ELSE IF execution_state.error_count >= thresholds.alert.errors:
        handleThreshold("errors", "alert", execution_state.error_count, execution_state)
    ELSE IF execution_state.error_count >= thresholds.warning.errors:
        handleThreshold("errors", "warning", execution_state.error_count, execution_state)

Acknowledgment Persistence

Storage Location

.autopilot/state/acknowledgments.json

Structure

{
  "acknowledgments": {
    "cost": {
      "acknowledged_at": "2026-01-29T14:30:00Z",
      "value_at_ack": 26.50,
      "session_id": "session-abc123"
    },
    "context": {
      "acknowledged_at": "2026-01-29T15:00:00Z",
      "value_at_ack": 42,
      "session_id": "session-def456"
    }
  },
  "last_reset": null
}

Persistence Protocol

FUNCTION loadAcknowledgments():
    """
    Load acknowledgments from persistent storage.
    """
    path = ".autopilot/state/acknowledgments.json"
    IF fileExists(path):
        RETURN parseJSON(readFile(path))
    ELSE:
        RETURN {acknowledgments: {}, last_reset: null}

FUNCTION saveAcknowledgment(type, value):
    """
    Persist acknowledgment for future sessions.
    """
    acks = loadAcknowledgments()
    acks.acknowledgments[type] = {
        acknowledged_at: now(),
        value_at_ack: value,
        session_id: getCurrentSessionId()
    }
    writeJSON(".autopilot/state/acknowledgments.json", acks)

FUNCTION resetAcknowledgments():
    """
    Clear all acknowledgments (--reset-alerts flag).
    """
    acks = {
        acknowledgments: {},
        last_reset: now()
    }
    writeJSON(".autopilot/state/acknowledgments.json", acks)
    LOG "✅ All alert acknowledgments cleared"

Reset Command

# Reset all acknowledgments
/autopilot:takeoff --reset-alerts

# or during execution
/autopilot:cockpit --reset-alerts

Additional Checkpoint Triggers

Trigger Configuration

checkpoint_triggers:
  # Task/Phase events
  - type: task_complete
    frequency: every
    action: update_state

  - type: phase_complete
    frequency: every
    action: checkpoint_and_verify

  # Context management
  - type: context_warning
    threshold: 30%
    action: log_warning

  - type: context_alert
    threshold: 40%
    action: prepare_checkpoint

  - type: context_stop
    threshold: 50%
    action: force_checkpoint

  # Cost management
  - type: cost_warning
    threshold: $10
    action: log_warning

  - type: cost_alert
    threshold: $25
    action: pause_for_ack

  - type: cost_stop
    threshold: $50
    action: hard_stop

  # Error handling
  - type: error_threshold
    count: 3
    action: pause_and_investigate

  # Time management
  - type: time_elapsed
    duration: 30min
    action: suggest_checkpoint

  # User interaction
  - type: user_interrupt
    signal: Ctrl+C
    action: graceful_checkpoint

Trigger Protocol

FUNCTION checkTriggers(execution_state):
    """
    Check all checkpoint triggers.
    """
    triggers = loadTriggers()

    FOR each trigger IN triggers:
        SWITCH trigger.type:
            CASE "task_complete":
                # Always triggered after task
                IF execution_state.just_completed_task:
                    updateState(execution_state)

            CASE "phase_complete":
                IF execution_state.just_completed_phase:
                    createCheckpoint("phase_complete")
                    verifyPhaseGoals(execution_state.phase)

            CASE "context_warning", "context_alert", "context_stop":
                context_pct = calculateContextUsage()
                IF context_pct >= trigger.threshold:
                    executeTriggerAction(trigger, context_pct)

            CASE "cost_warning", "cost_alert", "cost_stop":
                IF execution_state.total_cost >= trigger.threshold:
                    executeTriggerAction(trigger, execution_state.total_cost)

            CASE "error_threshold":
                IF execution_state.error_count >= trigger.count:
                    pauseAndInvestigate(execution_state.recent_errors)

            CASE "time_elapsed":
                elapsed = now() - execution_state.session_start
                IF elapsed >= trigger.duration:
                    suggestCheckpoint("time_elapsed", elapsed)

            CASE "user_interrupt":
                IF signalReceived(SIGINT):
                    gracefulCheckpoint(execution_state)

Autonomous vs Human-Verify Plans

Plan Types

# Autonomous plan (no checkpoint needed)
---
phase: 1
plan: 01
autonomous: true
checkpoint: null
---

# Tasks execute without interruption
# Summary generated at end
# Human-verify plan (requires confirmation)
---
phase: 3
plan: 06
autonomous: false
checkpoint:
  type: human-verify
  after_task: 4
  what: "Dashboard functional, data displays correctly"
---

# Pauses after task 4 for verification
# Continues after "approved" response

Execution Protocol

FUNCTION executePlan(plan):
    """
    Execute plan based on autonomous flag.
    """
    IF plan.autonomous == true:
        # Full autonomous execution
        LOG "🤖 Autonomous execution: Phase {plan.phase}, Plan {plan.plan}"

        FOR each task IN plan.tasks:
            executeTask(task)
            monitorThresholds(state)  # Still check thresholds

        generateSummary(plan)
        updateState(state)

    ELSE:
        # Execute with checkpoint
        LOG "👤 Human-verify execution: Phase {plan.phase}, Plan {plan.plan}"

        FOR index, task IN enumerate(plan.tasks):
            executeTask(task)
            monitorThresholds(state)

            # Check if checkpoint is after this task
            IF plan.checkpoint AND index + 1 == plan.checkpoint.after_task:
                presentCheckpoint(plan.checkpoint)
                response = waitForUserResponse()

                IF response == "approved":
                    LOG "✅ Checkpoint approved, continuing..."
                ELSE:
                    # User reported issues
                    handleIssues(response)

        generateSummary(plan)
        updateState(state)

Plan Type Selection

FUNCTION determinePlanType(phase, plan):
    """
    Determine if plan should be autonomous or human-verify.
    """
    # Always human-verify for these cases:
    IF plan.has_ui_changes:
        RETURN {autonomous: false, reason: "UI changes require visual verification"}

    IF plan.has_user_flows:
        RETURN {autonomous: false, reason: "User flows require functional verification"}

    IF plan.is_integration:
        RETURN {autonomous: false, reason: "Integration requires end-to-end verification"}

    IF phase.is_final:
        RETURN {autonomous: false, reason: "Final phase requires comprehensive verification"}

    # Default to autonomous for:
    IF plan.is_infrastructure:
        RETURN {autonomous: true, reason: "Infrastructure can be verified programmatically"}

    IF plan.is_backend_only:
        RETURN {autonomous: true, reason: "Backend verified by tests"}

    IF plan.is_setup:
        RETURN {autonomous: true, reason: "Setup verified by existence checks"}

    # Default: based on phase position
    IF phase.number <= 2:
        RETURN {autonomous: true, reason: "Early phases typically autonomous"}
    ELSE:
        RETURN {autonomous: false, reason: "Later phases need verification"}

Threshold Output Formats

Warning (No Interruption)

📝 Warning: Cost at $11.50 (threshold: $10)
   Continuing execution...

Alert (Requires Acknowledgment)

╔══════════════════════════════════════════════════════╗
║           🔶 ALERT: Threshold Reached                 ║
╠══════════════════════════════════════════════════════╣
║  Type:      Cost                                      ║
║  Current:   $26.50                                    ║
║  Threshold: $25.00 (alert)                            ║
║  Next:      $50.00 (stop)                             ║
╠══════════════════════════════════════════════════════╣
║  This alert requires acknowledgment to continue.      ║
║                                                       ║
║  Type 'ack' to acknowledge and continue               ║
║  Type 'stop' to halt execution                        ║
╚══════════════════════════════════════════════════════╝

Stop (Hard Stop)

╔══════════════════════════════════════════════════════╗
║           🛑 STOP: Threshold Exceeded                 ║
╠══════════════════════════════════════════════════════╣
║  Type:      Cost                                      ║
║  Current:   $52.30                                    ║
║  Threshold: $50.00 (stop)                             ║
╠══════════════════════════════════════════════════════╣
║  Execution HALTED. Checkpoint created.                ║
║                                                       ║
║  Options:                                             ║
║  1. Increase threshold in .autopilot/config.yaml      ║
║  2. Review and optimize remaining work                ║
║  3. Resume with /autopilot:cockpit --reset-alerts     ║
╚══════════════════════════════════════════════════════╝

Waypoint saved: .autopilot/waypoints/stop-20260129-143000.json