Upload images to GitHub (gh-image)
GitHub has no public API for image uploads — the web UI uses an internal
endpoint that mints user-attachments URLs scoped to the repo's visibility.
gh-image (MIT, © drogers0) replicates
that flow as a gh CLI extension, so you can upload from the terminal and get a
ready-to-embed  back.
This skill drives gh-image and then embeds the result into a PR/issue/comment.
Prerequisites — verify these before uploading
Run these checks; only act on the ones that fail.
ghCLI installed & authenticatedgh auth statusIf it fails, tell the user to run
gh auth login(do not attempt it unattended).The
gh-imageextension installed (idempotent — skip if already present)gh extension list | grep -q 'drogers0/gh-image' || gh extension install drogers0/gh-imageA GitHub session for the upload.
gh-imagedoes NOT use theghtoken for the upload (that endpoint rejects tokens); it needs the browseruser_sessioncookie. Resolution order (first match wins):--token <value>flag, orGH_SESSION_TOKENenv var (use this in CI / headless), or- the cookie store of a logged-in browser (Chrome/Brave/Chromium/Edge/Firefox/ Opera/Safari) — the default for local use. On macOS the first read may show a Keychain prompt; the user should click Always Allow.
⚠️ A
user_sessioncookie grants full account access (it is not scoped like a PAT). Treat it like a password; in CI use a dedicated bot account.
Step 1 — Normalize the image path
Use an absolute path. If a glob is given, resolve it first. Paths with spaces or Unicode (e.g. CleanShot's narrow spaces) work, but quote them.
Step 2 — Upload
# One or more images; --repo is optional inside a repo working dir (inferred from the remote).
gh image "/abs/path/screenshot.png" --repo <owner>/<repo>
gh image prints markdown to stdout, e.g.:

Capture that output — it is the embeddable reference. For multiple files it prints one line per image.
Step 3 — Embed into the PR / issue / comment
gh-image only prints the markdown; you embed it. Pick the target the user asked for.
Append to a PR description (preserves the existing body):
MD="$(gh image "/abs/path/shot.png" --repo owner/repo)"
BODY="$(gh pr view <pr> --repo owner/repo --json body -q .body)"
printf '%s\n\n## Screenshots\n\n%s\n' "$BODY" "$MD" \
| gh pr edit <pr> --repo owner/repo --body-file -
Post as a new PR comment:
MD="$(gh image "/abs/path/shot.png" --repo owner/repo)"
printf '## Screenshots\n\n%s\n' "$MD" | gh pr comment <pr> --repo owner/repo --body-file -
Add to an issue body / comment: same pattern with gh issue edit <n> --body-file -
or gh issue comment <n> --body-file -.
Always use --body-file - (not inline --body) so multi-line bodies and special
characters can't break shell quoting.
Step 4 — Verify
gh pr view <pr> --repo owner/repo --json body -q .body # confirm the URL is present
The user-attachments URL inherits the repo's visibility, so on a private repo
it renders only for authorized viewers (an anonymous fetch returns 404/403 — that is
expected, not a failure).
Sizing (optional)
To control display size, embed an HTML tag instead of the bare markdown:
<img width="800" alt="screenshot" src="https://github.com/user-attachments/assets/<uuid>" />
Troubleshooting
| Symptom | Cause / fix |
|---|---|
<org> enforces SAML SSO and your session is not authorized… |
The org requires SSO and your session isn't authorized. Open the https://github.com/orgs/<org>/sso URL from the message in a browser, authorize (lasts ~24h), then retry. Write access alone is not enough — this is not a permissions problem. |
uploadToken not found … do you have write access? |
The generic no-token case. Confirm you have write access; if the repo's org uses SSO, authorize at https://github.com/orgs/<org>/sso (the message includes this hint) and retry. |
No user_session cookie found |
Log into GitHub in a supported browser, or set GH_SESSION_TOKEN. |
| Windows + Chrome 127+ can't read cookies | Known cookie-library limitation — use another browser or GH_SESSION_TOKEN. |
| CI / headless run | Set GH_SESSION_TOKEN (dedicated bot account); the browser cookie path won't exist. |
gh: command not found |
Install the GitHub CLI (brew install gh, etc.). |