Gh comment image upload
Use when you need to put a local image or screenshot into a GitHub PR or issue comment automatically, with no human drag-drop — especially in a PRIVATE repo, where token-based user-attachments upload fails (422 anti-forgery) and committing to a branch pollutes the diff or triggers CI/Vercel builds. Triggers "attach screenshot to the PR", "embed image in PR comment", "put the image in the comment".From its SKILL.md
npx -y skills add AppLoidx/gh-comment-image-uploadAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 1 stars1 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.
- runs commandsInstructs the agent to run 8 commands, including `gh repo view --json nameWithOwner --jq .nameWithOwner` and 7 more.
SKILL.md
4.7 KB, ~1.2k tokens by cl100k_base, as published. Nobody here has run it
Embedding images in GitHub comments
Put a local image into a GitHub PR/issue comment with only a token — no browser, no human drag-drop, no diff pollution, no CI/Vercel build. Works in private repos.
Core trick
Host the image as a parentless commit on a non-branch ref, embed it by commit SHA:
- A ref outside
refs/heads/*andrefs/tags/*is not a branch or tag → invisible in the branches UI and ignored by CI/Vercel webhooks (they fire only on heads/tags). - GitHub serves first-party
…/blob/<sha>/file?raw=trueimages straight to the viewer's authenticated browser → renders for repo members, 403 for outsiders (inherits repo visibility). - A normal
git clone/pullnever downloads it: the default refspec isrefs/heads/*, and the objects are unreachable from any branch, so they add 0 bytes to a clone (only server-side).
Run from inside a clone of the TARGET repo. git hash-object -w writes to this clone's object
DB and git push origin pushes to its remote — so the clone's origin must be the repo the PR
lives in (gh repo view --json nameWithOwner to confirm), and you need push access. A worktree
works (objects/push resolve to the shared repo). GitHub-specific (custom-namespace ref push).
OWNER_REPO=$(gh repo view --json nameWithOwner --jq .nameWithOwner) # confirm it's the PR's repo
REF=refs/preview-shots/pr<pr>-shot # NON-branch, NON-tag; make <...> unique so runs don't clobber
# 1. Build a parentless commit holding the image(s) — pure plumbing, no checkout / worktree change
b=$(git hash-object -w shot.png)
tree=$(printf '100644 blob %s\tshot.png\n' "$b" | git mktree)
commit=$(git commit-tree "$tree" -m "screenshots")
# Multiple files: add more `100644 blob <sha>\tname.png\n` lines into mktree.
# 2. Push to the NON-branch ref (NOT refs/heads, NOT refs/tags) — keeps objects alive, fires no CI
git push origin "$commit:$REF"
# 3. Object alive? (token works — this is liveness, NOT the render check below)
gh api "repos/$OWNER_REPO/contents/shot.png?ref=$commit" --jq .size
# 4. Embed by SHA. HTML <img> lets you size / lay out side-by-side;  also works.
# <img src="https://github.com/$OWNER_REPO/blob/$commit/shot.png?raw=true" width="360" />
gh pr comment <pr> --repo "$OWNER_REPO" --body "$(cat body.md)"
# edit an existing comment by id:
# gh api -X PATCH /repos/$OWNER_REPO/issues/comments/<id> -f body="$(cat body.md)"
# Cleanup (drops ref → objects GC'd later): git push origin ":$REF"
Two distinct checks — don't conflate
- Object liveness (token works):
gh api repos/$OWNER_REPO/contents/shot.png?ref=$commit— confirms the push landed and the SHA resolves. Use this to debug "did it upload". - Rendered markdown (needs a member's browser): a token CANNOT read rendered private markdown.
Post the embed and have a repo member confirm in their browser — a one-time blessing of the
technique, not per-image human work. A
curl -H "Authorization: token <PAT>"on the raw URL returns 404: a PAT-vs-session-cookie artifact, NOT a render failure. Ignore it.
Don't
| Tempting | Why not |
|---|---|
Upload to user-attachments (POST github.com/upload/policies/assets) with a PAT | Needs a browser session cookie + CSRF → PAT gets an anti-forgery error page (422). No gh/REST equivalent exists. |
gh-image or any cookie-scraping extension | Reads your browser session cookie = full GitHub auth. Unverified third-party code + credential access = account-takeover/supply-chain risk. Decline. |
Commit to a refs/heads/* branch | CI/Vercel builds every branch push and it clutters the branch list. The non-branch ref avoids both. |
| External public host (imgur, public S3) | Camo renders it, but the image becomes public — leaks anything sensitive (balances, PII). |
Notes
- If the repo's CI does NOT build arbitrary branches and a visible branch is acceptable, a plain
orphan branch +
blob/<branch>/file?raw=truealso renders. The non-branch ref is what makes it invisible to CI and the branch list — prefer it when either matters. - Vercel fallback if you must use branches:
vercel.jsongit.deploymentEnabledminimatch glob{"<prefix>/*": false}on the production branch tells Vercel to skip those branches.
What ships with it: 2 files
3.3 KB alongside SKILL.md