Skip to content
Skills Library
Programming · Automation

github

/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).

Repository
ai-agents ↗
Licence
MIT
Last repository change
12.11.2026

Assessment and security

100/ 100Class: good
Format25 / 25
Frontmatter with name and description, valid name, description up to 1,024 characters, name matching the folder.
Discoverability25 / 25
Description explains when to use the skill, has a reasonable length and uses third person.
Content35 / 35
At least 150 words and at most 500 lines, headings, step lists, examples or code.
Hygiene15 / 15
No placeholders such as TODO, no Windows paths, with a licence.
Riskno signals detected in the scan
Files in this package
103
Scripts
84
HTML comments
1
URLs in SKILL.md
0
Deprecation

No signals detected. Repository changed on 12.11.2026, without references to retired models or APIs.

Licence

MIT, open: use and modify while retaining author attribution.

What to check before installing
  • 84 scripts in this package. Review them before installing, as Claude may execute them.
  • SKILL.md zawiera komentarze HTML (1). Nie widać ich w podglądzie Markdown, a model je czyta.

Scripts: scripts/issue/check_existing_pr_for_issue.py, scripts/issue/claim_issue.py, scripts/issue/close_issue.py, scripts/issue/edit_issue_body.py, scripts/issue/get_issue_comments.py, scripts/issue/get_issue_context.py, scripts/issue/get_issue_relationships.py, scripts/issue/invoke_copilot_assignment.py, scripts/issue/issue_provenance.py, scripts/issue/list_issues.py, scripts/issue/new_issue.py, scripts/

What it does and when to use it

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).

Triggers from the description

create a PRadd label to issuecheck CI status
Original author 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).

How it works

  1. Triggers
  2. Transport Preflight
  3. Decision Tree
  4. Offline Invocation
  5. Scripts
  6. Output Format
  7. Process
  8. GitHub Keywords for Issue Linking
  9. Linking Issues to Each Other
  10. Anti-Patterns
Original SKILL.md headings · 423 lines, 3,039 words
SKILL.md preview
---
name: github
version: 4.0.0
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
metadata:
  domains:
    - github
    - pr
    - issue
    - labels
    - milestones
    - comments
    - reactions
  capability:
    kind: specialized-implementation
    status: active
  complexity: intermediate
  generator:
    keep_headings:
      - Decision Tree
      - Offline Invocation
      - Script Reference
      - Output Format
      - See Also
  routing:
    role: front-door
    invoker: autoplan
    trigger: autoplan routes PR, issue, label, and milestone operations to github
    user-facing: true
---
# 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 |

---

## Transport Preflight

`gh` can be installed, hold a token, and still be refused for a whole session
(agent sandboxes that proxy egress do this). Decide the transport once, before
the first GitHub call:

```bash
( for d in "${CLAUDE_PLUGIN_ROOT}" "${COPILOT_PLUGIN_ROOT}" .claude; do if [ -n "$d" ] && [ -f "$d/lib/ptk_run.py" ]; then exec python3 "$d/lib/ptk_run.py" skills/github/scripts/utils/check_github_transport.py; fi; done; echo "ptk_run: no plugin root holds lib/ptk_run.py" >&2; exit 2 )
```

Non-POSIX hosts do not run the block above. The authoritative, per-harness
launcher for this one command is `check_transport` in the `scripts` map of
`pr-review-config.yaml`: the `copilot` entry runs it under PowerShell and
resolves the interpreter (`python3`, then `py -3`, then `python`), because a
Windows host may expose only the launcher. Read it from the map for the harness
you are on rather than transcribing a second copy here, which would drift.

- `Transport: gh` (exit 0). Use the scripts below. This is CI and a normal
  developer machine.
- `Transport: gh_unusable` (exit 0). `gh` cannot reach GitHub here. Route the
  work through the GitHub MCP operations and do not re-try the scripts to
  confirm. The verdict names only what was measured: confirm the operations you
  need are exposed before relying on them. Tool spelling differs by harness
  (`mcp__github__<op>` in Claude Code, `github/<op>` in Copilot CLI).
- Exit 3 or 4. Not a transport problem: a quota window or a fixable token.

Script-to-tool mapping, the operations with no MCP equivalent, and the rules
for reporting one: `references/transport-routing.md`.

A transport failure is an unknown, never a verdict. Do not report a PR as
blocked, red, or unmergeable because the API was unreachable.

---

## Decision Tree

```text
Which transport? → check_github_transport.py (run once, before the rest)

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
├─ Bot CHANGES_REQUESTED blocking after threads resolve → detect_stale_bot_review.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
├─ Issue parent, sub-issues, blockers, related → get_issue_relationships.py
├─ Merge readiness check → test_pr_merge_ready.py
├─ PR reports blocked/dirty and cause is unclear → why_pr_blocked.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
   ├─ Comment on a diff line → new_pr_review_comment.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
   ├─ Link issues (parent, sub-issue, blocked-by, blocking, relates-to) → set_issue_relationship.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
   ├─ Toggle auto-merge → set_pr_auto_merge.py
   ├─ Update PR branch with its base (server side) → update_pr_branch.py
   ├─ Rerun failed CI jobs on a PR or run → rerun_failed_jobs.py
   ├─ Draft PR ready or back → set_pr_ready.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 falls back to a vendored YAML parser, so
no third-party import is required.

```bash
# No PyPI round trip. Runs read-only PR status offline.
( for d in "${CLAUDE_PLUGIN_ROOT}" "${COPILOT_PLUGIN_ROOT}" .claude; do if [ -n "$d" ] && [ -f "$d/lib/ptk_run.py" ]; then exec python3 "$d/lib/ptk_run.py" skills/github/scripts/pr/get_pull_requests.py --state open; fi; done; echo "ptk_run: no plugin root holds lib/ptk_run.py" >&2; exit 2 )
( for d in "${CLAUDE_PLUGIN_ROOT}" "${COPILOT_PLUGIN_ROOT}" .claude; do if [ -n "$d" ] && [ -f "$d/lib/ptk_run.py" ]; then exec python3 "$d/lib/ptk_run.py" skills/github/scripts/pr/get_pr_context.py --pull-request <N>; fi; done; echo "ptk_run: no plugin root holds lib/ptk_run.py" >&2; exit 2 )
( for d in "${CLAUDE_PLUGIN_ROOT}" "${COPILOT_PLUGIN_ROOT}" .claude; do if [ -n "$d" ] && [ -f "$d/lib/ptk_run.py" ]; then exec python3 "$d/lib/ptk_run.py" skills/github/scripts/pr/get_pr_checks.py --pull-request <N>; fi; done; echo "ptk_run: no plugin root holds lib/ptk_run.py" >&2; exit 2 )
```

Any `python3` works; checked with PyYAML and the anthropic SDK blocked.
`scripts/bootstrap-vm.sh` and a project `.venv/bin/python3` ship PyYAML for the
faster path. The guard `tests/test_pr_scripts_offline.py` asserts the read-only
PR scripts and `github_core` import with the 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 with polling (full text: `references/script-catalog.md`) | `--pull-request`, `--wait`, `--timeout-seconds`, `--missing-grace-seconds`, `--required-only`, `--output-format {json,human,auto}` |
| `get_pr_check_logs.py` | Failing CI check logs; names each failed step (`FailedSteps`) | `--pull-request`, `--check-name` (repeatable, case-insensitive), `--max-lines`, `--context-lines` |
| `triage_red_check.py` | CI triage step 1: is a failing PR check also red on main? Exit 0 green on main, 1 red on main, 3 cannot determine | `--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}` |
| `detect_stale_bot_review.py` | Classify a stale bot `CHANGES_REQUESTED` review that blocks merge; emits the human dismissal handoff, never dismisses | `--pull-request`, `--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` |
| `new_pr_review_comment.py` | New diff-line comment | `--pull-request`, `--path`, `--line`, `--side` (default RIGHT), `--body` or `--body-file`, `--dry-run` |
| `post_pr_comment_reply.py` | Threaded replies | `--pull-request`, `--comment-id`, `--body`, `--dry-run` |
| `add_pr_review_thread_reply.py` | Reply to thread by ID (GraphQL) | `--pull-request`, `--thread-id`, `--body`, `--resolve` (needs one of `--expected-head-sha`, `--expected-base-ref`, `--expected-base-sha`) |
| `resolve_pr_review_thread.py` | Mark threads resolved | `--thread-id --expected-pull-request` or `--pull-request --all` |
| `unresolve_pr_review_thread.py` | Unresolve threads | `--thread-id` or `--pull-request --all`, `--dry-run` |
| `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` |
| `why_pr_blocked.py` | Explain a `blocked` PR, or say no cause holds (full text: `references/script-catalog.md`) | `--pull-request`, `--base-branch`, `--output-format {json,human,auto}` |
| `set_pr_auto_merge.py` | Enable/disable auto-merge | `--pull-request`, `--enable`/`--disable`, `--merge-method`, `--dry-run` |
| `invoke_pr_comment_processing.py` | Process AI triage | `--pr-number`, `--verdict`, `--findings-json`, `--dry-run` |
| `new_pr.py` | Create PR, validated | `--title`, `--body`, `--body-file`, `--prepare-body-file`, `--preflight`, `--base`, `--head`, `--draft`, `--skip-validation`, `--audit-reason`, `--validation-base`, `--dry-run` |
| `validate_pr_description.py` | Validate PR description | `--title`, `--body`, `--body-file`, `--fail-on-violation` |
| `update_pr_branch.py` | Server-side "Update branch". Exit 0 requested, done, or current; exit 1 PR not open or head differs from `--expected-head-sha` (`head_moved`); exit 2 not found; exit 3 other API failure or `--wait` timeout; exit 4 auth. Unattended callers pass the SHA | `--pull-request`, `--expected-head-sha`, `--wait`, `--timeout-seconds`, `--dry-run` |
| `rerun_failed_jobs.py` | Rerun failed Actions jobs. Exit 1 run in progress; exit 100 `cannot_be_retried` (no retry, prints fallbacks). Never use an empty commit | `--pull-request` or `--run-id`, `--job-id`, `--dry-run` |
| `set_pr_ready.py` | Draft to ready, or back. Exit 0 done or no-op; 1 not open or `head_moved`; 2 not found; 3 API or unverified; 4 auth | `--pull-request`, `--expected-head-sha`, `--draft`, `--dry-run` |
| `close_pr.py` | Close PR with comment | `--pull-request`, `--comment`, `--dry-run` |
| `reopen_pr.py` | Reopen a closed PR (merged is exit 1) | `--pull-request`, `--comment`, `--dry-run` |
| `merge_pr.py` | Merge pinned to the reviewed head, then read back and audited (ADR-112) | `--pull-request`, `--expected-head-sha`, `--strategy`, `--delete-branch`, `--auto`, `--dry-run` |
| `audit_closing_claims.py` | Fleet audit of open-PR closing claims; exit 1 on an unsupported claim, exit 3 without an administration-read token (full text: `references/script-catalog.md`) | `--state open`, `--artifact`, `--resume-from`, `--output-format {json,human,auto}` |
| `edit_pr_body.py` | PR body edit, SHA-256 guard | `--pull-request`, `--body`/`--body-file`, `--expected-hash`, `--dry-run` |

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

| Script | Purpose | Key Parameters |
|--------|---------|----------------|
| `get_issue_context.py` | Issue metadata (no comments) | `--issue` |
| `list_issues.py` | List issues | `--milestone` |
| `get_issue_comments.py` | Issue comments | `--issue`, `--limit` |
| `new_issue.py` | Create issue; `--source` required, agent needs Step 0 | `--title`, `--body`, `--labels`, `--source`, `--blocked-by`, `--signal`, `--milestone`, `--dry-run` |
| `close_issue.py` | Close with optional comment (full text: `references/script-catalog.md`) | `--issue`, `--reason`, `--comment`, `--verify-claims`, `--dry-run` |
| `reopen_issue.py` | Reopen with optional comment | `--issue`, `--comment`, `--dry-run` |
| `set_issue_labels.py` | Labels | `--issue`, `--labels`, `--remove-labels`, `--priority`, `--dry-run` |
| `set_issue_milestone.py` | Assign milestone | `--issue`, `--milestone`, `--dry-run` |
| `post_issue_comment.py` | Comments with idempotency | `--issue`, `--body`, `--marker`, `--dry-run` |
| `invoke_copilot_assignment.py` | Context for Copilot | `--issue-number`, `--what-if` |
| `set_issue_assignee.py` | Assign users | `--issue`, `--assignees`, `--dry-run` |
| `get_issue_relationships.py` | Native parent, sub-issues, blocked-by, blocking, relates-to | `--issue` |
| `set_issue_relationship.py` | Add or remove a native issue link (idempotent) | `--issue`, `--relation`, `--target`, `--remove`, `--replace-parent`, `--dry-run` |

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

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

### Repository Settings (`repo/` scripts)

| Script | Purpose | Key Parameters |
|--------|---------|----------------|
| `manage_squash_merge_message.py` | Read or update `squash_merge_commit_message` behind an expected-value guard (full text: `references/script-catalog.md`) | `--set`, `--expected-current`, `--dry-run`, `--output-format {json,human,auto}` |

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

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

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

| Script | Purpose | Key Parameters |
|--------|---------|----------------|
| `get_actionable_items.py` | List actionable backlog (reviews, PRs, 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` |
| `check_github_transport.py` | Report whether this session should use gh or the MCP tools | `--output-format` |

### More Scripts

Parameters: `references/script-catalog.md`. Gate-script usage and exit codes: `references/gate-script-usage.md`. PR: `check_pr_live_state.py`, `get_pr_code_scanning_alerts.py`, `check_pr_round_cap.py`, `run_completion_gate.py`, `check_review_thread_resolution_shas.py`, `check_suppressed_review_findings.py`, `detect_stale_pr_comments.py`, `get_pr_comments_by_reviewer.py`, `prepare_pr_body.py`. Issue: `check_existing_pr_for_issue.py`, `claim_issue.py`, `edit_issue_body.py`, `redact_secrets.py`.

### Workflow Testing (`scripts/`)

| Script | Purpose | Key Parameters |
|--------|---------|----------------|
| `test_workflow_locally.py` | Test 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
( for d in "${CLAUDE_PLUGIN_ROOT}" "${COPILOT_PLUGIN_ROOT}" .claude; do if [ -n "$d" ] && [ -f "$d/lib/ptk_run.py" ]; then exec python3 "$d/lib/ptk_run.py" skills/github/scripts/pr/get_pr_context.py --pull-request 50; fi; done; echo "ptk_run: no plugin root holds lib/ptk_run.py" >&2; exit 2 ) | jq '.Data'
```

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

---

## Process

**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
5. Reading an issue or PR: read the full discussion, open every linked item, recurse until no new links

---

## 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 #<number>` |
| Fixes | fix, fixed | `Fixes #<number>` |
| Resolves | resolve, resolved | `Resolves #<number>` |

### Usage Patterns

**In PR Descriptions:**

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

Closes #<number>
Fixes #<number>
```

**In Commit Messages:**

```text
feat: Add feature X

Implements the new feature as specified.

Closes #<number>
```

**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

---

## Linking Issues to Each Other

A `#<number>` in an issue body is text only. It sets no parent, no dependency, and
no relation. Whenever an issue body names another issue as a parent, child,
blocker, or context, add the native link with `set_issue_relationship.py`.

| The text says | `--relation` |
|---------------|--------------|
| "Parent", "child of #N", "part of epic #N", "umbrella #N" | `parent` |
| An epic lists its children | `sub-issue` |
| "Blocked by #N", "depends on #N", or an epic's execution steps name #N | `blocked-by` |
| "Blocks #N", "unblocks #N" | `blocking` |
| Problem statement, context, "split out of #N", "follow-up to #N" | `relates-to` |

After `new_issue.py`, link the new issue in the next call. Pull requests cannot
be linked this way; use a closing keyword. Full decision rules, the audit
procedure, and the MCP fallback: `references/issue-relationships.md`.

### Issue Provenance

`new_issue.py` requires `--source`, which records who selected the work:

- `human`: an explicit human request selected this issue. An owner login, a
  human-started session, or a user approving publication does not qualify.
- `agent`: anything an agent chose. It also needs Step 0 evidence:
  `--blocked-by` (who is blocked, and on what) and `--signal` (the metric, log,
  run, or ticket that proves it). A body that already carries a `## Step 0`
  block with `### Q3` and `### Q5` supplies the evidence instead; passing both
  is an error.

Blank answers, canonical hedge phrases, and conflicting `source:*` labels exit
2 before any GitHub call. The script creates the `source:human` or
`source:agent` label when the repository lacks it, and passes it to
`gh issue create` itself, so a label failure creates no issue. The script
redacts flag evidence before it publishes it. It refuses a body Step 0 block
that carries a secret, because it publishes the body unchanged.

`--source human` also appends `<!-- source:human -->` as the last body line. The
script rejects that marker in any other body.

Ground repo-state issues first: [guide](references/revision-grounding.md).

The GitHub MCP `issue_write` tool, raw `gh issue create`, and workflow steps
that call the API bypass this script's check. The
`Label Issue Source` workflow labels those issues: bots and
owner-login issues without a trailing human marker get `source:agent`, a burst
of owner issues within ten minutes forces `source:agent`, and every other
author gets `source:human`. It only labels.

---

## 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` |
| "Blocked by #N" or "Parent: #N" in a body with no native link | GitHub shows no dependency, parent, or progress | Add the link with `set_issue_relationship.py` |
| Raw `gh api graphql` for `addSubIssue`, `addBlockedBy`, `addRelatesTo` | No idempotency, no PR or parent-conflict guard | Use `set_issue_relationship.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` |
| Retrying `gh` after a session refusal | The refusal has no reset; retries only burn the budget | Run the transport preflight, then use the GitHub MCP operations |
| Reporting a PR blocked because a call failed | An unreachable API is an unknown, not a verdict | Name the transport failure as the cause |
| Treating `mergeable_state`/`mergeStateStatus: blocked` as self-explanatory | It is a cached, frequently-stale field. `why_pr_blocked.py` does not query `reviewDecision` or the required-approving-review count | Run `why_pr_blocked.py` first and resolve unresolved threads with `resolve_pr_review_thread.py`. Details: `references/api-reference.md`, "Blocked PR diagnosis" |

---

## See Also

| Document | Content |
|----------|---------|
| [examples.md](references/examples.md) | 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, endpoints, body-file rule, troubleshooting |
| [transport-routing.md](references/transport-routing.md) | Picking gh or the MCP tools, and the script-to-tool map |
| [issue-relationships.md](references/issue-relationships.md) | Choosing parent, sub-issue, blocked-by, blocking, or relates-to |
| `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)
Files in this package (103)
  • CLAUDE.md 1 KB
  • EXTENSIONS.md 9 KB
  • SKILL.md 24 KB
  • copilot-synthesis.yml 1 KB
  • fix-ci.md 13 KB
  • references/api-reference.md 18 KB
  • references/copilot-prompts.md 4 KB
  • references/copilot-synthesis-guide.md 5 KB
  • references/examples.md 16 KB
  • references/gate-script-usage.md 4 KB
  • references/issue-relationships.md 9 KB
  • references/patterns.md 13 KB
  • references/revision-grounding.md 4 KB
  • references/script-catalog.md 9 KB
  • references/transport-routing.md 16 KB
  • scripts/test_workflow_locally.py 19 KB
  • scripts/issue/CLAUDE.md 1 KB
  • scripts/issue/check_existing_pr_for_issue.py 19 KB
  • scripts/issue/claim_issue.py 17 KB
  • scripts/issue/close_issue.py 27 KB
  • scripts/issue/edit_issue_body.py 8 KB
  • scripts/issue/get_issue_comments.py 9 KB
  • scripts/issue/get_issue_context.py 5 KB
  • scripts/issue/get_issue_relationships.py 7 KB
  • scripts/issue/invoke_copilot_assignment.py 25 KB
  • scripts/issue/issue_provenance.py 12 KB
  • scripts/issue/list_issues.py 12 KB
  • scripts/issue/new_issue.py 22 KB
  • scripts/issue/new_issue_milestone.py 5 KB
  • scripts/issue/new_issue_output.py 1 KB
  • scripts/issue/post_issue_comment.py 15 KB
  • scripts/issue/redact_secrets.py 18 KB
  • scripts/issue/reopen_issue.py 14 KB
  • scripts/issue/set_issue_assignee.py 6 KB
  • scripts/issue/set_issue_labels.py 20 KB
  • scripts/issue/set_issue_milestone.py 14 KB
  • scripts/issue/set_issue_relationship.py 13 KB
  • scripts/milestone/CLAUDE.md 1 KB
  • scripts/milestone/get_latest_semantic_milestone.py 7 KB
  • scripts/milestone/set_item_milestone.py 11 KB
  • scripts/notifications/get_actionable_items.py 13 KB
  • scripts/pr/CLAUDE.md 1 KB
  • scripts/pr/add_pr_review_thread_reply.py 18 KB
  • scripts/pr/audit_closing_claims.py 19 KB
  • scripts/pr/auto_merge_guard.py 9 KB
  • scripts/pr/check_pr_live_state.py 24 KB
  • scripts/pr/check_pr_round_cap.py 22 KB
  • scripts/pr/check_review_thread_resolution_shas.py 19 KB
  • scripts/pr/check_suppressed_review_findings.py 17 KB
  • scripts/pr/close_pr.py 6 KB
  • scripts/pr/closing_claim_extraction.py 11 KB
  • scripts/pr/code_scanning_errors.py 1 KB
  • scripts/pr/code_scanning_sarif.py 7 KB
  • scripts/pr/code_scanning_scope.py 8 KB
  • scripts/pr/code_scanning_transport.py 9 KB
  • scripts/pr/commit_ancestry.py 5 KB
  • scripts/pr/detect_copilot_followup_pr.py 13 KB
  • scripts/pr/detect_stale_bot_review.py 19 KB
  • scripts/pr/detect_stale_pr_comments.py 10 KB
  • scripts/pr/edit_pr_body.py 15 KB
  • scripts/pr/get_pr_check_logs.py 27 KB
  • scripts/pr/get_pr_checks.py 51 KB
  • scripts/pr/get_pr_code_scanning_alerts.py 17 KB
  • scripts/pr/get_pr_comments_by_reviewer.py 14 KB
  • scripts/pr/get_pr_context.py 17 KB
  • scripts/pr/get_pr_review_comments.py 26 KB
  • scripts/pr/get_pr_review_threads.py 14 KB
  • scripts/pr/get_pr_reviewers.py 16 KB
  • scripts/pr/get_pr_reviews.py 9 KB
  • scripts/pr/get_pull_requests.py 7 KB
  • scripts/pr/get_thread_by_id.py 5 KB
  • scripts/pr/get_thread_conversation_history.py 10 KB
  • scripts/pr/get_unaddressed_comments.py 13 KB
  • scripts/pr/get_unresolved_review_threads.py 10 KB
  • scripts/pr/invoke_pr_comment_processing.py 12 KB
  • scripts/pr/merge_pr.py 60 KB
  • scripts/pr/new_pr.py 20 KB
  • scripts/pr/new_pr_review_comment.py 15 KB
  • scripts/pr/post_pr_comment_reply.py 12 KB
  • scripts/pr/pr_comment_dedupe.py 5 KB
  • scripts/pr/pr_context_helpers.py 4 KB
  • scripts/pr/pr_validations.py 20 KB
  • scripts/pr/prepare_pr_body.py 14 KB
  • scripts/pr/reopen_pr.py 8 KB
  • scripts/pr/rerun_failed_jobs.py 24 KB
  • scripts/pr/resolve_pr_review_thread.py 15 KB
  • scripts/pr/run_completion_gate.py 214 KB
  • scripts/pr/set_pr_auto_merge.py 14 KB
  • scripts/pr/set_pr_ready.py 12 KB
  • scripts/pr/test_pr_merge_ready.py 77 KB
  • scripts/pr/test_pr_merged.py 6 KB
  • scripts/pr/triage_red_check.py 30 KB
  • scripts/pr/unresolve_pr_review_thread.py 11 KB
  • scripts/pr/update_pr_branch.py 18 KB
  • scripts/pr/validate_pr_description.py 13 KB
  • scripts/pr/wait_for_unresolved_zero.py 16 KB
  • scripts/pr/why_pr_blocked.py 26 KB
  • scripts/reactions/CLAUDE.md 1 KB
  • scripts/reactions/add_comment_reaction.py 15 KB
  • scripts/reactions/review_thread_lookup.py 2 KB
  • scripts/repo/manage_squash_merge_message.py 10 KB
  • scripts/utils/check_github_transport.py 11 KB
  • scripts/utils/extract_github_context.py 5 KB

Versions

RepositoryScoreLicence
This page · rjmurillo/ai-agents100MIT
rjmurillo/ai-agents100MIT
VincenzoImp/pitcrew100MIT
AceDataCloud/Skills100Apache-2.0
the-open-agent/openagent100Apache-2.0
OpenHands/extensions100MIT
TerminalSkills/skills100Apache-2.0
atomicbot-ai/atomic-agent100MIT
langwatch/langwatch100Apache-2.0

Database snapshot: 13.11.2026 · package version c89fada4c333 (SHA-256 digest of the entire package)

Downloads in the last 30 days: 0 · ranking

Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.

Similar skills

  • 100github-issues
    Create, update, and manage GitHub issues using MCP tools. Use this skill when users want to create bug reports, feature requests, or task issues, update existing issues, add labels/assignees/milestones, or manage issue workflows. Triggers on requests like "create an issue",…
  • 100github-url-intercept
    BLOCKING INTERCEPT: When ANY github.com URL appears in user input, STOP and use this skill. Never fetch GitHub HTML pages directly - they are 5-10MB and will exhaust your context window. This skill routes URLs to efficient API calls (1-50KB). Triggers on: gist.github.com,…
  • 100github-issue-model
    This skill should be used when working with GitHub's issue data model — issue types, sub-issues, dependencies, labels, milestones, issue forms and templates, and the community health files that configure them.
  • 100github-issues
    Create, update, and manage GitHub issues using MCP tools. Use this skill when users want to create bug reports, feature requests, or task issues, update existing issues, add labels/assignees/milestones, manage repository labels, set issue fields (dates, priority, custom fields),…
  • 100github-issues
    Create, update, and manage GitHub issues using MCP tools. Use this skill when users want to create bug reports, feature requests, or task issues, update existing issues, add labels/assignees/milestones, set issue fields (dates, priority, custom fields), set issue types, or…
  • 100github-url-intercept
    BLOCKING INTERCEPT: When ANY github.com URL appears in user input, STOP and use this skill. Never fetch GitHub HTML pages directly - they are 5-10MB and will exhaust your context window. This skill routes URLs to efficient API calls (1-50KB). Triggers on: gist.github.com,…

Feedback and reports

Your message goes to Bartosz Sokoliński. An email address is needed only for a reply. See the privacy policy.