Skip to content
Back to skills

Mav Claude Code Recovery

ASecurity

Patterns for Claude Code workflow resilience — state persistence, crash recovery, command failure handling, subagent failure handling, and artefact durability. Not about application-level error handling.

  • 11 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added June 1, 2026
ai-agentsrustgobashdebugginggitapi

Works with

  • claude code
  • api

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned June 1, 2026

npx -y skills add thermiteau/maverick --skill mav-claude-code-recovery --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Mav Claude Code Recovery?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Mav Claude Code Recovery
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/thermiteau-mav-claude-code-recovery/badge)](https://www.skillsdirectory.com/skills/thermiteau-mav-claude-code-recovery)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: mav-claude-code-recovery
description: Patterns for Claude Code workflow resilience — state persistence, crash recovery, command failure handling, subagent failure handling, and artefact durability. Not about application-level error handling.
---

# Claude Code Error Handling and Recovery

Patterns for making Claude Code workflows resilient to failures. This covers Claude Code's own recovery mechanisms, not error handling in generated application code.

## Principles

1. **Persist state early and often** — write progress to a state file after each phase so work can be resumed
2. **Post artefacts immediately** — designs, plans, and status updates go to GitHub as soon as they are ready, not at the end
3. **Diagnose before retrying** — when something fails, understand why before trying again
4. **Verify before continuing** — on resume, confirm recorded state matches reality
5. **Isolate failures** — subagent failures stay in the subagent; fix via a new subagent, not by polluting the main session

## State Persistence

Maintain a state file to track workflow progress. The mav-github-issue-workflow skill defines the canonical state file format for issue-driven work (`.claude/issue-state.json`). This section covers the general principles.

### What to Persist

| Field | Why |
|---|---|
| Current phase | Resume from the right point |
| Branch name | Avoid re-deriving or creating duplicates |
| GitHub comment IDs | Update existing comments instead of posting new ones |
| Issue/task reference | Know what we're working on |

### When to Write State

Write to the state file **after** each significant milestone, not before:

```dot
digraph state_writes {
    "Complete a phase" [shape=box];
    "Write state" [shape=box];
    "Start next phase" [shape=box];
    "Failure mid-phase?" [shape=diamond];
    "State reflects last completed phase" [shape=box];
    "Resume from last completed phase" [shape=box];

    "Complete a phase" -> "Write state";
    "Write state" -> "Start next phase";
    "Start next phase" -> "Failure mid-phase?";
    "Failure mid-phase?" -> "State reflects last completed phase" [label="yes"];
    "State reflects last completed phase" -> "Resume from last completed phase";
    "Failure mid-phase?" -> "Complete a phase" [label="no — phase completes"];
}
```

Writing **after** completion means the state file always reflects a consistent, completed milestone. If a failure occurs mid-phase, the state file points to the last successfully completed phase, and the incomplete phase can be re-executed from scratch.

### State File Hygiene

- **Gitignore** — state files are session artefacts, not project code. Always gitignore them.
- **One file per workflow** — if working on multiple issues concurrently (e.g., in worktrees), use separate state files.
- **Clean up on completion** — delete the state file after the workflow completes successfully (PR created, issue updated).
- **Atomic writes** — write to a temp file then rename, to avoid corruption from partial writes:
  ```bash
  jq '.phase = "design"' .claude/issue-state.json > .claude/issue-state.tmp && mv .claude/issue-state.tmp .claude/issue-state.json
  ```

## Artefact Durability

Post artefacts (designs, plans, status updates) to GitHub immediately after they are produced. This ensures they survive Claude Code session failures.

### What Counts as an Artefact

| Artefact | Where to post | When |
|---|---|---|
| Solution design | Issue comment | Immediately after design is approved/produced |
| Implementation plan | Issue comment | Immediately after plan is approved/produced |
| Completion summary | Issue comment | After all steps pass verification |
| Blocking questions | Issue comment | When blocked and unable to resolve |

### Why Not Wait

If you batch artefacts and post them at the end:
- A crash loses all intermediate work
- The human has no visibility into progress
- Recovery requires re-doing the design/planning work

Post each artefact as soon as it is ready. Use the mav-github-issue-workflow comment patterns to capture comment IDs for later updates.

## Crash Recovery (Session Resume)

When starting a session that may be resuming previous work:

```dot
digraph resume {
    "Session starts" [shape=box];
    "State file exists?" [shape=diamond];
    "Read state file" [shape=box];
    "Validate state against reality" [shape=box];
    "State valid?" [shape=diamond];
    "Resume from recorded phase" [shape=box];
    "Reconcile state" [shape=box];
    "Fresh start" [shape=box];

    "Session starts" -> "State file exists?";
    "State file exists?" -> "Read state file" [label="yes"];
    "State file exists?" -> "Fresh start" [label="no"];
    "Read state file" -> "Validate state against reality";
    "Validate state against reality" -> "State valid?";
    "State valid?" -> "Resume from recorded phase" [label="yes"];
    "State valid?" -> "Reconcile state" [label="no — mismatch"];
    "Reconcile state" -> "Resume from recorded phase";
}
```

### Validating State Against Reality

Before resuming, verify that the recorded state matches what actually exists:

| State field | Validation check |
|---|---|
| Branch | Does the branch exist locally? `git branch --list $BRANCH` |
| Branch | Does it exist on remote? `git ls-remote --heads origin $BRANCH` |
| Phase | Are the expected commits present? `git log --oneline -5` |
| Comment IDs | Do the comments exist on the issue? `gh api repos/$REPO/issues/comments/$ID --jq '.id'` |
| Issue | Is the issue still open? `gh issue view $ISSUE --json state -q '.state'` |

### Reconciling Mismatched State

If validation finds discrepancies:

| Mismatch | Action |
|---|---|
| Branch exists locally but not on remote | Branch was never pushed — continue from implementation phase |
| Branch exists on remote but not locally | `git fetch origin && git checkout $BRANCH` |
| Branch does not exist anywhere | State is stale — start fresh, but check if a PR was already created |
| Comment ID does not exist | Comment was deleted — post a new one and update state |
| Issue is closed | Check if a PR was merged — work may already be complete |
| Phase says `implement` but no commits on branch | Implementation was interrupted — restart implementation phase |

### Reporting Recovery

When resuming, briefly report to the user what was recovered:

```
Resuming work on issue #42 (feat/42-add-export).
- Phase: implementation (3 of 5 steps completed)
- Branch: feat/42-add-export (exists locally and on remote)
- Design and plan already posted to issue
- Continuing from step 4.
```

## Command Failure Handling

When a tool or command fails during execution:

```dot
digraph cmd_failure {
    "Command fails" [shape=box];
    "Read error output" [shape=box];
    "Known failure pattern?" [shape=diamond];
    "Apply known fix" [shape=box];
    "Diagnose root cause" [shape=box];
    "Can fix autonomously?" [shape=diamond];
    "Fix and retry" [shape=box];
    "Report to user with diagnosis" [shape=box];

    "Command fails" -> "Read error output";
    "Read error output" -> "Known failure pattern?";
    "Known failure pattern?" -> "Apply known fix" [label="yes"];
    "Known failure pattern?" -> "Diagnose root cause" [label="no"];
    "Apply known fix" -> "Fix and retry";
    "Diagnose root cause" -> "Can fix autonomously?";
    "Can fix autonomously?" -> "Fix and retry" [label="yes"];
    "Can fix autonomously?" -> "Report to user with diagnosis" [label="no"];
}
```

### Known Failure Patterns

| Error pattern | Likely cause | Fix |
|---|---|---|
| `ENOENT` / file not found | Wrong path or file not yet created | Verify path, check if a prerequisite step was skipped |
| `EACCES` / permission denied | File permissions or sandbox restriction | Check permissions, do not bypass sandbox |
| `npm ERR!` / dependency resolution | Lock file out of sync or missing dependency | Run `pnpm install` / `npm install` |
| `tsc` type errors after code change | Introduced type mismatch | Read the error, fix the type issue |
| Test timeout | Test is hanging or async issue | Check for missing `await`, unclosed handles |
| `gh: Not Found` | Wrong repo, issue number, or permissions | Verify repo and issue exist, check auth |
| Git conflict markers in file | Unresolved merge conflict | Follow mav-git-workflow merge conflict procedure |

### Rules

- **Never retry blindly** — if a command fails, understand why before running it again. The same command will produce the same failure.
- **Never brute-force past failures** — do not add `--force`, `--no-verify`, or `|| true` to make a failing command succeed. Fix the root cause.
- **Limit retry attempts** — if a fix-and-retry cycle fails 3 times, stop and report to the user with full context.
- **Preserve error output** — include the actual error message when reporting to the user, not just "it failed".

## Epic Recovery

Multi-story (`do-epic`) workflows have additional state on GitHub that
single-issue recovery does not. On entry, always re-hydrate from GitHub
per `mav-durability-on-gh` before touching anything local.

### The five things to check on re-entry

| Signal | Location | What it means |
| --- | --- | --- |
| `maverick-dag` marker | Epic issue | DAG exists — do not rebuild, read it |
| `maverick-state` marker | Epic issue | Current story statuses — trust over local cache |
| `maverick-claim` + `maverick-lease` | Each claimed issue | Who holds what, and whether they are alive |
| `maverick-bprop` marker | Epic issue | **A block walk was in progress** — must resume it first |
| `blocked-by:#N` labels | Each story | Which stories are currently blocked |

If a local `.claude/epic-state.json` exists but the GitHub markers
disagree, **GitHub wins** — overwrite the local cache.

### Resume order

```dot
digraph epic_resume {
    "Session starts" [shape=box];
    "maverick-bprop present?" [shape=diamond];
    "Resume block propagation — idempotent walk from the ejected story" [shape=box];
    "Claim still live on any issue?" [shape=diamond];
    "Re-verify heartbeat — extend or release" [shape=box];
    "Stale claims present?" [shape=diamond];
    "Decide takeover vs defer" [shape=box];
    "Proceed with next wave" [shape=box];

    "Session starts" -> "maverick-bprop present?";
    "maverick-bprop present?" -> "Resume block propagation — idempotent walk from the ejected story" [label="yes"];
    "maverick-bprop present?" -> "Claim still live on any issue?" [label="no"];
    "Resume block propagation — idempotent walk from the ejected story" -> "Claim still live on any issue?";
    "Claim still live on any issue?" -> "Re-verify heartbeat — extend or release" [label="yes"];
    "Claim still live on any issue?" -> "Stale claims present?" [label="no"];
    "Stale claims present?" -> "Decide takeover vs defer" [label="yes"];
    "Stale claims present?" -> "Proceed with next wave" [label="no"];
    "Re-verify heartbeat — extend or release" -> "Proceed with next wave";
    "Decide takeover vs defer" -> "Proceed with next wave";
}
```

### Block-propagation resume — critical path

If a `maverick-bprop` marker exists on the epic when you enter, the prior
instance was mid-block-walk when it died. The marker payload names the
ejected story, the full descendant set, and which descendants are already
labelled. Per `mav-block-propagation`:

1. Read the marker payload.
2. For each descendant not already in `labelled`:
   - Apply `blocked-by:#<ejected>` if not present (idempotent).
   - Post the block comment if not present.
   - Update `maverick-state` for that story.
   - Append to `labelled` in the marker.
3. When every descendant is in `labelled`, **delete** the marker.

Only after `maverick-bprop` is cleared should you proceed with other
epic work. Leaving a partially-applied block set running invites
downstream PRs to merge against a broken base.

### Worktree reconciliation

Local worktrees under `.maverick/worktrees/` are a cache. After
re-hydration, walk them and reconcile:

| Worktree state | GitHub state | Action |
| --- | --- | --- |
| Exists | Story `merged` on GH | Destroy the worktree — work is done |
| Exists | Story `ejected` on GH | Keep — note the path for the human |
| Exists | Story `blocked` on GH | Destroy — abandon the work |
| Exists | Story `in_flight` by us (live lease) | Resume where you left off |
| Exists | Story `in_flight` by another instance | Destroy — they own it now |
| Missing | Story `in_flight` by us | Recreate from `origin/<branch>` |

See `mav-durability-on-gh` for the worktree-recreate command.

## Subagent Failure Handling

When a subagent fails or returns incomplete results:

```dot
digraph subagent_failure {
    "Subagent returns" [shape=box];
    "Result complete and correct?" [shape=diamond];
    "Accept result" [shape=box];
    "Partial result?" [shape=diamond];
    "Dispatch new subagent with corrective context" [shape=box];
    "Total failure?" [shape=diamond];
    "Dispatch new subagent with simplified scope" [shape=box];
    "Report to user" [shape=box];

    "Subagent returns" -> "Result complete and correct?";
    "Result complete and correct?" -> "Accept result" [label="yes"];
    "Result complete and correct?" -> "Partial result?" [label="no"];
    "Partial result?" -> "Dispatch new subagent with corrective context" [label="yes — some work done"];
    "Partial result?" -> "Total failure?" [label="no work done"];
    "Total failure?" -> "Dispatch new subagent with simplified scope" [label="scope too large"];
    "Total failure?" -> "Report to user" [label="unclear cause"];
}
```

### Rules

- **Do not fix subagent failures in the main session** — this pollutes the main context with debugging detail. Dispatch a new subagent.
- **Provide corrective context** — when dispatching a fix subagent, include what the previous subagent did, what it got wrong, and what specifically needs to be fixed.
- **Reduce scope on repeated failure** — if a subagent fails twice on the same task, split the task into smaller pieces and dispatch subagents for each piece.
- **Never silently swallow failures** — if a subagent fails and you cannot recover, report the failure clearly to the user.

<!-- maverick-plugin-version: 3.3.5 -->

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.