skills/mav-durability-on-gh/SKILL.md
Durability conventions for multi-instance Maverick workflows. Covers cold-start hydration from GitHub, marker-write protocols, push-per-task cadence, and recreating worktrees from remote branches. GitHub is the source of truth; local files are a cache.
npx skillsauth add thermiteau/maverick mav-durability-on-ghInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Maverick runs on many machines concurrently. Any one of them can die without notice. The only way to make the workflow crash-safe is to treat GitHub as the source of truth and treat local files as a derivable cache.
Every piece of state that another Maverick instance might need to resume your work must be on GitHub before you move to the next step. If the only copy of a piece of state is in your local filesystem, losing it loses the run.
Maverick persists workflow state to GitHub as fenced JSON code blocks inside issue comments. Each block is tagged with a kind-specific language marker so another instance can find and parse it reliably.
| Marker | Lives on | Purpose |
| --- | --- | --- |
| maverick-dag | epic issue | Machine-readable DAG of stories and their deps |
| maverick-state | epic issue | Rolling epic-state snapshot (merged / in_flight / blocked / ejected) |
| maverick-claim | each claimed issue | Atomic claim record (instance-id, host, scope) |
| maverick-lease | each claimed issue | Heartbeat lease (expiry timestamp, refreshed periodically) |
| maverick-bprop | epic issue | Block-propagation in-flight marker (resume if present) |
A marker looks like this inside a comment body:
```maverick-state
{
"epic": 123,
"stories": {"140": "merged", "142": "in_flight"},
"updated_at": "2026-04-23T10:15:00Z"
}
The canonical read/write surface is `uv run maverick gh-state …` (backed by
`src/maverick/gh_state.py`). Skills should call the CLI; they should not
re-implement marker parsing.
## Cold-start hydration
At the top of every run, assume your local filesystem is stale or empty and
rebuild context from GitHub:
```dot
digraph hydrate {
"Session starts" [shape=box];
"Identify target issue / epic" [shape=box];
"Read maverick-dag marker" [shape=box];
"Read maverick-state marker" [shape=box];
"Read claim / lease / block labels" [shape=box];
"Read open PRs and CI status" [shape=box];
"bprop marker present?" [shape=diamond];
"Resume block-propagation" [shape=box];
"Local cache hydrated" [shape=box];
"Session starts" -> "Identify target issue / epic";
"Identify target issue / epic" -> "Read maverick-dag marker";
"Read maverick-dag marker" -> "Read maverick-state marker";
"Read maverick-state marker" -> "Read claim / lease / block labels";
"Read claim / lease / block labels" -> "Read open PRs and CI status";
"Read open PRs and CI status" -> "bprop marker present?";
"bprop marker present?" -> "Resume block-propagation" [label="yes"];
"bprop marker present?" -> "Local cache hydrated" [label="no"];
"Resume block-propagation" -> "Local cache hydrated";
}
| What | Where | Why |
| --- | --- | --- |
| DAG | maverick-dag on epic | Know who depends on whom |
| Epic state | maverick-state on epic | Know merged / in-flight / blocked |
| Claims | claude-in-progress label + maverick-claim comment | Know who is working on what |
| Leases | maverick-lease comment | Know if a holder is alive or crashed |
| Blocks | blocked-by:#N label | Know downstream story is broken |
| PRs | gh pr list --json number,state,headRefName | Know merge state |
| CI | gh pr checks | Know green status |
Treat the local files below as hints — always reconcile against GitHub before acting on them:
.claude/issue-state.json — single-issue working state (WP single-issue cache).claude/epic-state.json — epic-state cache (mirror of maverick-state).maverick/worktrees/<branch>/ — worktree checkoutsIf any of these disagrees with GitHub, GitHub wins. Overwrite the local copy.
Rules for writing markers so that two instances writing at nearly the same time cannot corrupt each other:
mav-multi-instance-coordination.upsert_marker — it updates the latest
marker of the given kind in-place. Posting a new marker on every state
change floods the issue and makes parsing ambiguous.maverick-state on every transition. Every time a story moves
between merged / in-flight / blocked / ejected, update the marker. Never
batch state transitions.updated_at
ISO-8601 UTC timestamp so stale markers can be detected.Commit and push after every task, not at the end of the story. Rationale:
The cost is N CI runs instead of 1. Accept it unless the repo's CI is specifically configured to skip draft pushes. If CI cost becomes a problem, either mark the PR draft until the final task or use path-scoped triggers.
digraph push_per_task {
"Complete task N" [shape=box];
"Run local verification" [shape=box];
"Pass?" [shape=diamond];
"Diagnose and fix" [shape=box];
"Conventional commit" [shape=box];
"Push to remote" [shape=box];
"Update tasks comment on GH" [shape=box];
"Next task" [shape=box];
"Complete task N" -> "Run local verification";
"Run local verification" -> "Pass?";
"Pass?" -> "Diagnose and fix" [label="no"];
"Diagnose and fix" -> "Run local verification";
"Pass?" -> "Conventional commit" [label="yes"];
"Conventional commit" -> "Push to remote";
"Push to remote" -> "Update tasks comment on GH";
"Update tasks comment on GH" -> "Next task";
}
If you lose a local worktree (disk failure, manual cleanup, takeover from another machine) and the branch is on the remote, recreate without losing work:
git fetch origin $BRANCH
git worktree add .maverick/worktrees/$BRANCH_DIR $BRANCH
This is safe because push-per-task means origin/$BRANCH already carries
every completed task up to the crash point. Resume from the next
unchecked task in the tasks comment.
Keep these strictly local:
If a piece of state is regenerable within one task, don't mirror it to GitHub. The markers are a narrow coordination surface, not a storage layer.
<!-- maverick-plugin-version: 3.3.7 -->development
--- name: do-test description: Write or update tests for a code change. Operates in two modes: `unit` (module-scoped, fast, deterministic) and `integration` (crosses module / service / database boundaries). Intended to be invoked once per testable change from inside a do-issue-* or do-epic phase. Mode is required. argument-hint: mode: unit or integration user-invocable: true disable-model-invocation: false --- **Depends on:** mav-bp-unit-testing, mav-bp-integration-testing, mav-local-verificati
development
Implement a focused code change. Use this skill as the wrapper for any implementation work so the Maverick workflow report captures what was done and so the agent applies the project's coding standards before editing. Intended to be invoked once per task from inside a do-issue-* or do-epic phase, not standalone.
testing
How to stack a PR on top of an unmerged sibling branch, and how to retarget it to the repo's default branch once the sibling merges. Prevents orphan-merge incidents when a dependent story is ready before its parent.
development
Claim, lease, heartbeat, and release protocols for when multiple Claude Code instances may act on the same issue or epic concurrently. GitHub labels and marker comments are the coordination surface; local state is a cache.