gallery_create
Create gallery
Create a public ordered media gallery in the workspace. The returned canonical URL is safe to give users, but anyone who knows it can view the gallery and its media.
titlerequiredworkspacedescriptionsh.uploadsPublished by uploads.shOfficial publisherv0.62.1Updated Nov 5, 2026
Host files from coding agents; stage on a branch and attach to GitHub PRs.
uploads.sh hosts agent-produced files at stable public URLs, stages them on a branch and syncs them into one managed GitHub PR or issue comment.
Web executable via Streamable HTTP. Remote servers run from the web runtime once configured in a workspace.
Paste this prompt into Claude Code, Codex, Cursor or another agent — or into SourceWeft chat. The agent reads this server's install guide, shows you its publisher, endpoint and sign-in, and adds it to your client once you agree. Keys never go into a command.
Read https://sourceweft.com/mcp/sh.uploads%2Fmcp/install.md and connect the MCP server it describes to my client. Before changing any config, show me its publisher, endpoint and sign-in method and wait for my OK. Never put an API key in a command or in a file I would commit; ask me where it should come from.Add this to your client's mcpServers config. The client completes OAuth sign-in on first connect.
{
"mcpServers": {
"uploads-sh": {
"type": "http",
"url": "https://agents.uploads.sh/mcp"
}
}
}The missing upload command for coding agents.
Capture screenshots, recordings, and other artifacts as you work: test reports, logs, JSON, PDFs, zips. When the pull request opens, uploads.sh puts them in one tidy comment that updates automatically on each revision. Hosted uploads.sh is free to start. Connect your own bucket — Cloudflare R2 or any S3-compatible provider — so storage in that bucket is unmetered, or self-host the open-source service.
uploads.sh · Docs · npm → · Quick start · What it looks like · Screenshots in CI · What's in this repo · Develop
[skills.sh] [CI] [npm (CLI)] [MCP server] [GitHub App: uploads-sh] [Ask DeepWiki] [License: Apache 2.0]
Under active development. uploads.sh is being built in the open, so APIs can still change. Feedback is welcome — open an issue.
uploads hosts the artifacts coding agents produce at stable public URLs
they can use in pull requests and issues: screenshots and screen recordings,
but also test reports, logs, JSON, CSV, Markdown, PDFs, and zip archives
(the full list is under Plans & limits). On
a branch, uploads put stages each file as soon as it is ready. When the pull
request opens, uploads.sh promotes the staged files into one managed comment.
GitHub's own attachments work from a browser and, since GitHub CLI 2.99
(September 2026), from gh … --attach, but only once a pull request or issue
exists, and the files stay behind GitHub's own hosting, where they cannot be
embedded or fetched anywhere else. uploads.sh gives agents a stable
public URL from the same terminal where they build and test the change, while
the branch is still in progress; GitHub has no public API (yet) for that. The
hosted MCP server does the same for agents that cannot run a command at all,
taking files as bytes or a URL.
Keys are hash-free, so re-uploading the same filename overwrites in place and the URL never changes — every embed of it updates at once. Workspaces keep tenants (and their budgets and key policies) apart.
This repo is the source of the canonical deployment at
uploads.sh: the API worker, auth worker, MCP server, the
hosted read-gate Worker, the Astro web app, and the @buildinternet/uploads
CLI (published to npm from packages/uploads).
One comment per PR, rewritten in place on every sync. Files tagged
--state before and --state after pair into a side-by-side table; other
images and video land below it, and non-media files (reports, logs, archives)
list in a file table with their type and size.
The real comment on #436.
Pairing is by --meta path=… when several pairs share a comment (one before
and one after per path), and falls back to filenames that differ only by a
before/after token — hero-before.webp with hero-after.webp.
Everything you attach also lands in your workspace, grouped by where it came
from — pages by path, projects by repo or app — and browsable from one
place.
The screenshots view groups uploads by project and path.
Open any file for a share page: copy-ready embeds (Markdown, HTML, and more), the raw URL, and a delete button.
Each file's share page — copy-ready embeds, details, and delete.
Install the CLI and sign in once:
Upload a file and tag the page it shows:
On a branch, put stages the file automatically. Open the pull request however
you normally would. The GitHub App
promotes the staged files into one managed attachments comment.
Use the same commands for before-and-after evidence, an open pull request, a browser capture, or an annotated image:
attach detects the repository and current PR through gh, uploads all files,
and creates or updates that same one comment. On an issue it also keeps a
Markdown issue artifact (and a gallery link, when there is one) unless the
workspace or the repo turns that off. Without the GitHub App, run
uploads attach --promote after opening the pull request to promote files that
you staged earlier. All commands run under npx @buildinternet/uploads …
without a global install.
Sign in with GitHub or a magic link, then create your own workspace or accept an invite into one — see enrollment. Hosted files are public URLs — private-repo attachments get non-guessable links (how that works), but anyone holding a URL can view the file. A file that looks like it shows a credential, ID, or card number is held for your review before it goes public, but don't rely on that: do not upload secrets or sensitive UI.
The GitHub App adds an uploads.sh check to pull requests that change UI
files, next to your tests and builds. No workflow or Actions step is needed.
Out of the box it only reports, so nobody is blocked. Turn on Require
screenshots on UI changes in the workspace's Settings → GitHub, or set it
for one repo in .uploads.yml, and the check fails until screenshots arrive:
The PR comment shows a checklist that ticks itself as files arrive. Images
dragged into the PR on GitHub count too, so contributors without uploads.sh are
never stuck, and a skip-uploads label skips a PR that needs no screenshots.
Add uploads.sh as a required status check in branch protection to make it
block merges. Setup, which files count as UI, and skip labels are in
Require screenshots on pull requests.
The hosted MCP server runs at https://agents.uploads.sh/mcp and is listed in the
MCP Registry
as sh.uploads/mcp. Local stdio is uploads mcp on the same npm package.
uploads install adds the agent skills and the MCP server, so future sessions
can capture each visual milestone without being asked. The skills also install
standalone into any agent runtime:
That installs three skills: github-screenshots (visuals → PRs/issues),
uploads-cli (full CLI reference), and annotate-screenshots (callouts and
redaction on a capture).
On Claude Code or Codex, the plugin
bundles the skills, the MCP server, and a pre-PR screenshot reminder. In
Claude Code it also shows staged screenshots above the prompt and attaches
them when the PR opens. On claude.ai and in Cowork, add uploads from the
Claude directory. The same folder
(plugins/claude/uploads) is the common agent-plugin layout, and it is
submitted to the xAI plugin marketplace
as uploads.
Full CLI usage, including annotations, managed comments, public galleries, and change feeds (repo-wide or one pull request), lives in docs/cli.md.
uploads feed create prints a live page of the screenshots on a repo:
uploads feed create --repo buildinternet/uploads.
REST routes are in docs/api.md.
Each worker and the web app deploy separately. All storage access goes through
createStorage() in packages/storage — adding a provider is one new case
plus peer deps, no API changes.
Hosted file bytes stay on the shared uploads-default bucket.
store.uploads.sh, storage.uploads.sh, and embed.uploads.sh are served
through uploads-read-gate (apps/read-gate). A held image gets a "Held
for review" card. Any other safety hold is a 404. Every other request
passes through to R2. It does not gate private files, and it does not run
for a bring-your-own bucket. Operator notes are in
docs/ops.md.
Product docs — install, the staged loop, the GitHub App, limits — live at https://uploads.sh/docs. The docs in this repo are the companion: CLI and API reference, contributor setup, and operator material, all mapped from docs/README.md.
How to set up, test, and open a pull request: CONTRIBUTING.md. Where the project is headed: VISION.md. Agent working conventions live in AGENTS.md, and agents that land on this repo should start at llms.txt. The product site serves https://uploads.sh/llms.txt and https://uploads.sh/llms-full.txt.
Prerequisites: Node ≥24 and pnpm ≥11 (corepack enable). No Cloudflare
account needed for the core local loop — wrangler dev simulates R2, KV, and
D1 on disk:
bootstrap is idempotent, and pnpm doctor diagnoses a setup without changing
it. The rest of the loop — the authenticated dev stack, the check and test
gates, and how to open a pull request — is in
CONTRIBUTING.md.
Source: README.md at commit 4663b60
Create gallery
Create a public ordered media gallery in the workspace. The returned canonical URL is safe to give users, but anyone who knows it can view the gallery and its media.
titlerequiredworkspacedescriptionGet gallery
Get a workspace-owned gallery, including ordered media and its canonical public URL. Gallery media is public to anyone with the URL.
galleryIdrequiredworkspaceAdd gallery item
Add one existing, publicly served workspace object to a gallery. Reads the latest gallery version before writing, so the optimistic API version is handled safely. Does not upload or delete the object.
altTextcaptiongalleryIdrequiredobjectKeyrequiredworkspaceLink gallery
Link a gallery to an external reference. References use provider-neutral fields; github currently accepts owner/repo#number or a strict GitHub issue/PR URL. No GitHub credentials or API calls are used.
providerrequiredgalleryIdrequiredworkspacecoordinaterequiredFind galleries
Find workspace galleries linked to an external reference. Returns gallery summaries and canonical public URLs without contacting the provider.
limitcursorproviderrequiredworkspacecoordinaterequiredCreate change feed
Create a public newest-first screenshot feed (same product as CLI `uploads feed create`). Pass `repo` alone for the whole GitHub repo. Pass `pr` plus `repo` — or `github` as owner/repo#123 / a GitHub PR URL — to scope that same feed to one pull request. `issue` does the same for an issue. Optional `path` filters by page-path metadata. Creating the same scope again returns the existing URL. This is a live query, not a curated gallery. Anyone who knows the URL can view it. See https://uploads.sh/docs/feeds.
prpathrepoissuegithubworkspaceGet change feed
Get a workspace-owned change feed by ID, including its current newest-first screenshots and the canonical public /c/<id> URL. Each item includes pageUrl (`/c/<id>/<item>`) for the pager. The feed may be repo-wide or scoped to one pull request / issue (see `number` and `kind` on the result). Anyone with the URL can view the media.
feedIdrequiredworkspaceUpload file
Upload one or more files and get a public URL plus GitHub-ready markdown. Prefer `embedUrl` in GitHub markdown. Pass `contentUrl` for a public HTTPS file, or http://localhost on this machine, instead of a local path. With `pr`/`issue`, keys are stable and the managed comment is synced. `holdCheck: pending` means the classifier may still hold the file for review (it decides after the upload); `comment.held` counts files on the PR or issue held for review; see `list_held`. All uploads are public. Accepts images (PNG, JPEG, GIF, WebP, AVIF), video (MP4, WebM, MOV), PDF, zip, gzip, and text (plain, markdown, CSV, JSON). SVG and XML are accepted only on storage lanes verified to serve them sandboxed (see the workspace's storage settings); HTML is rejected.
praltappkeyreffilenoPrrepofilesframeissuenoGit+21 moreCapture screenshot
Capture a URL or local HTML file and host it. Shares put's attach, comment, and metadata options. `via=local` needs Chrome; `via=remote` renders server-side. localhost URLs are local-only.
praltappcdpkeyrefviahidenoPrrepowaitframe+29 moreAttach to GitHub
Upload one or more files as stable PR/issue attachments (in parallel) and maintain a managed GitHub comment. Returns `uploads` and `failures` (one bad file does not abort the batch). Each success has `url`, `embedUrl`, and `markdown` (prefer embedUrl for GitHub). With no pr/issue, targets the current branch PR, and files already staged for that branch are promoted into it (`promotion`/`promoteError`; renamed branches are followed automatically, or name the old branch with fromBranch). Attachments are public and keys are predictable; upload only non-sensitive media. On an issue, a Markdown artifact (and a gallery link, when there is a gallery) stays in sync with the comment unless `issueArtifacts` is false, the repo sets `comment.issueArtifacts: false`, or the workspace turns it off. Images stay on uploads.sh URLs. Pull requests are unchanged. An artifact failure is a warning and does not fail the attach.
prapprepofilesrequiredframeissuestatescreencaptionframeFitframeUrlkeepExif+10 moreList files
List uploaded objects in the workspace, filtered by key prefix or by a PR/issue's attachments. Paginate with cursor, or set all to fetch every page.
prallrepoissuelimitcursorprefixworkspaceList staged files
List files staged for a git branch and whether they will auto-attach when a PR opens. Returns `{ repo, branch, files, binding }`.
repobranchworkspaceUnstage files
Clear staged files for a branch, or specific keys, without deleting them. Sets gh.status=unstaged so they drop out of uploads staged and auto-promotion. Pass branch (repo inferred) or keys, not both. Needs files:write.
keysrepobranchdryRunworkspaceDelete file
Permanently delete one uploaded file by key, along with its metadata. Set dryRun to preview without deleting.
keyrequireddryRunworkspaceGet metadata
Read the queryable tags on one file. Returns `{ metadata }` (empty when none). Same as `uploads meta get`.
keyrequiredworkspaceList held files
List uploads held for review. The classifier holds a file it thinks shows a secret (an API key, a password, a token) or sensitive personal data (an ID, a card number). A held file stays out of the managed PR comment, feeds, and galleries until a workspace member approves it with `approve`. A signed-in member sees the real file on its /f/ page. On hosted storage an image URL returns a Held for review card, and any other raw URL returns 404. Pass `pr`/`issue` for one PR or issue, or `prefix`. Each item has a `reason` such as `secret: api_key`, and `sha`, the content hash of those bytes. `approve` sends that hash. Same as `uploads approve --pr <n>`.
prrepoissueprefixworkspaceApprove held files
Release uploads held for review (see `list_held`): pass `keys`, or `pr`/`issue` to approve every held file there. The file returns at the same URL and the managed PR comment re-syncs. Check the file first: if it shows a real credential, rotate it and delete the file instead of approving. Same as `uploads approve`.
prkeysrepoissueworkspaceSet metadata
Set or delete queryable tags on an existing file. `set` wins over `delete` for the same key. Requires `set` and/or `delete`. Same as `uploads meta set`.
keyrequiredsetdeleteworkspaceFind files
Search files by metadata (`filters`) and/or filename substring (`name`). At least one is required. Same as `uploads find`.
allnamelimitcursorprefixfiltersworkspaceList metadata keys
List metadata keys in the workspace (with counts). Pass `key` to list that key's values instead. Use before `find_files`. Same as `uploads meta keys`.
keyworkspaceShow usage
Workspace storage and monthly upload counters (and remaining headroom when budgets are configured). Same as `uploads usage`.
workspaceReconcile usage
Rebuild usage ledger bytes/objects from storage (source of truth). Preserves the monthly upload counter. Requires files:write. Same as `uploads reconcile`.
workspacePurge expired files
Delete objects older than the workspace retentionDays setting, then reconcile. Skips if retention is unset. Requires files:delete. Same as `uploads purge-expired`.
workspaceSync attachments comment
Create or update the managed attachments comment on a GitHub PR or issue, listing everything uploaded for it. Posts as uploads-sh[bot] when the GitHub App is installed on the repo; otherwise via local gh auth. Edits its own prior comment in place and never touches other comments. `held` counts files there held for review; see `list_held`.
prrepoissueworkspaceSearch uploads.sh docs
Search the public uploads.sh documentation. Use this to answer questions about uploads.sh product workflows, including: attaching screenshots and video to GitHub PRs and issues; staging files before a PR exists; galleries; the GitHub App; comment config (.uploads.yml); hosted MCP and agent setup; screenshot capture and annotate; plans and limits; bring-your-own bucket. Same as `uploads docs`. Returns titles, URLs, and snippets. Pass `page` to fetch the full markdown of one page (slug, path, or URL). Omit `query` to list the catalog.
pagelimitqueryProduct changelog
Read recent uploads.sh product updates (platform and CLI). Returns the latest entries with titles, dates, summaries, and a link to the full changelog at https://uploads.sh/changelog. Same as `uploads changelog`.
limitWho am I
Show the active uploads.sh identity: workspace, API URL, and token scopes. Use this to learn which workspace you're talking to. A successful result also means the API is up. For a full setup diagnosis, use `doctor`.
Takes no parameters.
Diagnose setup
Diagnose the configuration: API health, token auth, and workspace/token alignment. Returns the same report as `uploads doctor --json`, including hints.
workspaceSend diagnostic report
Send an explicit diagnostic report to the uploads team (message + optional text log). Only call this when the user asked to submit feedback, a bug report, or error logs — never automatically. Do not include tokens, secrets, or private file contents. Same as `uploads report`.
typecommandcontactmessagerequirederrorCodeattachmentTextattachmentFilename100% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
npm install --global @buildinternet/uploadsuploads loginuploads put ./settings.png --meta path=/settings# Pair two states from the same page in the pull request comment.uploads put ./before.png --meta path=/settings --state beforeuploads put ./after.png --meta path=/settings --state after
# See what this branch will attach when the pull request opens.uploads staged
# Attach files directly when a pull request or issue is already open.uploads attach ./before.png ./after.png
# Capture, annotate, and upload a page in one command.uploads screenshot http://localhost:4321/settings --via local --annotate ./callouts.jsoncomment: check: require: [before-after, desktop, mobile] # or just [uploads]# Claude Codeclaude mcp add --transport http uploads https://agents.uploads.sh/mcp
# Codexcodex mcp add uploads --url https://agents.uploads.sh/mcp
# OpenCodeopencode mcp add uploads --url https://agents.uploads.sh/mcpnpx skills add buildinternet/uploadspnpm bootstrap # one-command setup: tooling, deps, env vars, local D1, default workspacepnpm dev # API on :8787 (local R2 + KV + D1)