Use this skill when the user asks to inspect or operate GitHub state: issues, pull requests, checks, reviews, workflow run logs, labels, releases, or PR lifecycle actions.
Do not use it for local-only git work such as commits, rebases, branch cleanup, or worktree management unless a GitHub operation is also required.
Customer-readable explanation
What this skill can do
Use gh CLI for GitHub issue, PR, checks, review, workflow run, release, and collaborator-permission operations, plus a pre-merge rule-review procedure, with structured JSON output and safety gates
| What the customer wants | What the skill will do | What the customer can see |
|---|---|---|
| Complete the work covered by this skill | Read the user request, the necessary context, and this skill's main-body process, and execute the minimal reliable steps | The customer will see the execution plan, a summary of command output, code/document changes, verification results, and a description of risks. |
| Add/check/revoke repository collaborator permissions for a given person | First confirm the target repository, username, and permission level, then execute gh api write operations and verify they took effect |
Permission level description, confirmation checklist, verification result |
| Before merging, want to know whether this PR complies with the rules | Pull the diff + this repository's own rules files, cross-check them, then give tiered recommendations; do not auto-merge | One-sentence conclusion, a findings list tiered by blocking/should-fix/no-objection, and CI and mergeable status |
| Missing dependency, permission, configuration, or key | Stop actions that require external state, and clearly state what is missing | Installation commands, application URLs, configuration paths, or questions that need customer confirmation |
| Execution complete | Summarize successes, skips, failures, file changes, and verification results | A completion receipt that can be copied into a ticket/log |
How the customer uses it
- State the goal in natural language and provide the necessary inputs: files, URLs, repo, workspace, proposal, vault, or platform account status.
- The agent first determines whether this skill applies, then checks dependencies, configuration, permissions, and risky actions.
- For actions that support dry-run or preview, provide a preview first; for anything involving deletion, overwriting, sending, publishing, or writing remote state, ask the customer for confirmation first.
- After execution, verify the actual output; do not substitute "looks successful" for evidence.
- The final reply must give the customer a visible summary: what was done, log summary, file changes, issues, and next steps.
Dependencies and installation
Install this skill (single skill):
npx skills add soia-team/soia-open-skills -g -a '*' -s soia-dev-github-ops -y
Configuration conventions:
~/.config/soia-skills/soia-open-skills/soia-dev/soia-dev-github-ops/config.yml
SOIA_DEV_GITHUB_OPS_CONFIG_FILE=<custom-config-path>
- If this skill does not require private configuration, you may skip creating
config.yml。 - If an API key, cookie, session, provider home, or local path is required, it may only go into private
config.yml, the process environment, or the provider's own login state; it must not be written into the repository, the vault body, or logs. - Strong dependencies, optional dependencies, and third-party skill relationships must be based on this
SKILL.mdand the subsequent "dependencies / prerequisites / resources / boundaries" descriptions; if it is not clearly written, first add the description or ask the customer, and do not guess. - Third-party skills may only declare dependencies and installation methods; do not directly modify third-party skill files.
Logs and completion receipt
Every execution must let the customer see the process and results. Minimum receipt format:
完成:<一句话说明本次完成了什么>。
日志摘要:
- started: <检查到的输入/配置/依赖,不打印秘密值>
- processed: <数量或范围>
- created/updated: <数量或路径>
- skipped/failed: <数量和原因>
文件变化:
- <绝对路径或“未改动文件”>
验证:
- <运行过的检查、命令或人工核对点>
问题与下一步:
- <缺 key / 缺依赖 / 需要客户确认 / 建议下一条命令;没有则写“无”>
Safety Model
- Read-only
ghqueries may run once the target repo is known. - Mutating operations require clear user intent in the current request.
- High-impact operations require an explicit final confirmation before running:
gh pr merge,gh release create, branch deletion, label deletion, workflow dispatch against production, granting/revoking a collaborator's permission, or any action that closes public work or changes who can write to a repo. - Collaborator permission changes are the single most sensitive operation this
skill performs — more sensitive than
gh pr merge. A bad merge affects one change; a wrong permission grant is a standing capability the person keeps using until someone notices and revokes it. Never infer the target repo, username, or permission level from prior conversation turns alone — restate all three and get explicit confirmation in the current exchange before the write call. See "Collaborator Access Management" below for the full gate. - Use
gh auth statusbefore operations. If auth is missing or expired, stop and tell the user what needs to be configured. - Never put GitHub tokens in
SKILL.md, shell history, scripts, issue bodies, PR bodies, or comments. Usegh auth loginfor credentials; keep only non-token defaults in the skill-specific private config.
Repo Resolution
Resolve the target repository in this order:
- Explicit command argument:
--repo <owner>/<repo>. - Current git remote if the command runs inside a GitHub checkout.
- Environment variable:
GITHUB_REPOSITORY=<owner>/<repo>. - Optional private config:
~/.config/soia-skills/soia-open-skills/soia-dev/soia-dev-github-ops/config.yml. - Ask the user if the repo is still ambiguous.
The optional config file is a user-owned YAML file with an env: mapping, for example:
env:
GITHUB_REPOSITORY: "<owner>/<repo>"
Do not hardcode maintainer-specific repositories in reusable commands.
Query Patterns
Prefer --json and --jq for agent-readable output.
# Auth and repo sanity checks
gh auth status
gh repo view --json nameWithOwner,defaultBranchRef,isPrivate
# Open PRs
gh pr list --repo <owner>/<repo> --state open \
--json number,title,state,author,headRefName,baseRefName,updatedAt
# Single PR status
gh pr view <number> --repo <owner>/<repo> \
--json number,title,state,mergeable,mergeStateStatus,reviewDecision,headRefName,baseRefName
# PR checks
gh pr checks <number> --repo <owner>/<repo> \
--json name,state,bucket,startedAt,completedAt,link
# Issues
gh issue list --repo <owner>/<repo> --state open \
--json number,title,state,labels,assignees,updatedAt
# Workflow runs
gh run list --repo <owner>/<repo> --limit 20 \
--json databaseId,status,conclusion,workflowName,headBranch,createdAt,url
When reporting results, include:
- repo:
<owner>/<repo> - object: PR / issue / run / release
- identifier: number, run id, or tag
- status: open / closed / merged / passing / failing / cancelled
- next action or blocker
PR Lifecycle
Create PRs with a concise body containing summary and verification evidence.
gh pr create --repo <owner>/<repo> \
--base <base-branch> \
--head <feature-branch> \
--title "<type>: <short change>" \
--body "$(cat <<'EOF'
## Summary
- <what changed>
## Verification
- <command>: <result>
EOF
)"
Review operations:
gh pr review <number> --repo <owner>/<repo> --approve --body "<review note>"
gh pr review <number> --repo <owner>/<repo> --request-changes --body "<required changes>"
gh pr comment <number> --repo <owner>/<repo> --body "<comment>"
Before merge:
gh pr view <number> --repo <owner>/<repo> \
--json mergeable,mergeStateStatus,reviewDecision,statusCheckRollup \
--jq '{mergeable, mergeStateStatus, reviewDecision, checks: .statusCheckRollup}'
Only merge after explicit confirmation:
gh pr merge <number> --repo <owner>/<repo> --squash --delete-branch
Pre-Merge Rule Review
Use for: "Review this PR to see if it should be merged" / "Check whether this PR complies with the rules for me" / a bare PR
list URL the user wants reviewed / "review this <repo> 's pull/<n>".
The output of this procedure is advice, not a merge trigger. The user
reviews the findings and decides. A request to review is not a request to
merge — this holds even if the same message also pre-authorizes merging
("review PR 42, merge it if it's fine"). Pre-authorization is conditional on
findings the user has not seen yet, so it cannot substitute for the
confirmation Safety Model requires before gh pr merge. Always post the
graded findings from Step 4 first, then treat the next message as the actual
merge confirmation — never merge in the same turn the report is produced.
Step 0 — Resolve which PR
If the user gave a PR list URL or repo without a specific number, list the open PRs first and ask which one to review — do not guess:
gh pr list --repo <owner>/<repo> --state open \
--json number,title,author,updatedAt
Step 1 — Pull the facts (read-only, no confirmation needed)
gh pr view <number> --repo <owner>/<repo> \
--json title,body,author,baseRefName,headRefName,state,additions,deletions,changedFiles,labels,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup
gh pr diff <number> --repo <owner>/<repo>
gh pr checks <number> --repo <owner>/<repo> --json name,state,bucket
Step 2 — Find this repo's own rules (do not borrow another repo's)
Look for these files at the root of the PR's repo, in this order, skipping any that do not exist — do not assume a rule file exists because a similar repo you know has one:
CLAUDE.md/AGENTS.md— agent behavior conventionsCONTRIBUTING.md.github/PULL_REQUEST_TEMPLATE.md— if it has a checklist, the PR body should address each item- If the changed files live under a subdirectory that has its own
AGENTS.md/README.md(common in this org's repos: "read the zone's own rules before touching it"), read that too
If no rule file exists, say so plainly in the final report instead of inventing rules from memory of other repositories.
Step 3 — Cross-check the diff against the rules
For each changed area, check against what Step 2 turned up. These are recurring failure classes worth specifically looking for, not an exhaustive checklist:
- Scope creep: does the diff touch files outside what the title/body claims?
- Cross-repo/host conventions: if the rules say "no cross-repo code sharing" or "must be host-agnostic" (not tied to one AI CLI's proprietary tools) or similar hard constraints, check the diff against them specifically
- Security: new external input (URL/path/user data) without validation; hardcoded secrets/tokens; credentials or private data landing in logs or commit history
- Test coverage: behavior changed but tests didn't; or a test exists but its assertions don't actually verify the claimed behavior ("it ran without throwing" is not verification)
- Doc sync: user-facing behavior changed but README/SKILL.md/CHANGELOG wasn't updated, where the repo has that convention
- Third-party notices: new adapted code or dependency added without the
registration the repo's rules require (e.g. a
THIRD_PARTY_NOTICES.md)
When the diff view looks suspicious, open the real file before reporting it as a finding — a unified diff shows changed lines plus a few lines of context, which easily misrepresents things like a function's full signature:
gh api repos/<owner>/<repo>/contents/<path>?ref=<headRefName> --jq '.content' | base64 -d
# or, if this repo is already cloned locally:
git show <headRefName>:<path>
Step 4 — Report with graded confidence, ranked by severity
Tag each finding by its evidence: seen (cite the diff/file line), inferred (state the reasoning), or unconfirmed (say so, and name what would confirm it). Do not let a guess read like a fact.
| Tier | Meaning | Recommended action |
|---|---|---|
| 🔴 Blocking | Violates a hard rule, security issue, clear bug | Recommend not merging; list what must change |
| 🟡 Should-fix | Not blocking but worth addressing (style, test gaps, docs) | Recommend fixing before or shortly after merge |
| 🟢 Clean | Checked, nothing found | Say which checks were run |
The final reply must lead with:
- One-line verdict: recommend merge / recommend fix-first / recommend don't-merge — first sentence, not buried in a long report.
- Findings, grouped by tier above, each with file + line where locatable.
- CI/mergeable status from Step 1 — report what was actually observed, don't re-guess it.
- Explicit handoff: "the merge decision is yours" — never follow this
report with
gh pr mergein the same turn, even if the original request pre-authorized merging; wait for the user's next message after they have seen the findings.
CI Failure Triage
Use this order:
- Identify the failing run and job.
- Read the first actionable error in the failed log.
- Classify the failure.
- Reproduce locally only if the repo has enough context and the command is safe.
- Report the exact failing command, file, or external blocker.
gh run view <run-id> --repo <owner>/<repo> --json status,conclusion,workflowName,jobs,url
gh run view <run-id> --repo <owner>/<repo> --log-failed
Common classes:
| Class | Signal | Next step |
|---|---|---|
| Compile | compiler, typecheck, or lint error | Read the first error and map to file/line |
| Test | assertion failure or failing test name | Reproduce that test locally if possible |
| Environment | missing tool, package, or cache | Check setup steps and runner image |
| Permission | Resource not accessible or denied secret |
Check workflow permissions and fork context |
| Quota/timeout | quota message or cancelled after timeout | Report external limit or split work |
Release Operations
Release creation is a publish action. Prepare the command, show the tag/name/body summary, and ask for explicit confirmation before running:
gh release create <tag> --repo <owner>/<repo> \
--title "<release title>" \
--notes-file <notes-file>
After release, verify:
gh release view <tag> --repo <owner>/<repo> \
--json tagName,name,isDraft,isPrerelease,publishedAt,url
Collaborator Access Management
Use for: "Give <user> in <repo> permission to submit PRs" / "Add xxx to this repository" /
"See which collaborators this repository currently has" / "Remove xxx from this repository".
Permission levels
GitHub collaborator permissions, narrowest to broadest:
| Level | Grants | Typical fit |
|---|---|---|
pull |
Read-only; can fork and open cross-fork PRs | External contributor on a private repo — on a public repo, anyone can already fork and PR without being added at all |
triage |
pull + manage issue/PR labels and assignees, no code writes |
Triage-only, no code access |
push |
triage + push branches, open PRs from branches in the repo itself |
What "permission to submit PRs" usually means |
maintain |
push + manage some repo settings (not sensitive ones, not collaborators) |
Needs to manage issue templates/wiki, not full admin |
admin |
Full control: delete repo, manage collaborators, manage secrets | Rare; treat as a distinct, higher-bar request |
Default rule: when the user says "add permission to submit PRs" without naming a
level, confirm whether the person is an internal collaborator (→ push)
or an external contributor (→ usually no grant needed on a public repo;
on a private repo, pull or triage is enough to see the repo and open
PRs against it — push is more than they need). Do not default to push
without asking when it's ambiguous which case this is. Never grant
maintain/admin unless the user names that level explicitly.
Commands
# List current collaborators and their permission (read-only, always safe)
gh api repos/<owner>/<repo>/collaborators \
--jq '.[] | {login: .login, permission: .role_name}'
# Look up one person's current permission (read-only)
gh api repos/<owner>/<repo>/collaborators/<username>/permission \
--jq '{permission: .permission, role_name: .role_name}'
# Grant or change a collaborator's permission (write — see Safety Gate below)
gh api repos/<owner>/<repo>/collaborators/<username> \
-X PUT -f permission=<pull|triage|push|maintain|admin>
# Remove a collaborator (write — same Safety Gate)
gh api repos/<owner>/<repo>/collaborators/<username> -X DELETE
Safety Gate
This is the one operation in this skill that never runs on inferred intent — restate and get explicit confirmation on all of the following in the current exchange before the write call:
- Target repo:
<owner>/<repo> - Target user: the actual GitHub username, not a display name or email —
if you only have an email or display name, resolve the username first
(
gh api "search/users?q=<query>"— note the query goes in the URL sogh apistays a GET; passing it via-fwould switch the call to a POST and fail — or ask the user) rather than guessing the spelling - Permission level:
pull/triage/push/maintain/admin - If revoking: confirm this removes their direct collaborator access — it does not close their open PRs/branches (this skill does not cascade that cleanup), and it does not touch access granted through org Team membership, which is a separate permission path this call cannot revoke
Inviting someone to a private repo sends them a GitHub notification/email — an externally visible action — so the confirmation gate applies even when it feels like "just adding one person."
Verify after granting
gh api repos/<owner>/<repo>/collaborators/<username>/permission \
--jq '.permission'
Confirm the returned value matches what was requested before reporting
success. Do not treat a 2xx response alone as proof the grant took effect:
GitHub's collaborator-add endpoint returns 201 when it creates a pending
invitation (not in effect until the person accepts) versus 204 when it
updates an existing collaborator (in effect immediately) — for a 201, say
explicitly in the report that access is pending acceptance, not yet active.
Verify after revoking
gh api repos/<owner>/<repo>/collaborators/<username> --silent && echo "still a direct collaborator" || echo "removed as direct collaborator"
A successful DELETE (2xx) only means direct-collaborator access is gone —
it is not proof the person has no access at all. If <owner> is an org (not
a personal account), check whether a Team grants them access independently
before reporting "access revoked" as a complete statement:
gh api orgs/<owner>/teams --jq '.[].slug' \
| xargs -I{} gh api orgs/<owner>/teams/{}/repos/<owner>/<repo> --silent 2>/dev/null \
&& echo "a team still grants access to this repo — check its membership"
If any Team still has access to the repo, report both facts separately: direct-collaborator access removed, Team-based access (if applicable) unchanged — do not collapse them into one "access revoked" claim.
Output Checklist
Before final response:
- State the resolved repo and how it was resolved.
- Separate facts from inference when summarizing failures.
- Include exact PR/issue/run/release identifiers.
- For mutating operations, say what changed and include the resulting URL or id.
- For blocked auth or permission, say which
ghcommand failed and what the user must configure.