From gh-pr-image
Upload local images to a GitHub PR description or comment without committing them to the repo. Use when creating PRs that need before/after screenshots, visual diffs, or any embedded images.
How this skill is triggered — by the user, by Claude, or both
Slash command
/gh-pr-image:gh-pr-imageThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Upload local images (screenshots, diagrams, visual diffs) to a GitHub PR description without committing them to the repository. Uses GitHub release assets as a CDN — the only fully scriptable, CLI-only approach that works for private repos.
Upload local images (screenshots, diagrams, visual diffs) to a GitHub PR description without committing them to the repository. Uses GitHub release assets as a CDN — the only fully scriptable, CLI-only approach that works for private repos.
GitHub has no public API for uploading images to PR descriptions. The drag-and-drop upload in the web UI uses an undocumented endpoint (/upload/policies/assets) that requires browser session cookies — it cannot be called with an API token.
The available workarounds and their trade-offs:
| Approach | Works from CLI? | Private repos? | Downsides |
|---|---|---|---|
| Commit images to repo | Yes | Yes | Bloats the repo, images live forever in git history |
| Drag-and-drop on web | No | Yes | Manual, breaks CLI workflow |
| External host (S3, imgur) | Yes | N/A | Requires separate service, images may expire |
| Browser automation (gh-attach) | Partially | Yes | Requires Playwright + browser login session |
| Release assets (this skill) | Yes | Yes | Creates a prerelease tag in the repo |
browser_download_url for each assetRelease asset URLs are accessible to anyone with repo read access, making them work correctly in private repo PR descriptions.
# Variables
REPO="owner/repo" # or auto-detect from current directory
PR_NUMBER=137
TAG="pr-${PR_NUMBER}-images" # one tag per PR keeps things organized
# 1. Create prerelease with images attached
gh release create "$TAG" \
/tmp/before.png /tmp/after.png \
--repo "$REPO" \
--title "PR #${PR_NUMBER} screenshots" \
--notes "Image assets for PR #${PR_NUMBER}." \
--prerelease
# 2. Get the asset URLs
BEFORE_URL=$(gh api "repos/$REPO/releases/tags/$TAG" \
--jq '.assets[] | select(.name=="before.png") | .browser_download_url')
AFTER_URL=$(gh api "repos/$REPO/releases/tags/$TAG" \
--jq '.assets[] | select(.name=="after.png") | .browser_download_url')
# 3. Use in PR body
gh pr edit "$PR_NUMBER" --body "$(cat <<EOF
## Summary
Description here.
## Before

## After

EOF
)"
REPO="owner/repo"
TAG="pr-assets-$(date +%Y%m%d%H%M%S)"
FILE=/tmp/screenshot.png
gh release create "$TAG" "$FILE" \
--repo "$REPO" \
--title "PR screenshots" \
--notes "Image hosting for PRs." \
--prerelease
URL=$(gh api "repos/$REPO/releases/tags/$TAG" \
--jq ".assets[0].browser_download_url")
echo ""
If you want to reuse a single release as a persistent image store:
TAG="pr-assets"
# First time: create the release
gh release create "$TAG" \
--repo "$REPO" \
--title "PR image assets" \
--notes "Persistent image hosting for PR descriptions." \
--prerelease
# Subsequent uploads: add to existing release
gh release upload "$TAG" /tmp/new-screenshot.png --repo "$REPO"
URL=$(gh api "repos/$REPO/releases/tags/$TAG" \
--jq '.assets[] | select(.name=="new-screenshot.png") | .browser_download_url')
Prerelease tags can be cleaned up after PRs are merged:
# Delete a specific PR's image release
gh release delete "pr-137-images" --yes --cleanup-tag
# List all image releases
gh release list | grep "pr-.*-images"
gh CLI, authenticated (gh auth status)--prerelease so image-hosting releases don't appear as real releasespr-137-images) for easy cleanupGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.
Dispatches multiple subagents concurrently for independent tasks without shared state. Use when facing 2+ unrelated failures or subsystems that can be investigated in parallel.
npx claudepluginhub mrshu/agent-skills --plugin gh-pr-image