The missing upload command for coding agents.
A lightweight file-hosting service on Cloudflare Workers. One command —
uploads attach — hosts a file at a stable public URL and keeps one tidy
attachments comment on the PR. Built on files-sdk so
the storage layer is provider-agnostic (R2 today; any files-sdk adapter later).
What is this?
You add a screenshot to GitHub by dragging it into the comment box. Agents can't — GitHub's native image hosting only works through a browser session, so an agent that just captured a before/after has nowhere to put it.
uploads gives agents that missing step: a CLI and REST API that host files
at stable, public URLs and return ready-to-paste Markdown. --pr/--issue
keys are hash-free, so re-uploading the same filename overwrites in place and
the URL never changes, and a managed attachments comment keeps every file for
a PR in one tidy place. 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
Astro web app, and the @buildinternet/uploads CLI (published to npm from
packages/uploads).
Use it
Install the CLI, sign in once, then attach media from a checked-out PR branch:
npm install --global @buildinternet/uploads
uploads login
uploads attach ./before.png ./after.png
For a one-off run without a global install:
npx @buildinternet/uploads login
npx @buildinternet/uploads attach ./before.png ./after.png
attach detects the GitHub repository and current PR through gh, uploads
all files, and creates or updates one managed attachments comment.
No PR yet? Stage files against the branch while you work — uploads attach ./shot.png --branch — and they are promoted into the PR's attachments
automatically when one opens: instantly if the
GitHub App is installed, otherwise on
your first uploads attach (or uploads attach --promote) after the PR
exists.
An uploads.sh administrator invites your email to a workspace; uploads login
opens a browser to sign in (GitHub or a magic link) and saves the resulting
workspace token — see enrollment. Hosted files are
public, including media attached to private repositories. Do not upload
secrets or sensitive UI.
Agent skills — auto-triggering playbooks, installable into any agent
runtime without checking out anything (uploads install runs these for you):
npx skills add buildinternet/uploads
That installs both: github-screenshots (visuals → PRs/issues) and
uploads-cli (full CLI reference).
Full CLI usage — key conventions, stable PR/issue attachments, managed comments, and public galleries — lives in docs/cli.md. REST routes are in docs/api.md.
What's in this repo
| Path | What |
|---|---|
apps/api/ |
Hono worker — REST API, deploys to api.uploads.sh |
apps/auth/ |
Better Auth worker — sessions, enrollment, device flow |
apps/mcp/ |
Remote MCP server |
apps/web/ |
Astro site — uploads.sh, account and admin UI |
packages/storage/ |
@uploads/storage — files-sdk adapter factory |
packages/uploads/ |
@buildinternet/uploads — CLI + client, publishes to npm |
packages/ui/ |
@uploads/ui — shared design system |
skills/github-screenshots/ |
Workflow skill — visuals into PRs/issues/share links |
skills/uploads-cli/ |
Agent skill for driving the CLI |
The workers and web app are separate deployables. All storage access goes
through createStorage() in packages/storage — adding a provider is one new
case plus peer deps, no API changes.
Docs
| Doc | Contents |
|---|---|
| cli | CLI usage, GitHub embeds, keys, galleries |
| api | REST routes |
| local-dev | Manual setup, dev stack, smoke tests |
| workspaces | Multi-tenant model, budgets, key policy, BYO-bucket |
| enrollment | Agent login, scopes, expiry, and migration |
| admin-tokens | Minting, listing, and revoking upload tokens |
| ops | Operator runbook (limits, retention, secrets) |
| deploy | Cloudflare setup and production deploy |
| contract testing | Deployed smoke checks and release gate |
| roadmap | Planned features |
Agent and contributor conventions live in AGENTS.md.
Local development
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:
pnpm bootstrap # one-command setup: tooling, deps, env vars, local D1, default workspace
pnpm doctor # diagnose the setup — reports what's missing and how to fix it
pnpm dev # API on :8787 (local R2 + KV + D1)
pnpm dev:stack # authenticated Auth + API + Web stack at 127.0.0.1:4321
pnpm check # lint + format (the CI gate)
pnpm typecheck # wrangler types + tsc across workspaces
bootstrap is idempotent (safe to re-run; never overwrites your env files or
re-mints an existing local workspace) and doctor is read-only. Manual setup
steps, the full dev-stack detail, and a curl smoke test live in
docs/local-dev.md.
License
MIT.
No comments yet
Be the first to share your take.