skills/mav-multi-instance-coordination/SKILL.md
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.
npx skillsauth add thermiteau/maverick mav-multi-instance-coordinationInstall 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.
Depends on: mav-durability-on-gh, mav-block-propagation
Several Claude Code instances, on different machines, may be asked to act on the same issue or epic at the same time. This skill defines how they coordinate so that:
All coordination state is on GitHub. The local filesystem is a cache.
Every workflow entry point must run the entry check before touching an
issue. The CLI helper uv run maverick coord read <repo> <issue> returns
a JSON snapshot; parse it and decide:
digraph entry {
"Read claim state" [shape=box];
"blocked-by:#N label?" [shape=diamond];
"Abort — report block to user" [shape=box];
"claude-in-progress label?" [shape=diamond];
"lease live?" [shape=diamond];
"Abort — report holder + expiry" [shape=box];
"Stale lease — takeover or defer" [shape=diamond];
"Claim scope" [shape=box];
"Claim" [shape=box];
"Read claim state" -> "blocked-by:#N label?";
"blocked-by:#N label?" -> "Abort — report block to user" [label="yes"];
"blocked-by:#N label?" -> "claude-in-progress label?" [label="no"];
"claude-in-progress label?" -> "lease live?" [label="yes"];
"claude-in-progress label?" -> "Claim scope" [label="no"];
"lease live?" -> "Abort — report holder + expiry" [label="yes"];
"lease live?" -> "Stale lease — takeover or defer" [label="no"];
"Stale lease — takeover or defer" -> "Claim" [label="take over"];
"Claim scope" -> "Claim";
}
| Exit | When | Action |
| --- | --- | --- |
| Blocked | blocked-by:#N label present | Report to user; do not claim, do not modify issue |
| Claimed with live lease | Another instance is active | Report holder id and expiry; do not modify issue |
| Claimed with stale lease | Holder likely crashed | Decide: take over now, or defer |
| Free | No claim or stale/absent lease | Claim and proceed |
Decide the breadth of the claim before calling coord claim:
do-epic end-to-end.do-issue-solo for ad-hoc
single-issue work.The chosen scope is recorded in the maverick-claim payload so other
instances reading the marker can see exactly what you own.
The claim primitive does four things, in order:
claude-in-progress label (idempotent — repeating is safe).maverick-claim marker with this instance's id, host, scope,
and claimed_at timestamp.maverick-lease marker with expires_at set to
10 minutes from now.GitHub's API is not strongly ordered, so step 1 alone is insufficient —
two instances can both see "no label" and then both write the label. Step
4 is the race-detection check: if the re-read shows more than one
maverick-claim marker with an active instance, the instance with the
lower id (lexicographic) wins, and every other instance runs
release and aborts.
Once claimed, refresh the lease every ~2 minutes:
uv run maverick coord heartbeat <repo> <issue>
The refresh pushes expires_at forward by 10 minutes. If two consecutive
heartbeats fail (network flake, transient GitHub error), do not keep
working on the assumption you still own the claim — abort and release.
Heartbeat may also raise ClaimLost if:
claude-in-progress label has been removed (another instance took
over, or a human resolved the claim manually).maverick-claim marker now names a different instance.On ClaimLost: stop work immediately, do not push, do not comment
further. Clean up local worktree state and report to the user.
On completion, eject, or any clean exit:
uv run maverick coord release <repo> <issue> --reason merged
uv run maverick coord release <repo> <issue> --reason ejected
uv run maverick coord release <repo> <issue> --reason abort
This removes the label, writes a lease-released marker, and unassigns the GitHub App. Always release on every exit path. If an instance dies before release, the lease expires in ~10 minutes and another instance can take over.
If you find a claim with a stale lease (holder's last heartbeat > TTL ago), decide before acting:
To take over:
uv run maverick coord takeover <repo> <issue>
This posts a takeover comment naming the prior instance and then runs
claim with takeover permission. The prior instance's heartbeat will fail
on its next attempt with ClaimLost.
Every entry-point skill (do-issue-solo, do-issue-guided, do-epic) must
register a release handler that fires on every exit path — success,
eject, abort, crash-caught, user-interrupt. The easiest pattern is a
trap-on-exit wrapper that calls coord release for every claim this
instance still holds.
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.
documentation
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.