How to get agents to upload screenshots & video to GitHub
Claude Code, CI jobs, review bots, plain scripts — anything without a browser.
The problem: no drag-and-drop from a terminal
You put a screenshot on a pull request by dragging the file into the comment box. GitHub then hosts it at github.com/user-attachments/…. That only works in a signed-in browser. There is no gh command and no API for it.
So an agent that just changed your UI can't show its work. The usual workarounds all hurt:
- Committing images to the repo bloats it forever, for a screenshot that matters once.
- Random image hosts give you random URLs, expiring links, or need a browser anyway.
- A hand-rolled S3 script works — until you want stable URLs, image optimization, and comment cleanup.
The fix: host the file at a public URL the agent can create itself, then write plain Markdown. That's what uploads.sh does.
Step 1 — install the CLI and sign in (once)
uploads login trades an invite code for a workspace token and saves it. You do this once per machine. Access is invite-only for now — ask via the GitHub repo. Check your setup with uploads doctor.
Step 2 — teach your agent
One command sets up Claude Code:
- The agent skill teaches the agent when to attach screenshots — like before/after shots on a PR it just opened.
- The MCP server offers the same tools (
put,attach,list,delete, …) for runtimes that prefer MCP.
Or set up each piece yourself, for other agent runtimes:
Step 3 — the agent attaches media with one command
From a branch with an open pull request, attach only needs the files. It finds the PR through gh, uploads each file to a stable URL, and keeps one managed comment:
>> uploading ./before.png >> optimized 421337 → 96412 bytes (before.webp) >> uploading ./after.png >> optimized 407190 → 91205 bytes (after.webp) URL: https://storage.uploads.sh/gh/you/app/pull/123/before.webp MARKDOWN:  URL: https://storage.uploads.sh/gh/you/app/pull/123/after.webp MARKDOWN:  >> attachments comment updated
Not on a PR branch? Point it somewhere:
Want to place the image yourself — in a PR description or README? --no-comment prints the URL and Markdown without posting anything. uploads put gives full control over naming and output.
Why the URLs matter
Attachments get stable keys, like gh/owner/repo/pull/123/shot.webp. Upload the same filename again and the PR shows the new image at the same URL within a minute. No stale screenshots.
Video and everything else
A short screen recording is often the best proof that a change works. MP4, WebM, GIFs, zips, logs — anything uploads as-is:
One caveat: GitHub only plays videos it hosts itself. Outside video shows up as a link, not a player. GIFs embed like images.
Images are optimized by default: re-encoded to WebP, size capped, and EXIF stripped so they load fast and leak nothing. Opt out with --no-optimize or --keep-exif. Add device chrome with --frame phone|browser|iphone-16-pro.
FAQ
- Why can't my agent upload images to GitHub directly?
- GitHub's own image hosting (github.com/user-attachments) only works when you drag a file into the comment box in a signed-in browser. There is no gh command or API for it. So any image an agent puts in a comment must already live at a public URL.
- Do the image URLs change when I re-upload a screenshot?
- No. PR and issue attachments get stable keys like gh/owner/repo/pull/123/shot.webp. Upload the same filename again and every embed shows the new image within about a minute.
- Can agents upload video to GitHub pull requests?
- Yes. MP4, WebM, and other files upload as-is and get a stable public URL. GitHub only plays videos it hosts itself, so the comment links the file instead of embedding a player.
- How do I set up Claude Code to attach screenshots to its pull requests?
- Run `uploads install` once. It installs the uploads-cli agent skill and registers the hosted MCP server with Claude Code. After that, the agent runs `uploads attach <files>` on its own when it changes something visual.
- Are uploaded files private?
- No. Files are public to anyone with the URL — even media attached to private repos. Don't upload secrets or sensitive UI. Uploading itself requires an invite-issued workspace token.
Every command and flag is in the docs. Agents can read /llms.txt. If this saved you a hand-rolled upload script, a star on GitHub helps others find it.