From cloudup
Use when you have a screenshot or generated image you need to share via URL — in a PR comment, GitHub issue reply, or chat response. Works whether the image is on local disk, pasted into the conversation, or returned from another tool as an MCP image block. Typically triggered after Playwright UI verification or when the user pastes a screenshot.
How this skill is triggered — by the user, by Claude, or both
Slash command
/cloudup:uploading-to-cloudupThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You have access to a Cloudup MCP server that uploads images and returns a public share URL. Use this when you have an image — on disk, pasted into the conversation, or returned from another tool — and need to reference it in markdown that consumers will render: pull request comments, issue replies, chat responses.
You have access to a Cloudup MCP server that uploads images and returns a public share URL. Use this when you have an image — on disk, pasted into the conversation, or returned from another tool — and need to reference it in markdown that consumers will render: pull request comments, issue replies, chat responses.
The server is registered under the plugin-namespaced name plugin:cloudup:cloudup (Claude Code prefixes plugin-installed MCP servers with plugin:<plugin-name>:). When tooling asks for a server argument (e.g. ListMcpResourcesTool), pass that full name, not the bare cloudup.
The server exposes three upload paths. Pick by where the image already lives, then (for on-disk images) by size:
| Where's the image? | Path |
|---|---|
Already in the conversation (pasted screenshot, MCP image block from another tool, or a data: URL) | Path 0 |
| On disk, small (under ~60 KB binary / ~80 KB base64) | Path A |
| On disk, larger | Path B |
Never re-encode an in-conversation image to disk just to fit Path A — that doubles your context cost. Use Path 0.
upload_image with image or image_data_url)Use when an image already exists in your context: the user pasted a screenshot into chat, a Playwright/screenshot tool returned an MCP image content block, or you have a data:image/...;base64,... URL. Avoids round-tripping the bytes through disk.
image content block — shape {type: "image", data: "<base64>", mimeType: "image/png"} (annotations may also be present and is fine to pass through).data:image/...;base64,... URL string.mcp__plugin_cloudup_cloudup__upload_image with one of:
image: <the content block, verbatim> — when you have an MCP image block.image_data_url: "<the data URL string>" — when you have a data URL.alt if you want explicit alt text; otherwise the server derives it from the filename (defaults to screenshot-YYYYMMDDHHMMSS.<ext> here).direct_url, markdown, content_type, size_bytes, sku, expires_at.Do not pass content_base64 alongside image or image_data_url — exactly one input mode is allowed per call. The server sniffs the actual MIME from the decoded bytes regardless of what mimeType or the data URL claims, so non-image content gets rejected with invalid_request.
upload_image / quick_upload (inline base64)Use when the file is on disk and small enough that you can read it without hitting your tooling's read limits. As a rule of thumb in Claude Code: under ~60 KB binary (~80 KB base64) is safely Read-able. Above that, switch to Path B.
/tmp/screenshot.png).plugin:cloudup:cloudup MCP server. The runtime exposes tools using the namespace-normalized form: typically mcp__plugin_cloudup_cloudup__upload_image (colons replaced with underscores). If that exact name isn't surfaced, discover the right one from the available tools list — look for an upload_image or quick_upload tool under the cloudup-prefixed server. For non-image files, use quick_upload on the same server. quick_upload accepts the same three input modes as upload_image (content_base64, an MCP image content block, or an image_data_url), so it works equivalently for inline payloads when you want the cheaper / shorter-retention quick SKU.direct_url (the hotlink), markdown (ready-to-paste GH-flavored markdown), content_type, size_bytes, sku, and expires_at.begin_upload + S3 PUT + complete_upload (presigned S3)Use this for anything Path A can't swallow whole. Critically: never degrade the image to fit Path A — don't compress, downscale, or convert to lossy JPEG just to squeeze under the Read limit. The bytes never pass through your context on Path B, so the Read limit doesn't apply.
stat -f%z <path> (macOS) or stat -c%s <path> (Linux) to get the exact byte size.begin_upload with filename, mime, size_bytes. It returns s3_url, upload_id, and put_example (a curl one-liner). Note: this SKU (large) is more expensive than upload_image ($0.25 vs $0.05) — the plugin's default CLOUDUP_MAX_USD of $0.30 covers it, but if you've lowered the cap the call will fail with mpp-remote: charge … exceeds MPP_MAX_AMOUNT_USD=….s3_url from the shell — curl -X PUT --data-binary @<path> -H "Content-Type: <mime>" "<s3_url>". The bytes go straight from disk to S3, never through your context.complete_upload with the upload_id returned in step 2. It returns the same response shape as Path A (direct_url, markdown, etc.).If the PUT fails or you stall past the presign TTL, call begin_upload again — don't try to reuse the expired URL.
markdown field verbatim into your response. To customize alt text on Path A, pass an alt argument (stripped of [/], capped at 200 chars); otherwise it's derived from the filename stem. Path B doesn't accept an alt argument — edit the returned markdown if you need different alt text.expires_at: the embed SKU (used by upload_image) retains files for 2 years (730 days), so PR-comment embeds stay valid long term; the quick and large SKUs retain for 30 days. After expiry the embed turns into a broken-image icon with no in-band explanation.Each upload is paid for by the user's wallet, provisioned via /cloudup-setup (stored in macOS Keychain) or as a back-compat fallback the CLOUDUP_WALLET_KEY env var. The default cap is $0.30 per call (CLOUDUP_MAX_USD) — covers all three SKUs: embed (upload_image, $0.05), quick (quick_upload, $0.01), and large (begin_upload, $0.25).
If the upload fails:
/cloudup-setup (or set CLOUDUP_WALLET_KEY for the older path) and restart Claude Code./cloudup-setup.CLOUDUP_MAX_USD if appropriate.Never silently retry failed uploads — each retry potentially costs money.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub stevendufresne/cloudup-plugin --plugin cloudup