gh-issues

star 413

Walk over all open GitHub issues that are unassigned or assigned to the current user, and process each one via the /gh-issue skill, sequentially.

TypedDevs By TypedDevs schedule Updated 6/3/2026

name: gh-issues description: Walk over all open GitHub issues that are unassigned or assigned to the current user, and process each one via the /gh-issue skill, sequentially. user-invocable: true argument-hint: "[--limit N] [--label foo] [--dry-run]" disable-model-invocation: true allowed-tools: Read, Bash, Skill

GitHub Issues Watcher

Purpose

Process every open GitHub issue that is unassigned or assigned to the current user (@me), one after another, by delegating each to the /gh-issue skill. Stop on first hard failure so it can be inspected.

Driven from inside the Claude session rather than a polling shell script.

Args

  • --limit N — process at most N issues this run (default: all).
  • --label foo — only issues carrying label foo.
  • --dry-run — list issues that would be processed; do not invoke /gh-issue.

Strip leading # if user passes #123 style.

Phase 1: Discover

Fetch open issues that are unassigned or assigned to @me, oldest first. GitHub search does not OR these cleanly, so run two queries and merge:

# Unassigned
gh issue list \
  --state open \
  --search "no:assignee" \
  --json number,title,labels,assignees,createdAt \
  --limit 200

# Assigned to me
gh issue list \
  --state open \
  --assignee "@me" \
  --json number,title,labels,assignees,createdAt \
  --limit 200

Merge:

  • Deduplicate by number.
  • Keep only issues whose assignees array is empty or contains the current user (gh api user -q .login).
  • Drop issues assigned to anyone else (defensive).
  • Skip tracker/epic issues — those whose body is a checklist of other issues (e.g. - [ ] #123 …). Process the child issues directly, not the parent.
  • Apply --label filter if given.
  • Apply --limit if given.
  • Sort ascending by createdAt (FIFO).

Print the queue: #<num> <title> [assignee] per line, where [assignee] is unassigned or @me. If empty, exit cleanly.

Phase 2: Worktree Sanity

Before touching any issue:

git status --porcelain
git fetch origin main
git checkout main && git reset --hard origin/main

Abort if worktree dirty. Never auto-stash.

Phase 3: Process Loop

For each issue in the queue:

  1. Re-check assignment state (someone else may have grabbed it):

    gh issue view <num> --json assignees -q '.assignees[].login'
    me=$(gh api user -q .login)
    
    • Empty output → unassigned, proceed.
    • Only $me listed → already mine, proceed (skip self-assign step).
    • Any other login present → skip this issue.
  2. Invoke the /gh-issue skill with the issue number. That skill owns:

    • self-assign via gh issue edit <num> --add-assignee @me (no-op if already assigned)
    • branch from fresh main (prefix from labels: fix/, feat/, docs/)
    • strict TDD: RED → GREEN → REFACTOR (no production code without a failing test first)
    • full suite green locally (./bashunit tests/ and ./bashunit --parallel tests/)
    • CHANGELOG.md entry under ## Unreleased for user-facing changes
    • commit with conventional message + Closes #<num> in the body
    • PR opened via /pr #<num>
  3. Before pushing, run the exact command CI's strict job uses — plain sequential runs miss simple-mode and strict-mode bugs that CI rejects:

    ./bashunit --parallel --simple --strict tests/
    

    In --simple mode print_line emits only a one-char marker, so assert on pure helper functions, not on print_line stdout. Under --strict (set -euo pipefail): no [ cond ] && assignment (use if), initialise arrays with =() and read elements as ${arr[i]:-}, and never enable shopt -s extdebug in the parent shell (isolate it inside a $() subshell).

  4. After /gh-issue returns, wait for CI green on the PR:

    gh pr checks --watch
    

    Fix red checks on the branch before moving on. Bash 3.0 CI fails often — check that job specifically. A red docker/registry step is usually a transient Docker Hub timeout, not your code: gh run rerun <id> --failed.

  5. Merge when allowed:

    gh pr merge --auto --squash --admin
    
  6. Close the issue if the squash-merge did not. GitHub builds the squash commit from the PR body, and /pr writes Related #<num> there (never Closes), so the Closes #<num> in the branch commit body is lost. After merge:

    gh issue view <num> --json state -q .state   # still OPEN?
    gh issue close <num> --reason completed -c "Done in #<pr> (merged)."
    

    If the issue belongs to a tracker/epic, tick its checkbox in the parent issue body. Use sed for the tick — bash ${body/- [ ] #N/...} treats [ ] as a glob (it matches a space, not literal brackets) and silently does nothing:

    gh issue view <tracker> --json body -q .body \
      | sed 's/- \[ \] #<num>/- [x] #<num>/' | gh issue edit <tracker> --body-file -
    
  7. Sync main for next iteration:

    git checkout main && git fetch origin main && git reset --hard origin/main
    
  8. Continue with next issue.

Stop Conditions

Halt the loop and surface the failure when:

  • /gh-issue errors out or leaves the worktree dirty.
  • ./bashunit tests/ or ./bashunit --parallel tests/ fails after implementation (for the right reason — distinguish pre-existing failures; see Notes).
  • make sa (ShellCheck) or make lint (EditorConfig) fails.
  • CI stays red after one fix attempt.
  • Merge is blocked by branch protection beyond --admin bypass.
  • --limit reached.
  • Queue empty.

Do not retry blindly. Report which issue failed and why.

Dry Run

With --dry-run, only execute Phase 1 and print the queue. No assignment, no branching, no commits.

Preconditions

  • gh authenticated, can read issues, open and merge PRs.
  • Worktree clean.
  • main exists and tracks origin/main.
  • /gh-issue and /pr skills available in this session.

Notes

  • Bash 3.0+ compatibility is mandatory. No declare -A, [[ ]], ${var,,}, negative array indexing, or &>> in src/. See .claude/rules/bash-style.md.
  • Quality gate is make sa + make lint, not bare shfmt. shfmt -w . without project flags rewrites the whole tree (collapses line-continuations, flips binary-op style, tabs the indent_size = unset files). Match the surrounding 2-space style by hand and rely on make lint (EditorConfig) to verify. There is no shfmt make target.
  • Know your baseline. tests/unit/coverage_subshell_test.sh fails on some macOS setups regardless of the change — confirm a failure is new (git stash + re-run) before treating it as a regression.
  • Treat GitHub CI as the full quality gate; locally run focused tests during implementation, the full sequential + parallel suite once before commit.
  • Never split bundled changes into multiple PRs unless the issue explicitly demands it.
Install via CLI
npx skills add https://github.com/TypedDevs/bashunit --skill gh-issues
Repository Details
star Stars 413
call_split Forks 49
navigation Branch main
article Path SKILL.md
More from Creator