github-issues
This skill manages GitHub issues end-to-end, enabling creation, search, viewing, labeling, assignment, commenting, and closure through the gh CLI with curl REST fallback for environments lacking gh. Use it when users request issue filing, viewing, searching, updating, or bulk triage operations like labeling untriaged items or assigning open bugs.
git clone --depth 1 https://github.com/Lilac-Labs/gini-agent /tmp/github-issues && cp -r /tmp/github-issues/skills/dev/github-issues ~/.claude/skills/github-issuesSKILL.md
# GitHub Issues
Manage GitHub issues end to end: list, search, view, create, label,
assign, comment, close, reopen, triage, and run bulk operations. Every
section leads with the `gh` CLI (the preferred path) and follows with a
`curl` REST fallback for environments where `gh` is unavailable.
## When To Use
- User asks to file, view, search, or update a GitHub issue.
- User asks to triage a backlog ("label the untriaged issues", "assign
the open bugs to me").
- User asks for the status of issues on a repo ("what's open on
owner/repo", "show me the bugs I'm assigned").
## When NOT to Use
- Pull-request review or merge flows → not covered here; use `gh pr …`.
- Linear, Jira, or other trackers → use their dedicated skill.
- Plain local git history questions → answer with `git log` directly.
## Setup
`gh` is the preferred path. It must be installed and authenticated before
the first issue operation. **Installing is non-interactive — do it
yourself** (it's a side-effecting command, so it runs through the approval
seam; you propose it, you don't hand it to the user). Only the interactive
sign-in in step 2 needs the user.
### 1. Install gh if it's missing
Check for it, and if it's absent, detect the platform and run the matching
install command yourself:
```bash
command -v gh >/dev/null 2>&1 && echo "gh present: $(gh --version | head -1)"
```
If that prints nothing, install it:
```bash
brew install gh # macOS / Linuxbrew
sudo dnf install -y gh # Fedora / RHEL
sudo pacman -S --noconfirm github-cli # Arch
winget install --id GitHub.cli # Windows
```
Debian/Ubuntu need the GitHub CLI apt repo added first — run this chain
(don't ask the user to):
```bash
(type -p wget >/dev/null || (sudo apt update && sudo apt install -y wget)) \
&& sudo mkdir -p -m 755 /etc/apt/keyrings \
&& wget -nv -O- https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg >/dev/null \
&& sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
| sudo tee /etc/apt/sources.list.d/github-cli.list >/dev/null \
&& sudo apt update && sudo apt install -y gh
```
Only if the host genuinely can't install `gh` (no supported package
manager, no sudo) fall back to the curl/REST path in step 3.
### 2. Authenticate gh if it isn't signed in
```bash
gh auth status >/dev/null 2>&1 && echo "gh authenticated" || echo "gh NOT authenticated"
```
If it's not authenticated, tell the user in one line and stop — sign-in is
interactive, so they run it, not you. Say something like:
> Run `gh auth login` in your terminal to sign in, then I can file the issue.
Pick up where you left off once they confirm; re-run `gh auth status` to
verify before continuing.
### 3. Resolve the auth mode and target repo
```bash
# Prefer the gh CLI when it's present and signed in.
if command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then
AUTH="gh"
else
AUTH="curl"
: "${GITHUB_TOKEN:?gh is unavailable — set GITHUB_TOKEN, or install and auth gh (steps 1-2)}"
fi
# Derive owner/repo from the origin remote (needed for the curl path).
OWNER_REPO=$(git remote get-url origin 2>/dev/null \
| sed -E 's|.*github\.com[:/]||; s|\.git$||')
OWNER=${OWNER_REPO%%/*}
REPO=${OWNER_REPO##*/}
```
`gh` reads `$OWNER/$REPO` from the remote automatically; pass
`--repo owner/repo` to any `gh issue` command to target a different repo.
For curl, the REST base is `https://api.github.com/repos/$OWNER/$REPO`.
## 1. Listing and Searching
**gh:**
```bash
gh issue list
gh issue list --state open --label "needs-triage" --limit 30
gh issue list --assignee @me --json number,title,labels
gh issue list --search "in:title timeout sort:created-desc"
gh issue view 128
gh issue view 128 --comments
```
**curl:**
```bash
# Open issues (the REST /issues endpoint also returns PRs — filter them out).
curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
"https://api.github.com/repos/$OWNER/$REPO/issues?state=open&per_page=30" \
| jq -r '.[] | select(.pull_request|not)
| "#\(.number) \(.state) \([.labels[].name]|join(",")) \(.title)"'
# A single issue with its metadata.
curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
"https://api.github.com/repos/$OWNER/$REPO/issues/128" \
| jq -r '"#\(.number): \(.title)\nState: \(.state) Labels: \([.labels[].name]|join(", "))\n\n\(.body)"'
# Full-text search scoped to the repo.
curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
"https://api.github.com/search/issues?q=timeout+in:title+repo:$OWNER/$REPO" \
| jq -r '.items[] | "#\(.number) \(.state) \(.title)"'
```
## 2. Creating Issues
**gh:**
```bash
gh issue create \
--title "Webhook retries drop the Idempotency-Key header" \
--body "$(cat <<'EOF'
## Summary
Retried webhook deliveries are sent without the Idempotency-Key header,
so the downstream consumer treats each retry as a distinct event.
## Impact
Duplicate charges when a delivery is retried after a transient 5xx.
## Steps to Reproduce
1. Trigger a webhook whose first delivery returns 503.
2. Wait for the automatic retry.
3. Inspect the retried request headers.
## Expected
The retry carries the same Idempotency-Key as the original delivery.
EOF
)" \
--label "bug,webhooks" \
--assignee "@me"
```
**curl:**
```bash
curl -s -X POST -H "Authorization: Bearer $GITHUB_TOKEN" \
"https://api.github.com/repos/$OWNER/$REPO/issues" \
-d "$(jq -nc \
--arg title "Webhook retries drop the Idempotency-Key header" \
--arg body $'## Summary\nRetried deliveries omit the Idempotency-Key header.\n\n## Impact\nDuplicate charges on retry.' \
'{title:$title, body:$body, labels:["bug","webhooks"], assignees:["octocat"]}')"
```
### Body templates
Two fillable templates ship alongside this skill:
- `tDelegate coding work to Claude Code CLI for repository edits, reviews, and multi-turn implementation sessions.
Delegate coding work to the OpenAI Codex CLI for repository changes, reviews, and focused fixes.
Gini's self-knowledge: how Gini configures, extends, and operates on its own state via /api/* and registered tools. Load when the user asks Gini about its own capabilities or asks Gini to modify its own configuration.
Manage Apple Notes via memo CLI: create, search, edit.
Apple Reminders via remindctl: add, list, complete.
Move bytes between Gini upload space, external URLs, and workspace files. Used by every attachment / file-upload / file-download flow regardless of the target system (Linear, GitHub, S3, Notion, etc.).
File a locally-captured, already-redacted Gini crash report as a GitHub issue, with the user's consent. Reads the pending crash queue and delegates the actual filing to the github-issues skill.
Detection engine for Gmail email watches: iterates the watch list, polls gws for new matching mail per watch, dedups, drops automated/self, and hands matches (labeled by sender) to the shared drafting turn. Provisioned and run automatically by the shared email-watch backing job.