skills/mav-github-issue-workflow/SKILL.md
Standard patterns for interacting with GitHub issues — reading, commenting, updating, state tracking, branching, and PR creation. Use as a dependency from workflow skills, not directly.
npx skillsauth add thermiteau/maverick-private mav-github-issue-workflowInstall 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-git-workflow
Reusable patterns for GitHub issue interactions. Workflow skills (e.g., do-issue-guided, do-issue-solo) reference this skill for consistent GitHub operations.
Maintain a local state file at .claude/issue-state.json to track progress across sessions and subagents. This file MUST be gitignored.
{
"issue": 42,
"repo": "owner/repo",
"branch": "feat/42-short-description",
"phase": "understand|design|plan|branch|implement|complete",
"comments": {
"design": null,
"plan": null,
"completion": null
}
}
Create the state file at the start of work. Infer the repo from the current git remote.
REPO=$(gh repo view --json nameWithOwner -q '.nameWithOwner')
mkdir -p .claude
cat > .claude/issue-state.json << EOF
{
"issue": $ISSUE_NUMBER,
"repo": "$REPO",
"branch": null,
"phase": "understand",
"comments": {
"design": null,
"plan": null,
"completion": null
}
}
EOF
cat .claude/issue-state.json
Use jq (or equivalent) to update individual fields:
# Update phase
jq '.phase = "design"' .claude/issue-state.json > .claude/issue-state.tmp && mv .claude/issue-state.tmp .claude/issue-state.json
# Update branch
jq '.branch = "feat/42-add-export"' .claude/issue-state.json > .claude/issue-state.tmp && mv .claude/issue-state.tmp .claude/issue-state.json
Before creating the state file, ensure it is gitignored:
grep -q 'issue-state.json' .gitignore 2>/dev/null || echo '.claude/issue-state.json' >> .gitignore
Always fetch structured JSON to get the full picture including comments.
gh issue view $ISSUE_NUMBER --json title,body,labels,assignees,milestone,comments,state
# Just the body
gh issue view $ISSUE_NUMBER --json body -q '.body'
# Labels as comma-separated list
gh issue view $ISSUE_NUMBER --json labels -q '[.labels[].name] | join(", ")'
# Comment count
gh issue view $ISSUE_NUMBER --json comments -q '.comments | length'
Use one comment per artifact (design, plan, completion). Capture the comment ID so it can be updated later.
COMMENT_URL=$(gh issue comment $ISSUE_NUMBER --body "$(cat <<'EOF'
## Section Title
Content here
---
*Posted by Claude Code*
EOF
)" 2>&1)
Extract the comment ID from the URL for later updates:
# gh issue comment prints the URL to stdout, extract the numeric ID
COMMENT_ID=$(echo "$COMMENT_URL" | grep -o '[0-9]*$')
Then save to state:
jq ".comments.design = $COMMENT_ID" .claude/issue-state.json > .claude/issue-state.tmp && mv .claude/issue-state.tmp .claude/issue-state.json
COMMENT_URL=$(gh issue comment $ISSUE_NUMBER --body "$(cat <<'DESIGN_EOF'
## Solution Design
### Approach
<high-level description>
### Areas Affected
- <list of packages/files>
### Key Decisions
- <architectural choices and rationale>
### Risks / Open Questions
- <anything that might complicate implementation>
---
*Posted by Claude Code*
DESIGN_EOF
)" 2>&1)
COMMENT_ID=$(echo "$COMMENT_URL" | grep -o '[0-9]*$')
jq ".comments.design = $COMMENT_ID | .phase = \"design\"" .claude/issue-state.json > .claude/issue-state.tmp && mv .claude/issue-state.tmp .claude/issue-state.json
COMMENT_URL=$(gh issue comment $ISSUE_NUMBER --body "$(cat <<'PLAN_EOF'
## Implementation Plan
1. **Step name**
- Files: `path/to/file.ts`
- Change: <what the change does>
- Verify: <test command or check>
2. **Step name**
- Files: `path/to/file.ts`
- Change: <what the change does>
- Verify: <test command or check>
---
*Posted by Claude Code*
PLAN_EOF
)" 2>&1)
COMMENT_ID=$(echo "$COMMENT_URL" | grep -o '[0-9]*$')
jq ".comments.plan = $COMMENT_ID | .phase = \"plan\"" .claude/issue-state.json > .claude/issue-state.tmp && mv .claude/issue-state.tmp .claude/issue-state.json
BRANCH=$(jq -r '.branch' .claude/issue-state.json)
COMMENT_URL=$(gh issue comment $ISSUE_NUMBER --body "$(cat <<DONE_EOF
## Implementation Complete
**Branch:** \`$BRANCH\`
### Changes Made
- <summary of changes>
### Verification
- [ ] Linting passes
- [ ] Tests pass
---
*Posted by Claude Code*
DONE_EOF
)" 2>&1)
COMMENT_ID=$(echo "$COMMENT_URL" | grep -o '[0-9]*$')
jq ".comments.completion = $COMMENT_ID | .phase = \"complete\"" .claude/issue-state.json > .claude/issue-state.tmp && mv .claude/issue-state.tmp .claude/issue-state.json
When a design or plan is revised, update the existing comment instead of posting a new one. Read the comment ID from the state file.
REPO=$(jq -r '.repo' .claude/issue-state.json)
COMMENT_ID=$(jq -r '.comments.design' .claude/issue-state.json)
gh api "repos/$REPO/issues/comments/$COMMENT_ID" \
-X PATCH \
-f body="$(cat <<'EOF'
## Solution Design (Revised)
<updated content>
---
*Posted by Claude Code*
EOF
)"
Follow the mav-git-workflow skill for branch naming conventions, base branch identification, and branch creation.
After creating the branch, save to state:
jq ".branch = \"$BRANCH_NAME\" | .phase = \"branch\"" .claude/issue-state.json > .claude/issue-state.tmp && mv .claude/issue-state.tmp .claude/issue-state.json
ISSUE_NUMBER=$(jq -r '.issue' .claude/issue-state.json)
BRANCH=$(jq -r '.branch' .claude/issue-state.json)
git push -u origin $BRANCH
gh pr create --title "<concise title>" --body "$(cat <<PR_EOF
## Summary
<1-3 bullet points>
Closes #$ISSUE_NUMBER
## Test Plan
- [ ] <verification steps>
---
*Created by Claude Code*
PR_EOF
)"
Using Closes #N in the PR body automatically closes the issue when the PR is merged.
When resuming work on an issue (new session, after crash, subagent picking up):
digraph resume {
"State file exists?" [shape=diamond];
"Read state file" [shape=box];
"Read phase" [shape=box];
"Continue from current phase" [shape=box];
"Ask user for issue number" [shape=box];
"Initialise state" [shape=box];
"State file exists?" -> "Read state file" [label="yes"];
"State file exists?" -> "Ask user for issue number" [label="no"];
"Read state file" -> "Read phase";
"Read phase" -> "Continue from current phase";
"Ask user for issue number" -> "Initialise state";
"Initialise state" -> "Continue from current phase";
}
.claude/issue-state.json existsAfter the PR is created and the workflow is complete:
rm .claude/issue-state.json
Do not delete the state file until the PR is successfully created, as it is needed for crash recovery.
development
Use when a best-practice skill needs project-specific implementation details and no project skill exists at docs/maverick/skills/<topic>/SKILL.md. Scans the codebase and generates a project-specific skill file.
testing
Create or update technical documentation for a project. Covers architecture, service interactions, data flows, and design decisions. Produces professional markdown with Mermaid diagrams.
development
How to process code review feedback — verify before implementing, push back when wrong, clarify before acting on partial understanding. Applied when receiving review from the code-reviewer agent or human reviewers.
development
Analyze a project's codebase against Maverick standard practices and write a findings report. Checks linting, unit tests, integration tests, documentation, and CI/CD. Run when onboarding an existing project or on demand.