global/skills/issue-work/SKILL.md
Automate GitHub issue workflow - select issue, create branch, implement, build, test, and create PR.
npx skillsauth add kcenon/claude-config issue-workInstall 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.
Automate GitHub issue workflow with project name as argument.
/issue-work # Batch: all repos, all open issues
/issue-work vi_slam # Batch: all open issues in vi_slam
/issue-work vi_slam 21 # Single: work on issue #21
/issue-work vi_slam 21 --org mycompany # Explicit organization
/issue-work mycompany/vi_slam 21 # Full repo path format
/issue-work vi_slam 21 --solo # Force solo mode (sequential)
/issue-work vi_slam 21 --team # Force team mode (implementer + tester)
/issue-work --org mycompany # Batch: all repos in org
/issue-work vi_slam --limit 5 # Batch: top 5 priority issues
/issue-work vi_slam --dry-run # Preview batch plan only
/issue-work vi_slam --inline # Batch: process items in the parent context (legacy)
[project-name]: Project name or full repository path (optional)
<project-name> - auto-detect organization from git remote<project-name> --org <organization> - explicit organization<organization>/<project-name> - full repository path[issue-number]: GitHub issue number (optional)
[--solo|--team]: Execution mode override (optional)
--solo — Force solo mode for all items (single agent, sequential workflow)--team — Force team mode for all items (implementer + tester agents in parallel)[--limit N]: Maximum number of items to process in batch mode (default: 5, max: 10)
--force-large to acknowledge rule drift risk. Empirically, drift becomes visible around items 15-25 in long batches; the conservative default keeps batches inside the safe zone.[--force-large]: Allow --limit > 10. Required to bypass the safe-batch cap.
[--no-confirm]: Skip the chunked confirmation gate fired every 5 items in batch mode. Intended for CI-driven or fully unattended batches; interactive sessions should leave it off so the gate can serve as both a user-control checkpoint and an attention refresh for accumulated context.
[--auto-restart]: Force a session restart every CONFIRM_INTERVAL items instead of showing the interactive chunked gate. The batch writes .claude/resume.md using the Batch Workflow Resume Format and exits cleanly; a fresh claude session picks up the next item from the resume file. Use for long unattended batches where a full process-level attention reset per chunk matters more than human confirmation. Ignored in single-item mode.
[--no-restart]: Suppress the forced restart. When combined with --auto-restart, the batch falls back to the interactive chunked gate. Meaningful primarily as a defensive flag in scripts that want to guarantee no session exit even if --auto-restart is set elsewhere (aliases, wrappers, or a future default change).
[--dry-run]: Show batch plan only, do not execute
[--inline]: Process each batch item in the parent conversation context instead of delegating to a fresh subagent.
general-purpose Agent. The parent keeps only the queue state and a short per-item summary; gh outputs, build logs, and file reads live inside the subagent and are discarded on completion. This is the preferred mode for batches >3 items because rule compliance at item 30 looks like item 1.--inline: The parent executes Solo/Team workflow directly for every item. Lower token overhead (~10-15% savings) but accumulated tool results cause rule drift around items 15-25. Use for tiny batches (≤3 items) or when inter-item context is actually useful (e.g., fixing related regressions).[--priority <level>]: Filter batch to this priority level and above
critical, high, medium, low, all (default: all)Parse $ARGUMENTS and extract project, organization, issue number, and batch flags:
ARGS="$ARGUMENTS"
ISSUE_NUMBER="" PROJECT="" ORG="" EXEC_MODE=""
BATCH_MODE="single" BATCH_LIMIT=5 DRY_RUN=false PRIORITY_FILTER="all" FORCE_LARGE=false NO_CONFIRM=false INLINE_MODE=false AUTO_RESTART=false NO_RESTART=false
MAX_LIMIT=10
CONFIRM_INTERVAL=5
# Extract flags
if [[ "$ARGS" == *"--solo"* ]]; then EXEC_MODE="solo"; ARGS=$(echo "$ARGS" | sed 's/--solo//g'); fi
if [[ "$ARGS" == *"--team"* ]]; then EXEC_MODE="team"; ARGS=$(echo "$ARGS" | sed 's/--team//g'); fi
if [[ "$ARGS" == *"--dry-run"* ]]; then DRY_RUN=true; ARGS=$(echo "$ARGS" | sed 's/--dry-run//g'); fi
if [[ "$ARGS" == *"--force-large"* ]]; then FORCE_LARGE=true; ARGS=$(echo "$ARGS" | sed 's/--force-large//g'); fi
if [[ "$ARGS" == *"--no-confirm"* ]]; then NO_CONFIRM=true; ARGS=$(echo "$ARGS" | sed 's/--no-confirm//g'); fi
if [[ "$ARGS" == *"--no-restart"* ]]; then NO_RESTART=true; ARGS=$(echo "$ARGS" | sed 's/--no-restart//g'); fi
if [[ "$ARGS" == *"--auto-restart"* ]]; then AUTO_RESTART=true; ARGS=$(echo "$ARGS" | sed 's/--auto-restart//g'); fi
if [[ "$ARGS" == *"--inline"* ]]; then INLINE_MODE=true; ARGS=$(echo "$ARGS" | sed 's/--inline//g'); fi
if [[ "$ARGS" =~ --limit[[:space:]]+([0-9]+) ]]; then BATCH_LIMIT="${BASH_REMATCH[1]}"; ARGS=$(echo "$ARGS" | sed -E 's/--limit[[:space:]]+[0-9]+//g'); fi
if [[ "$ARGS" =~ --priority[[:space:]]+(critical|high|medium|low|all) ]]; then PRIORITY_FILTER="${BASH_REMATCH[1]}"; ARGS=$(echo "$ARGS" | sed -E 's/--priority[[:space:]]+\w+//g'); fi
# Hard cap on batch size to mitigate rule drift in long batches.
# Drift becomes empirically visible around items 15-25; default 5 keeps the
# operator inside the safe zone, and bypassing requires explicit acknowledgment.
if (( BATCH_LIMIT > MAX_LIMIT )) && [[ "$FORCE_LARGE" != "true" ]]; then
echo "Error: --limit ${BATCH_LIMIT} exceeds safe cap of ${MAX_LIMIT}." >&2
echo "Long batches risk rule drift around items 15-25." >&2
echo "Either split the batch into smaller runs or pass --force-large to override." >&2
exit 1
fi
# Extract issue number if present (numeric argument)
if [[ "$ARGS" =~ [[:space:]]([0-9]+)([[:space:]]|$) ]]; then
ISSUE_NUMBER="${BASH_REMATCH[1]}"
ARGS=$(echo "$ARGS" | sed -E "s/[[:space:]]+${ISSUE_NUMBER}([[:space:]]|$)/ /g")
fi
ARGS=$(echo "$ARGS" | xargs)
# Helper: resolve ORG/PROJECT from remaining ARGS
resolve_org_project() {
if [[ "$ARGS" == *"--org"* ]]; then
PROJECT=$(echo "$ARGS" | awk '{print $1}')
ORG=$(echo "$ARGS" | sed -n 's/.*--org[[:space:]]*\([^[:space:]]*\).*/\1/p')
elif [[ "$ARGS" == *"/"* ]]; then
ORG=$(echo "$ARGS" | cut -d'/' -f1 | xargs)
PROJECT=$(echo "$ARGS" | cut -d'/' -f2 | xargs)
else
PROJECT="$ARGS"
cd "$PROJECT" 2>/dev/null || { echo "Error: Project directory not found: $PROJECT"; exit 1; }
ORG=$(git remote get-url origin 2>/dev/null | sed -E 's|.*[:/]([^/]+)/[^/]+\.git$|\1|' | sed -E 's|.*[:/]([^/]+)/[^/]+$|\1|')
fi
}
# Determine batch mode and resolve org/project
if [[ -z "$ARGS" && -z "$ISSUE_NUMBER" ]]; then
BATCH_MODE="cross-repo"
if [[ "$ARGS" == *"--org"* ]]; then
ORG=$(echo "$ARGS" | sed -n 's/.*--org[[:space:]]*\([^[:space:]]*\).*/\1/p')
fi
elif [[ -n "$ARGS" && -z "$ISSUE_NUMBER" ]]; then
BATCH_MODE="single-repo"
resolve_org_project
else
BATCH_MODE="single"
resolve_org_project
fi
https://github.com/$ORG/$PROJECT (single/single-repo modes)./$PROJECT$ISSUE_NUMBER (empty for batch modes)$BATCH_MODE (single, single-repo, or cross-repo)$BATCH_MODE == "single-repo" or $BATCH_MODE == "cross-repo" → Execute Batch Mode Instructions below$BATCH_MODE == "single" → Execute Phase 0: Execution Mode Selection (skip Batch Mode)See reference/batch-mode.md for the complete batch mode workflow including discovery, priority sorting, plan approval, and sequential execution.
Batch-only behaviors (do not apply in single-item mode):
general-purpose Agent so it starts with an unpolluted attention pool. The parent retains only {item_id, status, pr_url, ci_conclusion} per item. Pass --inline to fall back to the legacy single-context loop.--inline mode it is emitted directly in the parent context.@load: reference/... inside the per-item loop: keep the inline reminder as the most recent context anchor.--no-confirm. When --auto-restart is set (and --no-restart is not), the gate is replaced by a forced session restart that writes .claude/resume.md and exits; a fresh claude session resumes from the next item.Determine whether to run in Solo mode (single agent, sequential) or Team mode (implementer + tester agents in parallel).
--solo or --team flag was providedSkip mode selection — use $EXEC_MODE directly.
First, fetch issue information for size estimation (after Issue Selection in Step 1):
ISSUE_INFO=$(gh issue view $ISSUE_NUMBER --repo $ORG/$PROJECT \
--json title,body,labels -q '{title: .title, body: .body, labels: [.labels[].name]}')
Auto-recommend based on issue size:
| Signal | Solo (Recommended) | Team (Recommended) |
|--------|-------------------|-------------------|
| Size label | size/XS, size/S | size/M, size/L, size/XL |
| Description length | < 500 chars | > 500 chars |
| Acceptance criteria | < 3 items | 4+ items |
| Subtask references | None | "Part of", checklist items |
Use AskUserQuestion to present the choice:
Store the result in $EXEC_MODE (solo | team).
$EXEC_MODE == "solo" → Execute Solo Mode Instructions (Steps 1-12 below)$EXEC_MODE == "team" → Execute Team Mode Instructions (after Solo Mode section)Execute the following workflow for the specified project:
If issue number is provided:
# Fetch specific issue
gh issue view $ISSUE_NUMBER --repo $ORG/$PROJECT --json number,title,state,labels
# Verify issue exists and is open
STATE=$(gh issue view $ISSUE_NUMBER --repo $ORG/$PROJECT --json state -q '.state')
if [[ "$STATE" != "OPEN" ]]; then
echo "Error: Issue #$ISSUE_NUMBER is not open (state: $STATE)"
exit 1
fi
If issue number is NOT provided:
# Auto-select by priority
gh issue list --repo $ORG/$PROJECT --label "priority/critical" --state open --limit 1
# If none found:
gh issue list --repo $ORG/$PROJECT --label "priority/high" --state open --limit 1
# If none found:
gh issue list --repo $ORG/$PROJECT --label "priority/medium" --state open --limit 1
Select the oldest (first created) issue from the results.
Store the selected issue number in $ISSUE_NUMBER variable.
Analyze the issue and determine size:
| Size | Expected LOC | Action | |------|--------------|--------| | XS/S | < 200 | Proceed directly | | M | 200-500 | Consider splitting into 2-3 sub-issues | | L/XL | > 500 | Must split into sub-issues, work on first |
If splitting required:
Part of #ORIGINAL referencecd $PROJECT
git fetch origin
git checkout develop && git pull origin develop
# Extract issue title for branch name
ISSUE_TITLE=$(gh issue view $ISSUE_NUMBER --repo $ORG/$PROJECT --json title -q '.title')
# Convert to kebab-case (lowercase, replace spaces with hyphens)
SHORT_DESC=$(echo "$ISSUE_TITLE" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g' | sed -E 's/^-+|-+$//g' | cut -c1-50)
# Determine branch type from issue labels
LABELS=$(gh issue view $ISSUE_NUMBER --repo $ORG/$PROJECT --json labels -q '.labels[].name')
if echo "$LABELS" | grep -q "type/feature"; then
BRANCH_TYPE="feat"
elif echo "$LABELS" | grep -q "type/bug"; then
BRANCH_TYPE="fix"
elif echo "$LABELS" | grep -q "type/refactor"; then
BRANCH_TYPE="refactor"
elif echo "$LABELS" | grep -q "type/docs"; then
BRANCH_TYPE="docs"
else
BRANCH_TYPE="feat" # Default
fi
BRANCH_NAME="${BRANCH_TYPE}/issue-${ISSUE_NUMBER}-${SHORT_DESC}"
git checkout -b "$BRANCH_NAME"
gh issue edit <NUMBER> --repo $ORG/$PROJECT --add-assignee @me
Priority: Start implementation immediately. Minimize upfront planning — analyze code as you implement, not in a separate planning phase.
Analyze existing code style:
.clang-format, .editorconfig if presentImplement changes:
Header file review (C/C++ projects):
Commit per logical unit:
type(scope): descriptionFollow the build verification workflow rule (build-verification.md) to select the
appropriate strategy based on expected build duration.
Before running local builds, verify required toolchains are installed:
# Check availability — do NOT install without asking the user
command -v go &>/dev/null # Go
command -v cargo &>/dev/null # Rust
command -v cmake &>/dev/null # C++
command -v npm &>/dev/null # Node.js
If toolchain is unavailable: Skip local build verification and rely on CI. Do NOT attempt to install toolchains without asking the user first. Report what was verified locally vs what needs CI.
| Build System | Typical Duration | Strategy |
|-------------|-----------------|----------|
| go build / cargo check | < 30s | Inline (synchronous) |
| cmake --build / gradle build | 30s - 5min | Background + log polling |
| ctest / pytest (large suites) | 1 - 10min | Background + log polling |
| CI pipeline (gh workflow run) | 5min+ | CI log check |
For builds expected under 30 seconds:
Bash(command="go build ./...", timeout=60000)
Bash(command="cargo check", timeout=60000)
For builds expected over 30 seconds:
Bash(command="cmake --build build/ ...", run_in_background=true)TaskOutput(task_id="<id>", block=false, timeout=10000)Built target/Finished = success, error:/FAILED = fix neededBash(command="ctest --test-dir build/ ...", run_in_background=true)Do NOT retry the same build without changes -- diagnose first.
Update relevant documentation if applicable:
Commit separately:
docs(scope): update documentation for <feature>
git push -u origin "$BRANCH_NAME"
gh pr create --repo $ORG/$PROJECT \
--title "${BRANCH_TYPE}(scope): description" \
--body "Closes #${ISSUE_NUMBER}
## Summary
- Brief description of changes
## Test Plan
- How to verify the changes"
Required:
Closes #<NUMBER> keyword to link issuecommit-settings.md)After PR creation, capture the PR URL from gh pr create output for the summary.
After PR creation, monitor CI with non-blocking polling:
# Wait briefly for workflows to register
sleep 8
Poll all PR checks every 30 seconds, max 10 minutes:
gh run list --repo $ORG/$PROJECT --branch "$BRANCH_NAME" \
--json databaseId,name,status,conclusion
Decision table — apply per run, evaluate ALL runs each poll cycle:
| All runs status | Any conclusion=failure | Action |
|-----------------|----------------------|--------|
| All completed | No | All pass → proceed to merge |
| All completed | Yes | Diagnose, fix, push, re-poll |
| Any in_progress or queued | — | Poll again after 30s |
Merge gate: Do NOT merge until every run shows status: completed.
A run that is in_progress or queued is NOT a passing run — wait for it.
Timeout: If 10-minute polling limit is reached and any run is still
in_progress or queued, stop polling, report the current status table
to the user, and do NOT merge. Ask the user whether to wait longer
or leave the PR open for manual merge.
Do NOT use gh run watch — it blocks the entire session.
On CI failure, fix the issue and push. Repeat up to 3 attempts. After 3 failures, convert the PR to draft, report the status, and do NOT proceed to merge or produce a completion summary. The task is NOT complete until all CI checks pass and the PR is merged.
ABSOLUTE CI GATE — MANDATORY PRE-MERGE VERIFICATION:
Before executing gh pr merge, you MUST run gh pr checks and verify every single check:
gh pr checks $PR_NUMBER --repo $ORG/$PROJECT
Do NOT merge if ANY check shows:
fail or failure conclusion (regardless of perceived cause)pending, queued, or in_progress statuscancelled, timed_out, or startup_failure conclusionALL checks must show pass or neutral to proceed. No exceptions. No rationalization.
Never judge a failure as "unrelated", "pre-existing", or "infrastructure-only" — all failures block merge.
If any check is not passing, STOP. Do NOT proceed to merge. Instead:
gh pr checks output to the userOnly when ALL checks pass:
gh pr merge $PR_NUMBER --repo $ORG/$PROJECT --squash --delete-branch
If merge fails (e.g., review required), report the status and skip merge.
After merge:
# Verify the linked issue was closed by the merge
STATE=$(gh issue view $ISSUE_NUMBER --repo $ORG/$PROJECT --json state -q '.state')
if [[ "$STATE" != "CLOSED" ]]; then
gh issue close $ISSUE_NUMBER --repo $ORG/$PROJECT
fi
Epic closure: If the issue references a parent epic (e.g., Part of #N),
check if all sub-issues of that epic are now closed. If so, close the epic
with a summary comment.
IMPORTANT: All issue comments MUST be written in English only, regardless of the project's primary language or user's locale.
gh issue comment <NUMBER> --repo $ORG/$PROJECT \
--body "Implementation PR: #<PR_NUMBER>"
See reference/team-mode.md for the complete team mode workflow with 3-team architecture (dev, reviewer, doc-writer), feedback loops, and cleanup.
See _policy.md for common rules.
| Item | Rule |
|------|------|
| Language | All issue comments, PR titles, PR descriptions, and commit messages MUST be written in English only |
| Issue linking | Closes #NUM required in PR |
| Build verification | Must pass before PR creation |
CRITICAL: Do NOT produce a completion summary if CI has any failing, pending, or incomplete checks. A task is only complete when the PR is merged with all CI checks passing.
After successful merge, provide summary:
## Work Summary
| Item | Value |
|------|-------|
| Repository | $ORG/$PROJECT |
| Issue | #$ISSUE_NUMBER - Title |
| Branch | $BRANCH_NAME |
| Execution mode | Solo / Team |
| PR | [#PR_NUMBER](https://github.com/$ORG/$PROJECT/pull/PR_NUMBER) |
| CI Status | All checks passed |
| Merged | Yes |
| Commits | N commits |
### Changes Made
- List of changes
### Files Modified
- file1.cpp
- file2.h
### Next Steps
- Any follow-up items
If CI failed or the PR was not merged, use this format instead:
## Work Summary (INCOMPLETE)
| Item | Value |
|------|-------|
| Repository | $ORG/$PROJECT |
| Issue | #$ISSUE_NUMBER - Title |
| Branch | $BRANCH_NAME |
| PR | [#PR_NUMBER](https://github.com/$ORG/$PROJECT/pull/PR_NUMBER) |
| CI Status | FAILING — [list failed checks] |
| Merged | No |
| Reason | [CI failure / Max retries exceeded / Timeout] |
### Action Required
- User must resolve CI failures before merge
IMPORTANT: Always include the full PR URL in the output (e.g., https://github.com/org/repo/pull/123).
In batch mode, use the summary format from Phase B-5 instead. Include per-item results and the overall success/failure count.
See reference/error-handling.md for prerequisite checks, runtime errors, and batch mode errors.
development
Generate and validate the bidirectional traceability matrix linking requirements, design, code, tests, risk records, and standard clauses. Consumes docs/.index/{manifest,bundles,graph,router}.yaml plus an optional compliance/ directory and produces docs/.index/traceability.yaml (machine-readable) and docs/.index/traceability.md (human-readable). Read-mostly: writes only the two trace artifacts and never mutates source documents. Opt-in — no-op when docs/.index/graph.yaml is absent so non-regulated repos are unaffected.
development
Maintain a SOUP (Software Of Unknown Provenance) register for every third-party software item the project depends on. Discovers candidates from lockfiles (package-lock.json, go.sum, Cargo.lock, requirements.txt, pyproject.toml, pom.xml, packages.lock.json), enriches with human-supplied risk class and verification refs, validates against a license allow-list and the requirements catalogue, and emits a per-supplier report. Outputs docs/.index/soup.yaml plus docs/.index/soup.md. Subcommands: discover | enrich | validate | list | report. Bidirectional linking with traceability via the soup_ids[] field on requirement rows. Opt-in: no-op when no lockfile is detected and docs/.index/soup.yaml is absent. Atomic writes (*.tmp + rename); idempotent (records sorted by id). Implements IEC 62304 sections 5.3.3 (SOUP requirements) and 8.1.1 (configuration items).
devops
Parse sonarcloud[bot] PR comments, classify findings, codify whitelisted auto-fixes, escalate the rest.
testing
Manage Hazard and Risk records for projects on the regulated-industry track. Maintains a single normalized risk file (docs/.index/risk-file.yaml) holding hazard identification, initial and residual risk estimates, control measures with verification links, and bidirectional Risk<->Requirement linking via the requirements[] field. Subcommands: add | edit | evaluate | validate | list. Output is consumed by the traceability skill (matrix risk_ids[] field) and the evidence-pack skill (risk_file kind). Opt-in: no-op when docs/.index/manifest.yaml is absent so non-regulated repos are unaffected. Atomic writes via *.tmp + rename; idempotent for diffability. Implements ISO 14971 sections 5-9 operationally.