GitHub Issue Tracking for Developers
If It Moved
You’ll Know
One command checks every issue you’re involved in, flags what actually changed, and tells you what to do next. It remembers the details so you don’t have to.
You’re listed on issues across a dozen repos. No single place tracks which ones actually moved.
The external problem
You’re the author, a commenter, or just mentioned on issues spread across repos you don’t maintain. Some have new comments, some got closed, some got duplicated by someone else’s report, and nothing tells you which.
The internal problem
Checking in means opening each issue cold and rereading old threads just to remember what you already knew, hoping you don’t skim past the one comment that actually needed a reply.
What's at stake
A maintainer’s question sits unanswered for two weeks. You comment on an issue someone already fixed. A PR that needs your review goes stale while you’re busy elsewhere.
Five steps carry an issue from fetch to a queued action.
Run it as a one-time audit or a daily check-in. The tracker file carries context between runs, so repeat runs get faster and go deeper.
Discover & Fetch
Pulls every open issue you’re the author, commenter, or mentioned party on, plus anything reopened or closed since the last run, straight from the GitHub API.
Cross-Check Duplicates
Batches of issues get analyzed in parallel: new comments read, duplicate and related issues searched for by keyword, and PR health (merge state, CI, reviews) checked where it applies.
Cache to Tracker
Every fact gets written to the tracker file immediately: state changes, new duplicates, filled-in context. If the session gets interrupted here, nothing is lost.
Goal-Driven Next Steps
Each issue’s recommendation is driven by the goal you set for it: get a fix merged, get a maintainer to respond, or just monitor for an upstream fix.
Report and Act
A tight report of what changed, what’s new, and what to do today, plus queued actions the skill can run directly, like posting a comment or rebasing a PR branch, once you approve them.
The formats and API calls it runs on.
Every fetch runs through documented gh CLI command templates instead of ad hoc queries, and every tracker write follows a strict schema for what gets overwritten versus what only fills a gap, so the tracker stays reliable across sessions.
Reference
gh CLI Patterns
Issue Metadata
Fetch state, labels, comment count, timestamps:
gh api repos/OWNER/REPO/issues/NUMBER --jq '{state: .state, labels: [.labels[].name], comments: .comments, updated: .updated_at, created: .created_at}'Issue Comments
Last 3 comments with author, date, full body:
gh api repos/OWNER/REPO/issues/NUMBER/comments --jq '.[-3:] | .[] | {author: .user.login, date: (.created_at | split("T")[0]), body: .body}'All comments (for drafting — verify claims before posting):
gh api repos/OWNER/REPO/issues/NUMBER/comments --jq '.[] | {author: .user.login, date: .created_at, body: .body}'Comments since a date:
gh api repos/OWNER/REPO/issues/NUMBER/comments --jq '[.[] | select(.created_at > "DATE")] | .[] | {author: .user.login, date: (.created_at | split("T")[0]), body: .body}'Truncation rules: Never truncate comments on the primary issue being reviewed — technical
details (addresses, error codes, test counts) get lost. For secondary fetches (known
duplicates, upstream), [0:1500] is acceptable to manage context size.
Issue Body
Full issue body (read before commenting on unfamiliar issues):
gh api repos/OWNER/REPO/issues/NUMBER --jq '.body'
Search: Issues Involving User
Open issues with recent activity:
gh api "search/issues?q=involves:USERNAME+updated:>DATE+is:open" --jq '.items[] | "#\(.number) \(.repository_url | split("/") | .[-2:] | join("/")) — \(.title) [updated: \(.updated_at)]"'Search: Issues by Author
gh api "search/issues?q=author:USERNAME+is:open&per_page=100&sort=updated" --jq '.items[] | "#\(.number) \(.repository_url | split("/") | .[-2:] | join("/")) — \(.title) [updated: \(.updated_at | split("T")[0])]"'Search: Issues by Commenter (excluding authored)
gh api "search/issues?q=commenter:USERNAME+is:open+-author:USERNAME&per_page=100&sort=updated" --jq '.items[] | "#\(.number) \(.repository_url | split("/") | .[-2:] | join("/")) — \(.title) [updated: \(.updated_at | split("T")[0])]"'Search: Keyword Search for Duplicates
Search for issues matching keywords, created after a specific date:
gh api "search/issues?q=repo:OWNER/REPO+is:open+created:>DATE+KEYWORD1+KEYWORD2&per_page=10" --jq '.items[] | "#\(.number) — \(.title) [\(.created_at | split("T")[0])] @\(.user.login)"'Use multiple keyword variations per search to catch different phrasings. Example for an OAuth issue:
- Search 1:
OAuth redirect MCP - Search 2:
clientId mcp add - Search 3:
Slack plugin authentication
Search: Recently Closed Issues
gh api "search/issues?q=involves:USERNAME+is:closed+closed:>DATE&per_page=50&sort=updated" --jq '.items[] | "#\(.number) \(.repository_url | split("/") | .[-2:] | join("/")) — \(.title) [closed: \(.closed_at | split("T")[0])]"'Post Comment
gh issue comment NUMBER --repo OWNER/REPO --body "$(cat <<'EOF' Comment body here. Supports **markdown**. EOF )"
Always use heredoc (<<'EOF') for comment bodies to handle special characters and newlines.
Quick State Check
Check if an issue is still open (fast, minimal data):
gh api repos/OWNER/REPO/issues/NUMBER --jq '.state'
PR Status Check
gh api repos/OWNER/REPO/pulls/NUMBER --jq '{state: .state, merged: .merged, title: .title, updated: .updated_at}'PR Health (run when the tracked item is a PR)
Merge-readiness, review decision, and CI status in one call:
gh pr view NUMBER --repo OWNER/REPO \ --json state,mergeStateStatus,mergeable,reviewDecision,statusCheckRollup,reviews
gh pr view --json resolves reviewDecision and statusCheckRollup via GraphQL under the
hood — the REST issues endpoint cannot. Use this template (not the issues endpoint) whenever
you need merge/CI/review state.
Reading the result:
mergeStateStatus—DIRTYmeans merge conflict;BLOCKEDmeans a required check or review
is failing/missing; CLEAN/UNSTABLE means mergeable (UNSTABLE = non-required checks failing).
mergeable—CONFLICTINGconfirms a conflict;MERGEABLEis clean;UNKNOWNmeans GitHub
is still computing it.
reviewDecision—APPROVED,CHANGES_REQUESTED, orREVIEW_REQUIRED.statusCheckRollup— array of checks; surface any withconclusionofFAILURE/TIMED_OUT/CANCELLED.
Review interpretation (do not misread):
- A review with
state: COMMENTEDis not an approval. Onlystate: APPROVEDcounts. - Reviewers whose login ends in
[bot]do not satisfy a human-review requirement — record
them separately from human reviews.
Rate Limiting
GitHub API has rate limits. If running many parallel requests:
- Authenticated requests: 5000/hour
- Search API: 30 requests/minute
- If you hit limits, batch searches and add short delays between search batches
- Metadata fetches (repos/OWNER/REPO/issues/NUMBER) don't count against search limits
Parallel Execution Strategy
To maximize speed, batch API calls by type:
Batch 1 (parallel): All active issue metadata + comments (these are REST calls, not search)
Batch 2 (parallel): All known duplicate/related issue checks (REST calls)
Batch 3 (parallel): All keyword searches for new duplicates (search API — respect 30/min limit)
Batch 4 (parallel): User involvement search + closed issue checks + upstream checks
Batches 1 and 2 can run simultaneously. Batch 3 should start after a brief pause if Batch 1+2 included many calls. Batch 4 can run with Batch 1.
Use it now. It's free.
Works on all platforms. Pick yours and get set up in under a minute.
Download & upload in 60 seconds
One click downloads the zip and opens Claude.ai.
Click below — the zip downloads and Claude.ai opens.
Click the + button in the skills column on the left.
Select Create a skill.
Select Upload a skill and upload the zip.
Start your issue check-in by running /estack-github-issue-tracker.
GitHub Issue Tracker ships in E-Stack, a set of 20 free skills installed by one command. See the whole stack.