githubv1.0.06 min read

Github Issues

Create, triage, label, assign GitHub issues via gh or REST.

Create, search, triage, and manage GitHub issues. Each section shows gh first, then the curl fallback.

Prerequisites

  • Authenticated with GitHub (see github-auth skill)
  • Inside a git repo with a GitHub remote, or specify the repo explicitly

Setup

BASH
if command -v gh &>/dev/null && gh auth status &>/dev/null; then AUTH="gh" else AUTH="git" if [ -z "$GITHUB_TOKEN" ]; then if _hermes_env="${HERMES_HOME:-$HOME/.hermes}/.env"; [ -f "$_hermes_env" ] && grep -q "^GITHUB_TOKEN=" "$_hermes_env"; then GITHUB_TOKEN=$(grep "^GITHUB_TOKEN=" "$_hermes_env" | head -1 | cut -d= -f2 | tr -d '\n\r') elif grep -q "github.com" ~/.git-credentials 2>/dev/null; then GITHUB_TOKEN=$(uv run python3 "${HERMES_HOME:-$HOME/.hermes}/skills/github/github-auth/scripts/git-credential-token.py") fi fi fi REMOTE_URL=$(git remote get-url origin) OWNER_REPO=$(echo "$REMOTE_URL" | sed -E 's|.*github\.com[:/]||; s|\.git$||') OWNER=$(echo "$OWNER_REPO" | cut -d/ -f1) REPO=$(echo "$OWNER_REPO" | cut -d/ -f2)

1. Viewing Issues

With gh:

BASH
gh issue list gh issue list --state open --label "bug" gh issue list --assignee @me gh issue list --search "authentication error" --state all gh issue view 42

With curl:

BASH
# List open issues curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ "https://api.github.com/repos/$OWNER/$REPO/issues?state=open&per_page=20" \ | python3 -c " import sys, json for i in json.load(sys.stdin): if 'pull_request' not in i: # GitHub API returns PRs in /issues too labels = ', '.join(l['name'] for l in i['labels']) print(f\"#{i['number']:5} {i['state']:6} {labels:30} {i['title']}\")" # Filter by label curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ "https://api.github.com/repos/$OWNER/$REPO/issues?state=open&labels=bug&per_page=20" \ | python3 -c " import sys, json for i in json.load(sys.stdin): if 'pull_request' not in i: print(f\"#{i['number']} {i['title']}\")" # View a specific issue curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/issues/42 \ | python3 -c " import sys, json i = json.load(sys.stdin) labels = ', '.join(l['name'] for l in i['labels']) assignees = ', '.join(a['login'] for a in i['assignees']) print(f\"#{i['number']}: {i['title']}\") print(f\"State: {i['state']} Labels: {labels} Assignees: {assignees}\") print(f\"Author: {i['user']['login']} Created: {i['created_at']}\") print(f\"\n{i['body']}\")" # Search issues curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ "https://api.github.com/search/issues?q=authentication+error+repo:$OWNER/$REPO" \ | python3 -c " import sys, json for i in json.load(sys.stdin)['items']: print(f\"#{i['number']} {i['state']:6} {i['title']}\")"

2. Creating Issues

With gh:

BASH
gh issue create \ --title "Login redirect ignores ?next= parameter" \ --body "## Description After logging in, users always land on /dashboard. ## Steps to Reproduce 1. Navigate to /settings while logged out 2. Get redirected to /login?next=/settings 3. Log in 4. Actual: redirected to /dashboard (should go to /settings) ## Expected Behavior Respect the ?next= query parameter." \ --label "bug,backend" \ --assignee "username"

With curl:

BASH
curl -s -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/issues \ -d '{ "title": "Login redirect ignores ?next= parameter", "body": "## Description\nAfter logging in, users always land on /dashboard.\n\n## Steps to Reproduce\n1. Navigate to /settings while logged out\n2. Get redirected to /login?next=/settings\n3. Log in\n4. Actual: redirected to /dashboard\n\n## Expected Behavior\nRespect the ?next= query parameter.", "labels": ["bug", "backend"], "assignees": ["username"] }'

Bug Report Template

## Bug Description <What's happening> ## Steps to Reproduce 1. <step> 2. <step> ## Expected Behavior <What should happen> ## Actual Behavior <What actually happens> ## Environment - OS: <os> - Version: <version>

Feature Request Template

## Feature Description <What you want> ## Motivation <Why this would be useful> ## Proposed Solution <How it could work> ## Alternatives Considered <Other approaches>

3. Managing Issues

Add/Remove Labels

With gh:

BASH
gh issue edit 42 --add-label "priority:high,bug" gh issue edit 42 --remove-label "needs-triage"

With curl:

BASH
# Add labels curl -s -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/issues/42/labels \ -d '{"labels": ["priority:high", "bug"]}' # Remove a label curl -s -X DELETE \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/issues/42/labels/needs-triage # List available labels in the repo curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/labels \ | python3 -c " import sys, json for l in json.load(sys.stdin): print(f\" {l['name']:30} {l.get('description', '')}\")"

Assignment

With gh:

BASH
gh issue edit 42 --add-assignee username gh issue edit 42 --add-assignee @me

With curl:

BASH
curl -s -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/issues/42/assignees \ -d '{"assignees": ["username"]}'

Commenting

With gh:

BASH
gh issue comment 42 --body "Investigated — root cause is in auth middleware. Working on a fix."

With curl:

BASH
curl -s -X POST \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/issues/42/comments \ -d '{"body": "Investigated — root cause is in auth middleware. Working on a fix."}'

Closing and Reopening

With gh:

BASH
gh issue close 42 gh issue close 42 --reason "not planned" gh issue reopen 42

With curl:

BASH
# Close curl -s -X PATCH \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/issues/42 \ -d '{"state": "closed", "state_reason": "completed"}' # Reopen curl -s -X PATCH \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/issues/42 \ -d '{"state": "open"}'

Linking Issues to PRs

Issues are automatically closed when a PR merges with the right keywords in the body:

Closes #42 Fixes #42 Resolves #42

To create a branch from an issue:

With gh:

BASH
gh issue develop 42 --checkout

With git (manual equivalent):

BASH
git checkout main && git pull origin main git checkout -b fix/issue-42-login-redirect

4. Issue Triage Workflow

When asked to triage issues:

  1. List untriaged issues:
BASH
# With gh gh issue list --label "needs-triage" --state open # With curl curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ "https://api.github.com/repos/$OWNER/$REPO/issues?labels=needs-triage&state=open" \ | python3 -c " import sys, json for i in json.load(sys.stdin): if 'pull_request' not in i: print(f\"#{i['number']} {i['title']}\")"
  1. Read and categorize each issue (view details, understand the bug/feature)

  2. Apply labels and priority (see Managing Issues above)

  3. Assign if the owner is clear

  4. Comment with triage notes if needed

5. Bulk Operations

For batch operations, combine API calls with shell scripting:

With gh:

BASH
# Close all issues with a specific label gh issue list --label "wontfix" --json number --jq '.[].number' | \ xargs -I {} gh issue close {} --reason "not planned"

With curl:

BASH
# List issue numbers with a label, then close each curl -s \ -H "Authorization: token $GITHUB_TOKEN" \ "https://api.github.com/repos/$OWNER/$REPO/issues?labels=wontfix&state=open" \ | python3 -c "import sys,json; [print(i['number']) for i in json.load(sys.stdin)]" \ | while read num; do curl -s -X PATCH \ -H "Authorization: token $GITHUB_TOKEN" \ https://api.github.com/repos/$OWNER/$REPO/issues/$num \ -d '{"state": "closed", "state_reason": "not_planned"}' echo "Closed #$num" done

Quick Reference Table

Actionghcurl endpoint
List issuesgh issue listGET /repos/{o}/{r}/issues
View issuegh issue view NGET /repos/{o}/{r}/issues/N
Create issuegh issue create ...POST /repos/{o}/{r}/issues
Add labelsgh issue edit N --add-label ...POST /repos/{o}/{r}/issues/N/labels
Assigngh issue edit N --add-assignee ...POST /repos/{o}/{r}/issues/N/assignees
Commentgh issue comment N --body ...POST /repos/{o}/{r}/issues/N/comments
Closegh issue close NPATCH /repos/{o}/{r}/issues/N
Searchgh issue list --search "..."GET /search/issues?q=...