github

Execute GitHub operations (PRs, issues, milestones, labels, comments, merges) using Python scripts with structured output and error handling. Use when working with pull requests, issues, review comments, CI checks, or milestones instead of raw gh. Use when you say "create a PR", "add label to issue", or "check CI status". Do NOT use to read a pasted github.com URL (use github-url-intercept).

rjmurillo/ai-agents5 installsMITSynced Aug 22

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
name: github
description: Execute GitHub operations (PRs, issues, milestones, labels, comments, merges) using Python scripts with structured output and error handling. Use when working with pull requests, issues, review comments, CI checks, or milestones instead of raw gh. Use when you say "create a PR", "add label to issue", or "check CI status". Do NOT use to read a pasted github.com URL (use github-url-intercept).
license: MIT
---

# GitHub Skill

Use these scripts instead of raw `gh` commands for consistent error handling and structured output.

---

## Triggers

| Phrase | Operation |
|--------|-----------|
| `create a PR` | new_pr.py |
| `respond to review comments` | post_pr_comment_reply.py |
| `check CI status` | get_pr_checks.py / get_pr_check_logs.py |
| `close issue` | close_issue.py |
| `add label to issue` | set_issue_labels.py |

---

## Decision Tree

```text
Need GitHub data?
├─ List PRs (filtered) → get_pull_requests.py
├─ PR info/diff → get_pr_context.py
├─ CI check status → get_pr_checks.py
├─ Failing check also red on main? → triage_red_check.py
├─ CI failure logs → get_pr_check_logs.py
├─ Review comments → get_pr_review_comments.py
├─ Review threads → get_pr_review_threads.py
├─ Review verdicts (approved / changes requested) → get_pr_reviews.py
├─ Unique reviewers → get_pr_reviewers.py
├─ Unaddressed bot comments → get_unaddressed_comments.py
├─ PR merged check → test_pr_merged.py
├─ Copilot follow-up PRs → detect_copilot_followup_pr.py
├─ Validate PR description → validate_pr_description.py
├─ Issue info → get_issue_context.py
├─ Merge readiness check → test_pr_merge_ready.py
├─ Latest milestone → get_latest_semantic_milestone.py
├─ Actionable backlog → get_actionable_items.py
└─ Need to take action?
   ├─ Create issue → new_issue.py
   ├─ Create PR → new_pr.py
   ├─ Reply to review → post_pr_comment_reply.py
   ├─ Reply to thread (GraphQL) → add_pr_review_thread_reply.py
   ├─ Comment on issue → post_issue_comment.py
   ├─ Add reaction → add_comment_reaction.py
   ├─ Apply labels → set_issue_labels.py
   ├─ Set issue milestone → set_issue_milestone.py
   ├─ Set PR/issue milestone (auto-detect) → set_item_milestone.py
   ├─ Assign issue → set_issue_assignee.py
   ├─ Resolve threads → resolve_pr_review_thread.py
   ├─ Unresolve threads → unresolve_pr_review_thread.py
   ├─ Process AI triage → invoke_pr_comment_processing.py
   ├─ Assign Copilot → invoke_copilot_assignment.py
   ├─ Enable/disable auto-merge → set_pr_auto_merge.py
   ├─ Close PR → close_pr.py
   └─ Merge PR → merge_pr.py
```

---

## Offline Invocation

In a network-restricted sandbox (triage, PR status checks), run read-only PR
scripts under `scripts/pr/` with bare `python3`, not `uv run`.

`uv run <script>` resolves the whole project environment first, which downloads
`anthropic==0.116.0` (a core dependency in `pyproject.toml`) from PyPI and times
out with no network. The read-only PR scripts never import the anthropic SDK.
They import only `github_core`, which parses YAML with a vendored fallback when
PyYAML is absent (issue #1844), so no third-party import is required.

```bash
# No PyPI round trip. Runs read-only PR status offline.
# CLAUDE_PLUGIN_ROOT is set in a vendored install; falls back to .claude in-repo.
SCRIPTS_DIR="${COPILOT_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-.claude}}/skills/github/scripts/pr"
python3 "$SCRIPTS_DIR/get_pull_requests.py" --state open
python3 "$SCRIPTS_DIR/get_pr_context.py" --pr <N>
python3 "$SCRIPTS_DIR/get_pr_checks.py" --pr <N>
```

Any `python3` works: `github_core` falls back to a vendored YAML parser when
PyYAML is absent (issue #1844), confirmed by running these scripts with both
PyYAML and the anthropic SDK blocked. The interpreter from
`scripts/bootstrap-vm.sh` and a project `.venv/bin/python3` both ship PyYAML for
the faster path. Do not use `uv run` for read-only triage offline; it forces the
resolve that fetches anthropic.

The regression guard `tests/test_pr_scripts_offline.py` asserts the read-only PR
scripts and `github_core` import with the anthropic SDK blocked.

---

## Scripts

### PR Operations (`scripts/pr/`)

| Script | Purpose | Key Parameters |
|--------|---------|----------------|
| `get_pull_requests.py` | List PRs with filters | `--state`, `--label`, `--author`, `--base`, `--head`, `--search`, `--limit` |
| `get_pr_context.py` | PR metadata, diff, files | `--pull-request`, `--include-changed-files`, `--include-diff` |
| `get_pr_checks.py` | CI check status, polling | `--pull-request`, `--wait`, `--timeout-seconds`, `--required-only`, `--output-format {json,human,auto}` |
| `get_pr_check_logs.py` | Fetch logs from failing CI checks | `--pull-request`, `--max-lines`, `--context-lines` |
| `triage_red_check.py` | CI-failure triage step 1: is a failing PR check also red on main's latest run? Exit 0 green on main, exit 1 red on main (EvidenceUrl cites the main run), exit 3 cannot determine (never reported as green) | `--check-name`, `--branch`, `--history-depth`, `--pull-request` |
| `get_pr_review_comments.py` | Paginated review comments with stale detection | `--pull-request`, `--include-issue-comments`, `--detect-stale`, `--exclude-stale`, `--only-stale` |
| `get_pr_review_threads.py` | Thread-level review data | `--pull-request`, `--unresolved-only` |
| `get_pr_reviews.py` | Review submissions (verdict state and body) | `--pull-request`, `--state`, `--output-format {json,human,auto}` |
| `get_pr_reviewers.py` | Enumerate unique reviewers | `--pull-request`, `--exclude-bots` |
| `get_unaddressed_comments.py` | Bot comments needing attention | `--pull-request` |
| `get_unresolved_review_threads.py` | Unresolved thread IDs | `--pull-request` |
| `wait_for_unresolved_zero.py` | Settling gate: poll until unresolved count holds at zero across bot scans | `--pull-request`, `--interval-seconds`, `--max-wait-seconds`, `--strict-pagination` |
| `test_pr_merged.py` | Check if PR is merged | `--pull-request` |
| `detect_copilot_followup_pr.py` | Detect Copilot follow-up PRs | `--pr-number`, `--owner`, `--repo` |
| `post_pr_comment_reply.py` | Thread-preserving replies | `--pull-request`, `--comment-id`, `--body` |
| `add_pr_review_thread_reply.py` | Reply to thread by ID (GraphQL) | `--pull-request`, `--thread-id`, `--body`, `--resolve` |
| `resolve_pr_review_thread.py` | Mark threads resolved | `--thread-id --expected-pull-request` or `--pull-request --all` |
| `unresolve_pr_review_thread.py` | Mark threads unresolved | `--thread-id` or `--pull-request --all` |
| `get_thread_by_id.py` | Get single thread by ID | `--thread-id` |
| `get_thread_conversation_history.py` | Full thread comment history | `--thread-id`, `--include-minimized` |
| `test_pr_merge_ready.py` | Check merge readiness | `--pull-request`, `--ignore-ci`, `--ignore-threads` |
| `set_pr_auto_merge.py` | Enable/disable auto-merge | `--pull-request`, `--enable`/`--disable`, `--merge-method` |
| `invoke_pr_comment_processing.py` | Process AI triage output | `--pr-number`, `--verdict`, `--findings-json` |
| `new_pr.py` | Create PR with validation | `--title`, `--body`, `--base` |
| `validate_pr_description.py` | Validate PR description | `--title`, `--body`, `--body-file`, `--fail-on-violation` |
| `close_pr.py` | Close PR with comment | `--pull-request`, `--comment` |
| `merge_pr.py` | Merge with strategy | `--pull-request`, `--strategy`, `--delete-branch`, `--auto` |

### Issue Operations (`scripts/issue/`)

| Script | Purpose | Key Parameters |
|--------|---------|----------------|
| `get_issue_context.py` | Issue metadata (no comments) | `--issue` |
| `get_issue_comments.py` | Issue comment thread (discourse) | `--issue`, `--limit` |
| `new_issue.py` | Create new issue | `--title`, `--body`, `--labels` |
| `close_issue.py` | Close with optional comment (`--verify-claims` aborts on a cited commit/PR the remote disproves, exit 1, and separately on one it could not check, exit 3 or 4) | `--issue`, `--reason`, `--comment`, `--verify-claims` |
| `reopen_issue.py` | Reopen with optional comment | `--issue`, `--comment` |
| `set_issue_labels.py` | Apply labels (auto-create) | `--issue`, `--labels`, `--priority` |
| `set_issue_milestone.py` | Assign milestone | `--issue`, `--milestone` |
| `post_issue_comment.py` | Comments with idempotency | `--issue`, `--body`, `--marker` |
| `invoke_copilot_assignment.py` | Synthesize context for Copilot | `--issue-number`, `--what-if` |
| `set_issue_assignee.py` | Assign users to issues | `--issue`, `--assignees` |

### Milestone Operations (`scripts/milestone/`)

| Script | Purpose | Key Parameters |
|--------|---------|----------------|
| `get_latest_semantic_milestone.py` | Detect latest semantic version milestone | `--owner`, `--repo` |
| `set_item_milestone.py` | Assign milestone to PR/issue (auto-detect) | `--item-type`, `--item-number`, `--milestone-title` |

### Reactions (`scripts/reactions/`)

| Script | Purpose | Key Parameters |
|--------|---------|----------------|
| `add_comment_reaction.py` | Add emoji reactions (batch support) | `--comment-id`, `--reaction`, `--comment-type`, `--pull-request` |

### Notifications (`scripts/notifications/`)

| Script | Purpose | Key Parameters |
|--------|---------|----------------|
| `get_actionable_items.py` | List actionable backlog (reviews, authored PRs, assigned issues) | `--owner`, `--repo`, `--limit` |

### Utilities (`scripts/utils/`)

| Script | Purpose | Key Parameters |
|--------|---------|----------------|
| `extract_github_context.py` | Extract issue/PR references from text | `--text`, `--require-pr`, `--require-issue` |

### Workflow Testing (`scripts/`)

| Script | Purpose | Key Parameters |
|--------|---------|----------------|
| `test_workflow_locally.py` | Test GitHub Actions locally with act | `--workflow`, `--event`, `--job`, `--dry-run` |

---

## Output Format

All scripts output structured JSON wrapped in a standard envelope per ADR-051.

**Success envelope:**

```json
{
  "Success": true,
  "Data": { "Number": 42, "Title": "..." },
  "Error": null,
  "Metadata": { "Script": "get_pr_checks.py", "Version": "1.0.0", "Timestamp": "..." }
}
```

**Error envelope:**

```json
{
  "Success": false,
  "Data": null,
  "Error": { "Message": "PR not found", "Code": 2, "Type": "NotFound" },
  "Metadata": { "Script": "get_pr_checks.py", "Version": "1.0.0", "Timestamp": "..." }
}
```

**Usage:**

```bash
SCRIPTS_DIR="${CLAUDE_PLUGIN_ROOT:-.claude}/skills/github/scripts"
result=$(python3 "$SCRIPTS_DIR/pr/get_pr_context.py" --pull-request 50)
echo "$result" | jq '.Data'
```

Exit codes follow ADR-035: 0=success, 1=logic error, 2=config error, 3=external failure, 4=auth error.

---

## Process

This skill provides a toolkit of Python scripts for GitHub operations. Use scripts directly or compose them into workflows.

**Basic Usage:**

1. Identify the operation needed using the Decision Tree
2. Find the corresponding script in the Script Reference
3. Call the script with required parameters
4. Parse the JSON output

**Example Flow:**

```bash
SCRIPTS_DIR="${CLAUDE_PLUGIN_ROOT:-.claude}/skills/github/scripts"

# Get PR context
python3 "$SCRIPTS_DIR/pr/get_pr_context.py" --pull-request 123

# Check CI status
python3 "$SCRIPTS_DIR/pr/get_pr_checks.py" --pull-request 123

# Add comment if needed
python3 "$SCRIPTS_DIR/pr/post_pr_comment_reply.py" --pull-request 123 --comment-id 456 --body "CI failures detected"
```

---

## GitHub Keywords for Issue Linking

GitHub automatically links and closes issues when PRs use specific keywords in PR descriptions, commit messages, or PR comments.

### Supported Keywords

| Keyword | Variations | Example |
|---------|-----------|---------|
| Closes | close, closed | `Closes #123` |
| Fixes | fix, fixed | `Fixes #456` |
| Resolves | resolve, resolved | `Resolves #789` |

### Usage Patterns

**In PR Descriptions:**

```markdown
## Summary
This PR adds feature X.

Closes #123
Fixes #456
```

**In Commit Messages:**

```text
feat: Add feature X

Implements the new feature as specified.

Closes #123
```

**Best Practices:**

- Use keywords in PR description for primary issue
- Use keywords in commit bodies for related issues
- One keyword per line for clarity
- Place keywords in dedicated section or at end of description

---

## Anti-Patterns

| Avoid | Why | Instead |
|-------|-----|---------|
| Raw `gh pr view` commands | No structured output | Use `get_pr_context.py` |
| Raw `gh api` for comments | Doesn't preserve threading | Use `post_pr_comment_reply.py` |
| Replying to thread expecting auto-resolve | Replies DON'T auto-resolve threads | Use `resolve_pr_review_thread.py` after reply |
| Inline issue creation | Missing validation | Use `new_issue.py` |
| Multiple individual reactions | 88% slower | Use batch mode in `add_comment_reaction.py` |
| Hardcoding owner/repo | Breaks in forks | Let scripts infer from `git remote` |
| Ignoring exit codes | Missing error handling | Check exit codes per ADR-035 |
| Skipping idempotency markers | Duplicate comments | Use `--marker` parameter |
| Raw `gh notify` or notifications API | 403 with app tokens | Use `get_actionable_items.py` |

---

## See Also

| Document | Content |
|----------|---------|
| [examples.md](references/examples.md) | Complete script examples |
| [patterns.md](references/patterns.md) | Reusable workflow patterns |
| [copilot-prompts.md](references/copilot-prompts.md) | Creating @copilot directives |
| [copilot-synthesis-guide.md](references/copilot-synthesis-guide.md) | Copilot context synthesis |
| [api-reference.md](references/api-reference.md) | Exit codes, API endpoints, troubleshooting |
| `scripts/github_core/` | Shared Python helper functions |

---

## Verification

Before completing a GitHub operation:

- [ ] Correct script selected from Decision Tree
- [ ] Required parameters provided (PR/issue number)
- [ ] Response JSON parsed successfully
- [ ] Exit code is 0 (success)
- [ ] State change verified (for mutating operations)

More Code Review skills

pr-to-video

heygen-com/hyperframes

Turn a GitHub pull request (a PR URL, owner/repo#N, or 'this PR' in a checked-out repo) into a code-change explainer video — changelog, feature reveal, fix, or refactor walkthrough built from the diff, commits, and files: the input is a code change, not a website. Not a product promo (/product-launch-video) or a no-PR topic explainer (/faceless-explainer). Unclear → /hyperframes.

178.9k

receiving-code-review

obra/superpowers

Use when receiving code review feedback, before implementing suggestions, especially if feedback seems unclear or technically questionable - requires technical rigor and verification, not performative agreement or blind implementation

178.0k

public-relations

coreyhaines31/marketingskills

When the user wants help with public relations, earned media, press coverage, journalist outreach, or media strategy (not pull requests). Also use when the user mentions 'PR,' 'public relations,' 'press,' 'press release,' 'press coverage,' 'media outreach,' 'pitch a journalist,' 'get featured,' 'media list,' 'media kit,' 'press kit,' 'newsjacking,' 'news hijack,' 'HARO,' 'Qwoted,' 'Featured,' 'Help A Reporter,' 'reporter request,' 'tech press,' 'TechCrunch,' 'earned media,' 'thought leadership placement,' 'op-ed,' 'guest article,' 'press contacts,' 'podcast prep,' 'going on a podcast,' 'podcast guest,' 'prep me for this podcast,' or 'how do I get press.' Use this for earned media work — finding journalists, pitching stories, newsjacking, prepping podcast appearances, and responding to press requests. For startup/SaaS/AI directory submissions, see directory-submissions. For product launches, see launch. For social-media engagement, see social. For cold-email outreach to prospects, see cold-email.

33.1k

← All Code Review skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY