| name | upload-screenshot |
| description | Upload screenshots or images to GitHub and get back embeddable URLs for PR comments and issues. Use this when you have taken a screenshot, captured a UI change, or have any image file that needs to be shared in a GitHub PR or issue. |
Upload Screenshot
Upload images to GitHub via release assets and get back stable, embeddable URLs. This is the recommended way to share screenshots of frontend changes, UI diffs, or any visual artifacts in PR comments and issue descriptions.
Important: Always upload to the fork repo, not upstream, to avoid polluting upstream releases.
When to Use This Skill
Use this skill when you:
- Have taken a screenshot of a frontend/UI change and need to show it in a PR
- Need to attach visual evidence (error screenshots, UI comparisons) to a GitHub issue or PR comment
- Want to embed an image in any GitHub markdown context (PR description, comment, issue)
- Are working in an agentic workflow and need to share visual output
Prerequisites
gh CLI: Authenticated with gh auth login
- Repository write access: The
gh token must have permission to create releases on the target repo
Implementation
Upload a screenshot
bash "${CLAUDE_PLUGIN_ROOT}/skills/upload-screenshot/upload_screenshot.sh" \
--file /path/to/screenshot.png \
--repo owner/fork-repo
Upload with a custom title
bash "${CLAUDE_PLUGIN_ROOT}/skills/upload-screenshot/upload_screenshot.sh" \
--file /path/to/screenshot.png \
--repo owner/fork-repo \
--title "Login page after dark mode changes"
Parameters
| Parameter | Required | Description |
|---|
--file | Yes | Path to the image file (png, jpg, gif, svg, webp) |
--repo | No | Target GitHub repository in owner/repo format (defaults to $FORK_REPO env var) |
--title | No | Alt text for the image (defaults to filename) |
--token-file | No | Path to a file containing a GitHub token to use for auth |
When --token-file is provided, the token is loaded into GITHUB_TOKEN for the duration of the script. This is useful in CI where the default GITHUB_TOKEN may not have write access to the target repo.
Environment variable defaults: If --repo is not provided, the script uses $FORK_REPO. If no explicit token is provided via --token-file, the script uses $GH_FORK_TOKEN when available. This means in CI environments where these env vars are set, you can call the script with just --file and it will upload to the correct fork with the right credentials.
Output
JSON on stdout:
{
"url": "https://github.com/owner/fork-repo/releases/download/screenshot-1719100000-a1b2c3d4/screenshot.png",
"markdown": "",
"tag": "screenshot-1719100000-a1b2c3d4",
"repo": "owner/fork-repo"
}
Embedding in a PR comment
After uploading, use the markdown field directly in a gh pr comment:
result=$(bash "${CLAUDE_PLUGIN_ROOT}/skills/upload-screenshot/upload_screenshot.sh" \
--file /tmp/screenshot.png --repo owner/fork-repo --title "UI change")
markdown=$(echo "$result" | jq -r '.markdown')
gh pr comment 123 --repo owner/upstream-repo --body "## Screenshot
$markdown"
How It Works
- Creates a GitHub prerelease with a unique tag (
screenshot-<timestamp>-<random>)
- Attaches the image file as a release asset
- Extracts the
browser_download_url from the GitHub API
- Returns the URL in both raw and markdown-formatted forms
The release is marked as a prerelease and tagged with a screenshot- prefix for easy identification and cleanup.
Cleanup
Screenshot releases accumulate over time. To clean up old uploads:
gh release delete screenshot-1719100000-a1b2c3d4 --yes --cleanup-tag --repo owner/fork-repo
gh api "repos/owner/fork-repo/releases" --paginate --jq \
'.[] | select(.tag_name | startswith("screenshot-")) | select(.prerelease) | .tag_name' | \
while read -r tag; do
gh release delete "$tag" --yes --cleanup-tag --repo owner/fork-repo
done
Limitations
- URLs are only accessible as long as the release exists
- For private repos, viewers must have repo access to see the images
- GitHub release asset size limit is 2 GB per file
- Creates one release per upload (use cleanup to manage volume)
Error Handling
| Error | Cause | Resolution |
|---|
Missing required arguments | --file or --repo not provided | Provide both required arguments |
File not found | Image path doesn't exist | Check the file path |
Failed to create release | Auth or permission issue | Run gh auth login or check repo access |
Failed to retrieve asset URL | Release created but asset missing | Retry; the release is auto-cleaned on failure |
See Also