| name | gh-safe |
| description | Use this skill whenever you are about to run any write `gh` CLI command — `gh pr edit`, `gh pr create`, `gh issue edit`, `gh issue create`, `gh pr comment`, `gh issue comment`, `gh pr close`, `gh pr merge`, `gh release create`, or similar. High-level `gh` commands sometimes fail with "missing required scopes" auth errors even though the underlying GitHub REST API works fine with the same token. This skill makes you automatically fall back to `gh api` instead of stopping to ask the user to re-authenticate. Always invoke before running any mutating `gh` command.
|
gh-safe: try gh first, fall back to gh api
Why this exists
gh pr edit --body "..." (and similar write commands) can fail with:
error: your authentication token is missing required scopes [read:project]
To request it, run: gh auth refresh -s read:project
The suggested gh auth refresh requires interactive browser confirmation, which
blocks automation. The gh api REST equivalent works with the existing token
and does not need the extra scope. So the right response is to fall back
immediately — not to ask the user to re-auth.
The pattern
- Run the high-level
gh command and capture stderr.
- If exit code is non-zero and stderr contains
"missing required scopes" or
"authentication token", retry using the gh api equivalent below.
- Do not prompt the user to re-authenticate or run
gh auth refresh.
if ! gh pr edit 123 --repo owner/repo --body "text" 2>/dev/null; then
gh api repos/owner/repo/pulls/123 --method PATCH --field body='text'
fi
Resolve owner/repo
When the repo is not already known, resolve it once:
REPO=$(gh repo view --json owner,name -q '"\(.owner.login)/\(.name)"')
Command → API fallback table
Pull requests
| High-level command | gh api fallback |
|---|
gh pr edit <n> --body "..." | gh api repos/{R}/pulls/<n> --method PATCH --field body='...' |
gh pr edit <n> --title "..." | gh api repos/{R}/pulls/<n> --method PATCH --field title='...' |
gh pr edit <n> --add-label "..." | gh api repos/{R}/issues/<n>/labels --method POST --field 'labels[]=...' |
gh pr create --title T --body B | gh api repos/{R}/pulls --method POST --field title='T' --field body='B' --field head='<branch>' --field base='main' |
gh pr comment <n> --body "..." | gh api repos/{R}/issues/<n>/comments --method POST --field body='...' |
gh pr close <n> | gh api repos/{R}/pulls/<n> --method PATCH --field state='closed' |
gh pr merge <n> --squash | gh api repos/{R}/pulls/<n>/merge --method PUT --field merge_method='squash' |
Issues
| High-level command | gh api fallback |
|---|
gh issue edit <n> --body "..." | gh api repos/{R}/issues/<n> --method PATCH --field body='...' |
gh issue edit <n> --title "..." | gh api repos/{R}/issues/<n> --method PATCH --field title='...' |
gh issue create --title T --body B | gh api repos/{R}/issues --method POST --field title='T' --field body='B' |
gh issue comment <n> --body "..." | gh api repos/{R}/issues/<n>/comments --method POST --field body='...' |
gh issue close <n> | gh api repos/{R}/issues/<n> --method PATCH --field state='closed' |
Releases
| High-level command | gh api fallback |
|---|
gh release create <tag> --title T --notes N | gh api repos/{R}/releases --method POST --field tag_name='<tag>' --field name='T' --field body='N' |
gh release edit <tag> --notes N | First gh api repos/{R}/releases/tags/<tag> -q .id to get the numeric ID, then gh api repos/{R}/releases/<id> --method PATCH --field body='N' |
{R} = owner/repo resolved above.
Tips