agentsclimarketplace

Github

Skill jmlrt/skills/github

Personal agent skills for Claude Code, Cursor, and compatible AI coding tools

Install
npx -y skills add jmlrt/skills --skill github

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

GitHub CLI (gh) mechanics: retrieving issues/PRs, posting reviews, managing workflow runs, and troubleshooting. Use when working with the gh CLI itself.

SKILL.md

17.6 KB, ~4.8k tokens by cl100k_base, as published. Nobody here has run it

GitHub CLI (gh) mechanics

Scope + defaults

  • Default to read-only GitHub access. Do not create/edit/comment/close/merge or otherwise modify GitHub state unless explicitly requested.
  • Prefer small, targeted reads (specific PR/issue, or a small list) over dumping large JSON.
  • Use explicit --method GET for gh api reads.
  • Shell, sandbox, and authentication behavior varies by environment. Verify a failing command with gh <command> --help or the current GitHub CLI documentation before treating a workaround as universal.

Load a skill from a pull request

When a referenced skill is only available on an unmerged PR branch, fetch its entry point directly and follow it as local guidance:

gh api repos/<owner>/<repo>/contents/<path-to-SKILL.md> --jq '.content' | base64 --decode
# macOS: replace --decode with -D

Repo selection (critical)

  • gh defaults to the current git repository.
  • If the target is in another repo, always pass --repo <owner/repo>.

Quick start (common reads)

View a PR (JSON)

gh pr view 12345 --repo owner/repo --json number,title,state,url,author,assignees,labels,baseRefName,headRefName,mergeable,reviewDecision,reviewRequests,reviews,commits,files,checks,statusCheckRollup

PR inline review comments (diff comments)

  • gh pr view <num> --comments is convenient but can truncate. For all comments, prefer gh api with --paginate:
gh api --method GET repos/owner/repo/pulls/12345/comments --paginate

PR "conversation" comments (non-diff) come from the issues endpoint:

gh api --method GET repos/owner/repo/issues/12345/comments --paginate

PR event history (merge queue, labels, assignments)

Use the issues events endpoint — the pulls timeline endpoint (pulls/{n}/timeline) returns 404:

gh api --method GET repos/owner/repo/issues/1598/events --jq '.[] | {event, created_at, actor: .actor.login}'

Useful events: added_to_merge_queue, removed_from_merge_queue, labeled, head_ref_force_pushed.

Merge queue operations

Adding a PR to the merge queue requires GraphQL — gh pr merge --auto prints a message but does not enqueue when the repo uses a merge queue strategy:

# 1. Wait for required checks to pass (enqueuePullRequest fails if any are pending)
gh pr checks <number> --repo owner/repo --watch

# 2. Get the PR node ID
PR_ID=$(gh api graphql -f query='query { repository(owner:"<owner>", name:"<repo>") { pullRequest(number: <N>) { id } } }' --jq '.data.repository.pullRequest.id')

# 3. Enqueue
gh api graphql -f pullRequestId="$PR_ID" -f query='mutation($pullRequestId: ID!) { enqueuePullRequest(input: {pullRequestId: $pullRequestId}) { mergeQueueEntry { position } } }'

Mutation name: enqueuePullRequest — NOT addPullRequestToMergeQueue (that field does not exist).

Alternative: auto-merge — when checks haven't passed yet (so enqueuePullRequest would fail), use enablePullRequestAutoMerge to schedule merge-on-green instead of direct queue entry:

NODE_ID=$(gh api repos/<owner>/<repo>/pulls/<N> --jq '.node_id')
gh api graphql -f query="mutation { enablePullRequestAutoMerge(input: {pullRequestId: \"$NODE_ID\", mergeMethod: SQUASH}) { pullRequest { number autoMergeRequest { enabledAt } } } }"

gh pr merge --squash unreliable on merge-queue repos: returns invalid character '{' even when it works (PR silently enters queue) or silently does nothing. Always verify afterward: gh api graphql -f query='{ repository(owner:"<org>",name:"<repo>") { pullRequest(number:<N>) { mergeQueueEntry { position } autoMergeRequest { enabledAt } } } }' --jq '.data.repository.pullRequest'. If both are null, the command failed — use enqueuePullRequest or enablePullRequestAutoMerge.

View an issue (JSON)

gh issue view 678 --repo owner/repo --json number,title,state,url,author,assignees,labels,milestone,projects,body,comments

Compare two branches/commits

To check whether two branches have diverged (e.g. before assuming a pipeline/repo's main and a release branch run identical code), use the compare endpoint rather than manually diffing files:

gh api repos/owner/repo/compare/main...9.5 --jq '{status, ahead_by, behind_by}'
gh api repos/owner/repo/compare/main...9.5 --jq '.commits[] | {sha: .sha[0:8], message: (.commit.message | split("\n")[0])}'
gh api repos/owner/repo/commits/<sha> --jq '.files[] | {filename, patch}'   # see what a specific commit changed

ahead_by/behind_by > 0 means real divergence — worth checking before assuming behavior is identical across branches just because params/env look the same.

List PRs

gh pr list --repo owner/repo --state open --limit 20
gh pr list --repo owner/repo --search "author:@me is:open" --limit 20
gh pr list --repo owner/repo --search "review-requested:@me is:open" --limit 20

Draft PRs are not reliably included in --state=all or cross-repo searches. When completeness matters (e.g. auditing all authored PRs), run a separate explicit is:draft search in addition to the main query:

gh api graphql -f query='{ search(query: "author:USERNAME is:pr is:draft created:>=YYYY-MM-DD org:ORG", type: ISSUE, first: 50) { nodes { ... on PullRequest { number title repository { nameWithOwner } } } } }'

List issues

gh issue list --repo owner/repo --state open --limit 50

Issue write operations

Create issue:

gh issue create --title "<title>" --body "<body>"
gh issue create --title "<title>" --body "<body>" --label <label1>,<label2>
gh issue create --title "<title>" --body "<body>" --assignee <username>

Edit issue:

gh issue edit <ISSUE_NUMBER> --title "<new-title>"
gh issue edit <ISSUE_NUMBER> --body "<new-body>"
gh issue edit <ISSUE_NUMBER> --add-label <label1>,<label2>
gh issue edit <ISSUE_NUMBER> --add-assignee <user1>,<user2>

Close issue:

gh issue close <ISSUE_NUMBER>
gh issue close <ISSUE_NUMBER> --reason "completed"

Add comment:

gh issue comment <ISSUE_NUMBER> --body "<comment-text>"

Edit existing comment (when asked to modify a comment, always edit the existing one instead of adding a new one):

gh api repos/<owner>/<repo>/issues/comments/<COMMENT_ID> --method PATCH --input /dev/stdin <<'EOF'
{
  "body": "<updated-comment-text>"
}
EOF

Cross-repo references in markdown (for clickable links in comments, use full owner/repo#number format; omit owner only for local repo refs):

owner/repo#123                  # Clickable cross-repo PR reference (requires owner/repo for cross-repo)
#1022                           # Local issue reference (current repo — owner optional)

Note: GitHub markdown auto-links owner/repo#number format; partial repo#number (without owner) is not clickable across repos. Always use the full format for cross-repo references.

Links in issue/PR bodies and comments: bare URL or owner/repo#number, never [text](url) markdown link syntax. GitHub auto-linkifies both. The [text](url) convention used for internal Notes/PKM workspace files does not apply here — that's for referencing GitHub items from markdown notes, not for content actually posted to GitHub.

Actions & Workflows

Manage workflows

List workflows:

gh workflow list

Enable/disable workflows:

gh workflow enable <workflow-file-name-or-id>
gh workflow disable <workflow-file-name-or-id>

Trigger workflow manually:

gh workflow run <workflow-file-name-or-id>
gh workflow run <workflow-file-name-or-id> -f <input-name>=<input-value>

View and control runs

List workflow runs:

gh run list
gh run list --workflow <workflow-name-or-id>
gh run list --status failure

Filter by commit:

COMMIT_SHA=$(git rev-parse HEAD)
gh run list --head-sha $COMMIT_SHA

View run details:

gh run view <run-id>
gh run view <run-id> --json status,conclusion,createdAt,updatedAt,headBranch

View logs:

gh run view <run-id> --log
gh run view <run-id> --log-failed
gh run download <run-id> -D <output-dir>

List jobs in run:

gh run view <run-id> --json jobs --jq '.jobs[] | {name, status, conclusion}'

# Rerun failed run
gh run rerun <run-id>
gh run rerun <run-id> --failed

# Cancel run
gh run cancel <run-id>

PR-specific workflow queries

# Get latest run for PR
PR=<PR_NUMBER>
COMMIT_SHA=$(gh pr view $PR --json commits -q '.commits[-1].oid')
gh run list --head-sha $COMMIT_SHA --limit 1 --json status,conclusion,name,createdAt,url

# Get latest run on main
gh run list --branch main --limit 1 --json status,conclusion,createdAt,workflowName

Write operations (when explicitly requested)

  • Any GitHub side effect requires explicit user approval.
  • Never merge into the base branch via CLI; merges happen via the GitHub UI.

Creating or editing a PR

Use pull-request for PR creation instructions. This skill covers only the CLI side.

gh pr create          # optionally --draft
gh pr edit <number> --title "..." --body "..."

PR already exists for the branch: gh pr create exits with code 1. Use gh pr edit <number> instead.

Backticks in --body heredocs: do not escape backticks with \`` in --body "$(cat <<'EOF'...EOF)"content. The single-quoted heredoc prevents all shell expansion — raw backticks are safe. Using`` causes the backslash to appear literally in the rendered GitHub description.

Creating multiple PRs in bulk: gh pr create (and gh api REST POST) fail with TLS keychain errors when called in a loop on macOS. Use a single batched createPullRequest GraphQL mutation instead:

# Get repo node ID first
gh api graphql -f query='{ repository(owner: "OWNER", name: "REPO") { id } }' \
  --jq '.data.repository.id'

# Create up to ~15 PRs in one call (resource limit ~16 mutations per call)
gh api graphql -f query='
mutation {
  pr1: createPullRequest(input: {
    repositoryId: "<REPO_ID>",
    title: "[8.19] <title> (#N)", baseRefName: "8.19", headRefName: "backport/8.19/pr-N",
    body: "Backport of #N.", draft: true
  }) { pullRequest { number url } }
  pr2: createPullRequest(input: {
    repositoryId: "<REPO_ID>",
    title: "[9.3] <title> (#N)", baseRefName: "9.3", headRefName: "backport/9.3/pr-N",
    body: "Backport of #N.", draft: true
  }) { pullRequest { number url } }
}' --jq '.data | to_entries[] | "\(.key): #\(.value.pullRequest.number) \(.value.pullRequest.url)"'

Bulk labeling: use addLabelsToLabelable mutations batched similarly. Get label ID: gh api graphql -f query='{ repository(owner: "o", name: "r") { label(name: "backport") { id } } }' --jq '.data.repository.label.id'. Batch at ~16 per call; split into a second call if you hit RESOURCE_LIMITS_EXCEEDED.

Draft ↔ ready-for-review:

gh pr ready <number> --undo   # → draft
gh pr ready <number>           # → ready

Reopening a closed PR after a force push: Both gh pr reopen and PATCH state=open will fail with "state cannot be changed. The branch was force-pushed or recreated." There is no workaround — create a new PR from the same branch instead (gh pr create), reference the old PR number in the body for context.

Resolving and unresolving review threads

Resolve a single thread:

gh api graphql -f id="<THREAD_ID>" -f query='
mutation($id: ID!) {
  resolveReviewThread(input: {threadId: $id}) {
    thread { id isResolved }
  }
}
'

Unresolve a thread:

gh api graphql -f id="<THREAD_ID>" -f query='
mutation($id: ID!) {
  unresolveReviewThread(input: {threadId: $id}) {
    thread { id isResolved }
  }
}
'

Batch resolve all threads on a PR:

OWNER=$(gh repo view --json owner -q .owner.login)
REPO=$(gh repo view --json name -q .name)
PR=<PR_NUMBER>

gh api graphql -f o="$OWNER" -f r="$REPO" --field p=$PR -f query='
query($o: String!, $r: String!, $p: Int!) {
  repository(owner: $o, name: $r) {
    pullRequest(number: $p) {
      reviewThreads(first: 100) {
        nodes { id }
      }
    }
  }
}
' -q '.data.repository.pullRequest.reviewThreads.nodes[].id' | while read id; do
  gh api graphql -f i="$id" -f query='
  mutation($i: ID!) {
    resolveReviewThread(input: {threadId: $i}) {
      thread { id isResolved }
    }
  }
  ' && echo "✅ $id"
done

Posting reviews

gh pr review <n> --repo <r> --approve --body "..."
gh pr review <n> --repo <r> --request-changes --body "..."
gh pr review <n> --repo <r> --comment --body "..."

Inline comments via REST API:

gh api repos/<r>/pulls/<n>/reviews --method POST \
  --field commit_id="<head_sha>" \
  --field event="APPROVE" \
  --field body="<summary_body>" \
  --field "comments[][path]=<file>" \
  --field "comments[][line]=<line_number>" \
  --field "comments[][side]=RIGHT" \
  --field "comments[][body]=<comment_body>"

Get head SHA:

gh pr view <n> --repo <r> --json headRefOid --jq .headRefOid

Troubleshooting

Wrong repo: Add --repo <owner/repo> explicitly.

Not authenticated: gh auth statusgh auth login (scopes: repo, gist, read:org). If GITHUB_TOKEN is invalid: unset GITHUB_TOKEN GH_TOKEN.

Repository not found: Either not in a git repo (git rev-parse --git-dir) or REST shorthand failing. Extract explicitly: OWNER=$(gh repo view --json owner -q .owner.login), REPO=$(gh repo view --json name -q .name).

No push permission: Check gh repo view <owner/repo> --json viewerPermission. If READ only, push to a fork: gh pr create --repo upstream --base main --head user:branch.

Too much output: Use --json with narrow field list.

GraphQL variable error: Declare in signature: mutation($id: ID!) { ... } not mutation { ... }.

GraphQL Int! variable: -f p="$PR" sends a string and fails with "Variable $p of type Int! was provided invalid value". Use --field p=$PR (no quotes) to send an integer.

Review thread ID format: resolveReviewThread requires thread IDs with PRRT_... prefix (from the reviewThreads query). Review comment IDs (PRRC_...) will fail with "Could not resolve to a node". Always fetch thread IDs via reviewThreads(first: N) { nodes { id } } before resolving.

gh api --jq object construction silently returns empty: never use --jq '{key: .value}' object construction syntax — it fails silently with no error. Use string concatenation instead ('.f1 + " " + .f2') or pipe to jq -r:

# ❌ WRONG — silently returns empty
gh api repos/owner/repo/pulls/1 --jq '{state: .state, title: .title}'

# ✅ CORRECT — string concat
gh api repos/owner/repo/pulls/1 --jq '.state + " " + .title'

# ✅ CORRECT — pipe to jq
gh api repos/owner/repo/pulls/1 | jq -r '.state + " " + .title'

gh api / gh pr create TLS failures on macOS: two distinct failure modes:

  • Spawned scripts: gh api in a child process (bash script.sh, $() in a loop) fails with tls: failed to verify certificate: x509: OSStatus -26276. Run gh api as direct inline Bash calls only.
  • Sequential calls in the same session: even in a direct Bash tool invocation, calling gh api or gh pr create multiple times sequentially (e.g. in a shell loop) causes TLS failures on the second and subsequent calls. The failure is silent — exit code is 0, any following echo runs, but the operation was never performed. Always verify by querying GitHub after bulk write operations before assuming success.
  • Workaround for bulk writes: use a single batched GraphQL mutation call (e.g. multiple aliased createPullRequest mutations) — one HTTPS connection, no sequential reconnects.

GraphQL failure fallback: if gh api graphql returns a 502, HTML, or TLS error, use the REST API instead:

gh api --method GET repos/<org>/<repo>/pulls/<N> --jq '{state, title, merged_at}'
# list all open PRs
gh api --method GET 'repos/<org>/<repo>/pulls?state=open' --jq '.[] | {number, state, title}'
# list closed/merged
gh api --method GET 'repos/<org>/<repo>/pulls?state=closed' --jq '.[] | {number, state, title, merged_at}'

Note: quote the URL when it contains ? to prevent zsh glob expansion.

gh pr diff does not support file path filtering: gh pr diff <N> accepts only one positional arg (the PR number) — passing extra file paths fails with "accepts at most 1 arg(s)". To filter by filename, pipe through grep:

gh pr diff <N> --repo <owner>/<repo> | grep "^diff --git\|^+\|^-" | grep -A20 "filename-pattern"
# or to see only changed filenames:
gh pr diff <N> --repo <owner>/<repo> --name-only

gh pr diff returns empty output: TLS issues or large diffs can cause gh pr diff to silently return nothing. Fall back to the files API:

gh api --method GET repos/<owner>/<repo>/pulls/<number>/files --paginate \
  --jq '.[] | {filename, additions, deletions, patch}'

Debug: GH_DEBUG=api gh <command> shows actual API calls.

Gists

Secret vs public: gh gist create creates a secret gist by default. Use --public for a public gist. There is no --secret flag — it will fail with "unknown flag: --secret".

gh gist create file1 file2           # secret (default)
gh gist create file1 file2 --public  # public
gh gist delete <gist-id>
gh gist edit <gist-id> -f filename /path/to/replacement-file

Gist revisions cannot be deleted via the API or UI — the only way to remove a revision is to delete the gist entirely and recreate it.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.