Skip to content

Checkpoint Enforcement Hook

The checkpoint-enforcement hook runs when a Claude Code session ends, providing a summary of pending checkpoints, in-progress work, and artifacts that need attention.

Overview

Attribute Value
Hook Name checkpoint-enforcement
Script hooks/scripts/checkpoint-enforcement.py
Event Stop
Matcher None (all session stops)
Blocking No (warning only)
Timeout 5000ms

Purpose

The checkpoint enforcement hook ensures:

  1. Pending Review Awareness: Users know which checkpoints await approval
  2. Work Continuity: In-progress phase is clearly identified for resumption
  3. Artifact Tracking: Reminder about files in artifacts directory
  4. Session Timestamps: Updates last activity for session tracking

Configuration

In hooks/hooks.json:

{
  "Stop": [
    {
      "hooks": [
        {
          "type": "command",
          "command": "python ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/checkpoint-enforcement.py",
          "timeout": 5000
        }
      ]
    }
  ]
}

Behavior

Active Session with Pending Work

When session has pending checkpoints or in-progress work:

═══════════════════════════════════════════
Mistaber Session Summary
═══════════════════════════════════════════

Pending Checkpoints: hll-encode, validate
   These require human review before proceeding.

In-Progress Work: YD:87:3 (hll-encode)
   Session state saved - resume with 'Resume encoding YD:87:3'

Artifacts: 5 files in .mistaber-artifacts/
   Review these before next session.

═══════════════════════════════════════════

No Active Session

When no session file exists:

{
  "continue": true,
  "message": ""
}

The hook returns silently when there's nothing to report.

Session Complete

When all checkpoints are approved and no pending work:

{
  "continue": true,
  "message": ""
}

Session Summary Components

Pending Checkpoints Section

Identifies checkpoints with status: pending_review:

def get_pending_checkpoints(session: dict) -> list[str]:
    """Get list of checkpoints pending review."""
    pending = []
    checkpoints = session.get("checkpoints", {})

    for name, data in checkpoints.items():
        status = data.get("status", "not_started")
        if status == "pending_review":
            pending.append(name)

    return pending

Output Format:

Pending Checkpoints: corpus-prep, hll-encode
   These require human review before proceeding.

In-Progress Work Section

Reports the current phase and target:

def get_in_progress_phase(session: dict) -> str | None:
    """Get current in-progress phase."""
    return session.get("current_phase")

Output Format:

In-Progress Work: YD:87:3 (hll-encode)
   Session state saved - resume with 'Resume encoding YD:87:3'

Excluded Phases: - complete - Session finished - not_started - Session not yet begun

Artifacts Section

Counts files in .mistaber-artifacts/:

artifacts_dir = Path(".mistaber-artifacts")
if artifacts_dir.exists():
    artifact_count = len(list(artifacts_dir.glob("*")))
    if artifact_count > 0:
        messages.append(
            f"Artifacts: {artifact_count} files in .mistaber-artifacts/\n"
            "   Review these before next session."
        )

Output Format:

Artifacts: 5 files in .mistaber-artifacts/
   Review these before next session.

Session State Updates

The hook updates the session's last activity timestamp:

def save_session_state(session: dict) -> None:
    """Save session state with last activity timestamp."""
    session["last_activity"] = datetime.now().isoformat()

    session_path = Path(".mistaber-session.yaml")
    with open(session_path, "w") as f:
        yaml.dump(session, f, default_flow_style=False, allow_unicode=True)

Updated Session:

current_phase: hll-encode
target_seif: "YD:87:3"
started: "2026-01-25T10:00:00Z"
last_activity: "2026-01-25T14:30:00.123456"  # Updated on stop
checkpoints:
  corpus-prep:
    status: approved
  hll-encode:
    status: pending_review

Implementation Flow

graph TD
    A[Session Stop Event] --> B{Session File Exists?}
    B -->|No| C[Return Silently]
    B -->|Yes| D[Load Session State]
    D --> E{Pending Checkpoints?}
    E -->|Yes| F[Add Pending Message]
    E -->|No| G{In-Progress Phase?}
    F --> G
    G -->|Yes| H[Add In-Progress Message]
    G -->|No| I{Artifacts Exist?}
    H --> I
    I -->|Yes| J[Add Artifacts Message]
    I -->|No| K{Any Messages?}
    J --> K
    K -->|Yes| L[Format Summary]
    K -->|No| C
    L --> M[Update Last Activity]
    M --> N[Return Summary]

Message Structure

Full Summary Format

═══════════════════════════════════════════
Mistaber Session Summary
═══════════════════════════════════════════

[Pending Checkpoints Section - if any]

[In-Progress Work Section - if any]

[Artifacts Section - if any]

═══════════════════════════════════════════

Section Components

Section Condition Content
Pending Checkpoints Any checkpoint with pending_review List of checkpoint names
In-Progress Work current_phase not complete/not_started Phase name and target seif
Artifacts Files in .mistaber-artifacts/ File count

Example Sessions

Session with Pending Approval

Session State:

current_phase: hll-encode
target_seif: "YD:87:3"
checkpoints:
  corpus-prep:
    status: approved
  hll-encode:
    status: pending_review
  validate:
    status: not_started
  review:
    status: not_started

Artifacts Directory:

.mistaber-artifacts/
├── corpus-sources-YD-87-3.yaml
├── encoding-notes.md
└── source-chain-log.yaml

Hook Output:

═══════════════════════════════════════════
Mistaber Session Summary
═══════════════════════════════════════════

Pending Checkpoints: hll-encode
   These require human review before proceeding.

In-Progress Work: YD:87:3 (hll-encode)
   Session state saved - resume with 'Resume encoding YD:87:3'

Artifacts: 3 files in .mistaber-artifacts/
   Review these before next session.

═══════════════════════════════════════════

Session Nearing Completion

Session State:

current_phase: review
target_seif: "YD:87:3"
checkpoints:
  corpus-prep:
    status: approved
  hll-encode:
    status: approved
  validate:
    status: approved
  review:
    status: pending_review

Hook Output:

═══════════════════════════════════════════
Mistaber Session Summary
═══════════════════════════════════════════

Pending Checkpoints: review
   These require human review before proceeding.

In-Progress Work: YD:87:3 (review)
   Session state saved - resume with 'Resume encoding YD:87:3'

═══════════════════════════════════════════

Clean Session End

Session State:

current_phase: complete
target_seif: "YD:87:3"
checkpoints:
  corpus-prep:
    status: approved
  hll-encode:
    status: approved
  validate:
    status: approved
  review:
    status: approved

Hook Output: (empty - no message displayed)

Checkpoint Status Values

Status Pending? Description
not_started No Phase not yet begun
in_progress No Phase currently executing
pending_review Yes Awaiting human approval
approved No Checkpoint passed
tests_passed No Validation tests successful
tests_failed No Validation tests failed
compile_failed No Compilation failed

Debugging

Manual Testing

# Test with no session
rm -f .mistaber-session.yaml
python mistaber-skills/hooks/scripts/checkpoint-enforcement.py | jq .

# Test with pending session
cat > .mistaber-session.yaml << 'EOF'
current_phase: hll-encode
target_seif: "YD:87:3"
checkpoints:
  corpus-prep:
    status: approved
  hll-encode:
    status: pending_review
EOF
python mistaber-skills/hooks/scripts/checkpoint-enforcement.py | jq .

Check Session State

# View current session
cat .mistaber-session.yaml

# Check pending checkpoints
cat .mistaber-session.yaml | grep -A1 "status:" | grep "pending_review"

Verify Artifacts

# Count artifacts
ls .mistaber-artifacts/ | wc -l

# List artifact files
ls -la .mistaber-artifacts/

Common Issues

Summary Not Displayed

Symptom: Session ends without summary.

Causes: - No session file exists - All checkpoints approved - No in-progress phase - No artifacts

Solutions:

# Check session exists
ls -la .mistaber-session.yaml

# Check for pending checkpoints
grep "pending_review" .mistaber-session.yaml

Incomplete Summary

Symptom: Some sections missing from summary.

Causes: - Section condition not met - Session state missing expected fields

Solutions:

# Verify session structure
cat .mistaber-session.yaml

# Check required fields
python -c "
import yaml
with open('.mistaber-session.yaml') as f:
    s = yaml.safe_load(f)
print('current_phase:', s.get('current_phase'))
print('target_seif:', s.get('target_seif'))
print('checkpoints:', list(s.get('checkpoints', {}).keys()))
"

Last Activity Not Updated

Symptom: last_activity timestamp not changed.

Causes: - PyYAML not available - File write permissions - No messages generated (hook returns early)

Solutions:

# Check PyYAML
python -c "import yaml; print('OK')"

# Check permissions
touch .mistaber-session.yaml

Integration with Workflow

Resuming Work

The summary tells users how to resume:

In-Progress Work: YD:87:3 (hll-encode)
   Session state saved - resume with 'Resume encoding YD:87:3'

In next session, user can say:

"Resume encoding YD:87:3"

The session-init hook will load the saved state and continue.

Addressing Pending Checkpoints

The summary identifies what needs approval:

Pending Checkpoints: hll-encode
   These require human review before proceeding.

User should review the HLL encoding before the next phase.

Managing Artifacts

The summary reminds about artifacts:

Artifacts: 3 files in .mistaber-artifacts/
   Review these before next session.

User should review: - Corpus sources - Source chain logs - Encoding notes