github-screenshots
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseScreenshots and recordings in GitHub PRs and issues
在GitHub PR和Issues中使用截图与录屏
Why this exists
设计初衷
GitHub's native image hosting () only works
from an authenticated browser session — there is no CLI or REST endpoint
for it. Any image URL in a PR/issue body written with must
already point at something publicly hosted. The CLI and the
hosted MCP at both host the file on uploads.sh
and return a stable public URL plus ready-to-paste markdown.
github.com/user-attachments/…ghgh … --body-fileuploadshttps://agents.uploads.sh/mcpGitHub 原生图片托管服务()仅支持已认证的浏览器会话上传——没有对应的 CLI 或 REST 接口。通过 写入 PR/Issue 正文的图片 URL,必须指向已公开托管的资源。 CLI 和位于 的托管式 MCP 会将文件托管在 uploads.sh,并返回稳定的公开 URL 及可直接粘贴的 Markdown 代码。
github.com/user-attachments/…ghgh … --body-fileuploadshttps://agents.uploads.sh/mcpWhich surface
选择合适的使用方式
Pick one transport and stay on it. This skill is the workflow. The
uploads-cli skill owns flags and MCP tool contracts.
| You have | Use |
|---|---|
| No shell (ChatGPT, or any host without a checkout) | Hosted MCP |
A checkout and the | The CLI examples below. Git can fill |
A | CLI only ( |
| Neither MCP nor the CLI | Stop and say so. Do not treat |
On the hosted MCP there is no tool and no git defaults. Stage with
+ + . Once the PR exists, with + +
, or with + (optional also promotes). The
managed comment is bot-only on that server.
attachputbranchrepopromoterepoprbranchputprrepobranch选择一种传输方式并保持一致。此技能定义了完整工作流,uploads-cli 技能则负责处理参数和 MCP 工具约定。
| 你的环境情况 | 使用方式 |
|---|---|
| 无 Shell 环境(如 ChatGPT,或无代码仓库的主机) | 使用托管式 MCP 的 |
有代码仓库和 | 使用下方的 CLI 示例。Git 会自动填充 |
需要对 | 仅使用 CLI( |
| 既无 MCP 也无 CLI | 直接告知用户无法操作。不要将 |
托管式 MCP 没有 工具,也没有 Git 默认配置。使用 + + 进行暂存。PR 创建完成后,使用 方法并传入 + + ,或使用 方法传入 + (可选传入 也会触发升级)。该服务器上的托管评论仅由机器人维护。
attachputbranchrepopromoterepoprbranchputprrepobranchStep 1 — Capture the visual
步骤1 — 捕获可视化内容
Skip this step if the visual is already in context (a ChatGPT attachment, a
file the host already holds). Go straight to hosted MCP .
putPrefer — it captures and hosts in
one step (drives a local Chrome, or falls back to a server-side render), so you
skip a separate host call. It takes , , ,
, and (to also save the PNG).
uploads screenshot <url|file.html>--viewport WxH@Nx--wait--selector--full-page--out <file>Capturing your own dev server? It hides known framework dev toolbars
(Astro/Next/Nuxt/Vite) automatically (opt out with ) and
takes to settle animations — no manual DOM surgery. Use
for any other overlay (repeatable), and /
(local backend) as an escape hatch to dismiss a banner or
freeze a specific animation.
--no-hide-dev-tools--reduced-motion--hide <selector>--eval <js>--init-script <file>bash
uploads screenshot http://localhost:4321 --viewport 1520x960@1x --out home.png --reduced-motion
uploads screenshot https://uploads.sh --selector main --dark--out<file>.uploads.jsonputattach.gitignore*.uploads.jsonOnly reach for your harness's browser tools / Playwright / an existing file when
can't reach the target (e.g. a flow that needs auth or
interaction first). GIFs and video: capture with any tool and upload as-is — the
optimizer only rewrites still images (PNG/JPEG → WebP).
uploads screenshot如果可视化内容已在上下文环境中(如 ChatGPT 附件、主机已有的文件),可跳过此步骤,直接使用托管式 MCP 的 方法。
put优先使用 —— 它可一步完成捕获和托管(调用本地 Chrome,或回退到服务器端渲染),无需单独调用托管接口。支持 、、、 和 (同时保存 PNG 文件)参数。
uploads screenshot <url|file.html>--viewport WxH@Nx--wait--selector--full-page--out <file>捕获本地开发服务器内容?它会自动隐藏已知框架的开发工具栏(Astro/Next/Nuxt/Vite),可通过 参数关闭此功能;还支持 参数来停止动画——无需手动修改 DOM。使用 参数隐藏其他覆盖层(可重复使用),使用 / (本地后端)作为应急方案来关闭横幅或冻结特定动画。
--no-hide-dev-tools--reduced-motion--hide <selector>--eval <js>--init-script <file>bash
uploads screenshot http://localhost:4321 --viewport 1520x960@1x --out home.png --reduced-motion
uploads screenshot https://uploads.sh --selector main --dark--out<file>.uploads.jsonputattach.gitignore*.uploads.json仅当 无法访问目标内容时(如需要先认证或交互的流程),再使用测试框架的浏览器工具/Playwright/已有文件。GIF 和视频:使用任意工具捕获后直接上传——优化器仅重写静态图片(PNG/JPEG → WebP)。
uploads screenshotStep 2 — Host and embed
步骤2 — 托管与嵌入
Two tiers, pick by whether a PR already exists:
- Simple — a PR/issue already exists. (or
uploads put shot.png --pr 123, which infers the PR from the current branch) — one call, stable per-PR key, embed URLs back immediately, and the managed comment collects that PR's media as a side effect.uploads attach shot.png - Advanced — stage pre-PR, before there's anything to target. (see below) — no PR/issue needed yet; promotion and the comment happen automatically once the PR opens, but only for a repo already bound to the workspace (see the caveat below). Reach for the simple tier once the PR exists unless you're deliberately building up a staged set across a longer branch.
uploads attach shot.png --branch
Default loop: stage as you go, from the first visual milestone. Don't wait
for a PR to exist. The moment you have something worth capturing — mid-task,
still on a branch, no PR yet — attach it right then. As of issue #403, a
bare already does this automatically whenever you're inside
a git repo on a non-default branch with no ////
— it stages under the same branch-keyed path
would produce, so a plain is enough. As of issue #469, (with no
// target) stages the same way, so capturing directly
from a URL before the PR exists carries every derived fact (path/url/env/
viewport, plus ) all the way through to the PR once it opens — no
extra flag needed for the auto-derived ones. Reach for
explicitly when you want its extras (uploading several files at once with
shared flags, or triggering promotion/comment sync as a side effect):
uploads put--pr--issue--key--ref--prefixattach --branchuploads put step1-before.png --meta path=/settings --state beforeuploads screenshot--pr--issue--branch--stateattach --branchbash
uploads screenshot http://localhost:4321/settings --out step1-before.png --state before
uploads screenshot http://localhost:4321/settings --out step2-after.png --state after分为两种场景,根据 PR 是否已创建选择:
- 简单场景 — PR/Issue 已存在:执行 (或
uploads put shot.png --pr 123,它会从当前分支自动推断 PR 编号)——一次调用即可获取稳定的 PR 专属链接和嵌入 URL,托管评论会自动汇总该 PR 的媒体文件。uploads attach shot.png - 进阶场景 — PR 创建前暂存:执行 (见下文)——无需提前创建 PR/Issue;PR 打开后会自动完成升级和评论操作,但仅适用于已绑定到工作区的仓库(见下方注意事项)。PR 创建完成后,除非需要在分支上长期构建暂存集,否则优先使用简单场景。
uploads attach shot.png --branch
默认工作流:随工作进度暂存内容,从第一个可视化里程碑开始。不要等到 PR 创建完成后再操作。一旦捕获到有价值的内容——即使是在任务进行中、仍在分支上、PR 尚未创建时——立即附加。从 Issue #403 开始,直接执行 会自动完成暂存,只要你处于 Git 仓库的非默认分支,且未传入 //// 参数——它会使用与 相同的分支键路径进行暂存,因此只需执行 即可。从 Issue #469 开始,(未传入 // 目标参数)也会以相同方式暂存,因此在 PR 创建前直接从 URL 捕获内容时,所有派生信息(路径/URL/环境/视口,加上 )都会保留到 PR 创建完成后——无需额外添加自动派生参数。当需要批量上传多个文件并共享参数,或触发升级/评论同步时,可显式使用 :
uploads put--pr--issue--key--ref--prefixattach --branchuploads put step1-before.png --meta path=/settings --state beforeuploads screenshot--pr--issue--branch--stateattach --branchbash
uploads screenshot http://localhost:4321/settings --out step1-before.png --state before
uploads screenshot http://localhost:4321/settings --out step2-after.png --state afteror, capturing an existing local file instead of a live URL:
或者,捕获本地已有文件而非实时URL:
uploads put ./step1-before.png --meta path=/settings --state before
uploads put ./step1-before.png --meta path=/settings --state before
or, explicitly, e.g. to upload several at once:
或者,显式执行,例如批量上传多个文件:
uploads attach ./step1-before.png ./step2-after.png --branch --state after
This uploads under stable, branch-keyed paths (no PR/issue target needed, no
comment yet — there's nothing to comment on until a PR exists). Keep doing
this at each meaningful visual milestone as you work; don't batch everything
into one call at the end. On the default branch (or outside a git repo, or
with `--no-git`), `put`/`screenshot` fall back to their ordinary dated
layout — that's the opt-out, along with any explicit `--key`/`--ref`/
`--prefix`/`--destination`.
**Staging only auto-promotes into a bound repo — don't promise it blind.**
Auto-promotion at PR-open time (webhook or CLI-triggered, below) requires the
repo already bound to a workspace: any earlier successful attach/comment/
promote call against that repo binds it implicitly, or `uploads github link`
binds it explicitly. A repo that's never been bound and only ever staged with
`--branch` sees **no error and no comment** when the PR opens — it's a silent
no-op. If you can't confirm the repo is already bound (`uploads github link
--status`), don't tell the user the screenshot will "just show up" in the PR.
The zero-setup fallback that works regardless of binding history: once the PR
exists, run `uploads attach --promote` (or any targeted `uploads attach`
against that PR) to promote and post explicitly.
**Pass `--state before`/`--state after` and `--meta path=/route` as a habit —
both, every time.** Before/after is the whole point of most PR screenshots, and
it's the one thing no tool can infer from the image; `path` is the other
highest-value queryable tag, and it's just as easy to forget outside
`uploads screenshot` (which derives it from the captured URL automatically —
`uploads put`/`uploads attach` of an existing file have nothing to derive it
from). Both cost one flag now and make `uploads find state=after` or
`uploads find path=/settings` work months later, when the filenames mean
nothing to anyone.
**`uploads screenshot` for both sides of a same-URL before/after pair is the
straightforward path** — its object name derives from the captured URL, and
`--state` folds into that derived name (`localhost-docs-mcp.webp` becomes
`localhost-docs-mcp-before.webp`/`-after.webp`), so capturing the same URL
twice with different states lands two distinct objects instead of one
overwriting the other. An explicit `--key` is unaffected — pass one when you
need a specific object name. A `put` of an already-existing file still needs
its own filenames or `--key` to keep before/after distinct, since there's no
URL to derive a stem from:
```bash
uploads screenshot https://app.example/settings --pr 123 --state before
uploads screenshot https://app.example/settings --pr 123 --state after
uploads put ./after.png --pr 123 --meta path=/settings --state after( also takes , , and .) //
print a on stderr (and a JSON field) when an image lands with no
meta — don't ignore it. Viewport is derived for you on — see the
uploads-cli skill for the full canonical vocabulary.
--stateemptyerrorloadingattachput --prput --issuetip: add --meta path=/route so this shot is findable by pagehintpathscreenshotThe PR comment assembles itself — you don't drive that step. Once the PR
opens (whether via or the GitHub UI), every branch-staged file
gets promoted into that PR's attachments and the managed comment is created
automatically:
gh pr create- With the uploads-sh GitHub App installed on the repo, a webhook does this the moment the PR opens, reopens, or gets a new commit — no CLI call required at all.
- Without the App, the next you run against that PR triggers the same promotion + comment refresh as a side effect. If you have nothing new to add right after opening the PR, run
uploads attach(zero file arguments) to promote and refresh explicitly — it exitsuploads attach --promoteeven if nothing was staged. Skip auto-promotion on a given call with0.--no-promote
"PR already exists" is just the simple case of the same command — same
, just pointed at a PR/issue number instead of a branch, and
the comment updates immediately since there's already something to comment
on:
uploads attachbash
uploads attach ./before.png ./after.png
uploads attach ./flow.gif --issue 45 --repo myorg/myapp
uploads attach ./shot.png --no-comment # stable URLs only, no commentFor a URL you'll hard-code in a PR/issue body (re-uploads overwrite in place,
URL never changes):
bash
uploads put ./after.png --pr 123 --alt "Dashboard after" --width 700For a durable public link to share anywhere (Slack, docs, a teammate):
bash
uploads put ./demo.gif --format urlAlways embed the returned markdown (or ) in GitHub — it uses the
no-cache host so overwrites propagate. Don't hand-build storage URLs.
embedUrlComment briefly disappeared? Don't panic-repost. If the App is installed
and subscribed to the event, a deleted or edited-out managed
comment self-heals automatically on the next webhook delivery — no need to
run / again just to bring it back.
issue_commentcommentattachRemoved the wrong screenshots? the object(s) and re-run
(or the hosted tool) to re-sync. Once the last attachment
is gone the comment is rewritten in place to a neutral empty state — it stays
on the PR (a later upload repopulates it) rather than leaving stale entries
that point at deleted files.
deletecommentcommentBot comment not showing up at all? The managed comment needs a
repo↔workspace binding (normally created implicitly by the first
comment/promote call, or by installing the GitHub App). If a comment you
expected doesn't appear, check the binding first:
bash
uploads github link --statusThat's read-only and shows the current binding (or that the repo is
unbound) without claiming anything. If the CLI reports
instead, the repo is already bound to a different workspace — it
won't fall back to posting via your own auth in that case. The fix is
from the owning workspace, or
asking an operator to reassign the binding; switching to the workspace that
already owns it also works.
not_authorizedghuploads github unlink --repo owner/nameCurate, don't dump. The comment inlines up to 16 images; anything past
that collapses into a overflow list. Name and pick shots
meaningfully (/, not ..) rather
than attaching every incidental screenshot from a long session — a curated
handful of milestones reads better than a dumped folder.
<details>before.pngafter.pngcapture-1capture-40uploads attach ./step1-before.png ./step2-after.png --branch --state after
此操作会将文件上传到稳定的分支键路径下(无需 PR/Issue 目标,也不会立即生成评论——PR 未创建时没有可评论的对象)。在工作中的每个重要可视化里程碑都执行此操作;不要等到最后批量上传。在默认分支(或 Git 仓库外,或使用 `--no-git` 参数),`put`/`screenshot` 会回退到普通的日期路径布局——这是退出暂存的方式,也可通过传入 `--key`/`--ref`/`--prefix`/`--destination` 参数显式指定。
**暂存内容仅会自动升级到已绑定的仓库——不要盲目承诺**。PR 打开时的自动升级(通过 Webhook 或 CLI 触发)要求仓库已绑定到工作区:之前针对该仓库的任意成功 attach/comment/promote 调用会自动绑定,或通过 `uploads github link` 显式绑定。从未绑定过、仅通过 `--branch` 暂存的仓库,在 PR 打开时**不会报错也不会生成评论**——这是静默无操作。如果无法确认仓库已绑定(执行 `uploads github link --status`),不要告知用户截图会「自动出现在 PR 中」。无论绑定历史如何,零配置的 fallback 方案是:PR 创建完成后,执行 `uploads attach --promote`(或针对该 PR 的任意 `uploads attach` 调用)来显式完成升级和发布。
**养成传入 `--state before`/`--state after` 和 `--meta path=/route` 参数的习惯——每次都要传**。前后对比是大多数 PR 截图的核心价值,也是工具无法从图片中推断的信息;`path` 是另一个高价值的可查询标签,在 `uploads screenshot` 外很容易遗漏(`uploads screenshot` 会从捕获的 URL 自动派生该参数——`uploads put`/`uploads attach` 已有文件时没有可派生的来源)。现在多传一个参数,几个月后执行 `uploads find state=after` 或 `uploads find path=/settings` 时就能轻松找到内容,而那时文件名可能已毫无意义。
**针对同一 URL 的前后对比,使用 `uploads screenshot` 是最直接的方式**——它的对象名称从捕获的 URL 派生,`--state` 参数会融入派生名称(`localhost-docs-mcp.webp` 会变为 `localhost-docs-mcp-before.webp`/`-after.webp`),因此针对同一 URL 捕获两次并传入不同的 `state` 参数会生成两个不同的对象,而非覆盖原有对象。显式传入 `--key` 参数不受影响——需要特定对象名称时可传入该参数。上传已有文件的 `put` 调用仍需使用不同的文件名或 `--key` 参数来区分前后内容,因为没有 URL 可派生命名前缀:
```bash
uploads screenshot https://app.example/settings --pr 123 --state before
uploads screenshot https://app.example/settings --pr 123 --state after
uploads put ./after.png --pr 123 --meta path=/settings --state after( 参数还支持 、 和 值。)// 在图片未携带 元数据时,会在 stderr 输出提示信息(),并在 JSON 中包含 字段——不要忽略此提示。 会自动派生视口参数——完整的规范词汇请参考 uploads-cli 技能。
--stateemptyerrorloadingattachput --prput --issuepathtip: add --meta path=/route so this shot is findable by pagehintscreenshotPR 评论会自动生成——无需手动操作。PR 打开后(无论是通过 还是 GitHub UI),所有分支暂存的文件都会升级到该 PR 的附件中,托管评论会自动创建:
gh pr create- 仓库已安装 uploads-sh GitHub App:Webhook 会在 PR 打开、重新打开或收到新提交时自动完成此操作——无需执行任何 CLI 调用。
- 未安装 App:下次针对该 PR 执行 时,会自动触发升级和评论刷新。如果 PR 打开后没有新内容需要添加,可执行
uploads attach(无需传入文件参数)来显式完成升级和刷新——即使没有暂存内容,也会返回uploads attach --promote退出码。可通过0参数跳过当前调用的自动升级。--no-promote
「PR 已存在」只是同一命令的简单场景——同样使用 ,只需指向 PR/Issue 编号而非分支,评论会立即更新,因为已有可评论的对象:
uploads attachbash
uploads attach ./before.png ./after.png
uploads attach ./flow.gif --issue 45 --repo myorg/myapp
uploads attach ./shot.png --no-comment # 仅获取稳定URL,不生成评论如果需要在 PR/Issue 正文中硬编码 URL(重新上传会覆盖原有内容,URL 保持不变):
bash
uploads put ./after.png --pr 123 --alt "Dashboard after" --width 700如果需要持久化的公开链接以分享到任意平台(Slack、文档、队友):
bash
uploads put ./demo.gif --format url始终在 GitHub 中嵌入返回的 markdown(或 )——它使用无缓存托管,因此覆盖操作会立即生效。不要手动构建存储 URL。
embedUrl评论短暂消失?不要急于重新发布。如果已安装 App 并订阅了 事件,删除或编辑掉的托管评论会在下次 Webhook 触发时自动恢复——无需重新执行 / 调用。
issue_commentcommentattach误删了截图? 删除对应的对象,然后重新执行 (或托管的 工具)来重新同步。最后一个附件删除后,评论会原地重写为中性空状态——它会保留在 PR 上(后续上传会重新填充),而非留下指向已删除文件的无效条目。
commentcomment机器人评论未显示? 托管评论需要仓库与工作区绑定(通常由第一次 comment/promote 调用自动创建,或通过安装 GitHub App 创建)。如果预期的评论未出现,首先检查绑定状态:
bash
uploads github link --status此命令为只读,会显示当前绑定状态(或仓库未绑定),不会修改任何内容。如果 CLI 返回 ,说明该仓库已绑定到其他工作区——此时不会回退到使用你的 认证发布内容。解决方法是在拥有绑定权限的工作区执行 ,或联系管理员重新分配绑定;切换到已拥有绑定权限的工作区也可解决问题。
not_authorizedghuploads github unlink --repo owner/name精心筛选,不要批量上传。评论最多可内联显示 16 张图片;超过此数量的内容会折叠到 溢出列表中。为截图赋予有意义的名称(如 /,而非 ..),并选择重要的截图——精心挑选的几个里程碑截图比批量上传整个文件夹的截图更易阅读。
<details>before.pngafter.pngcapture-1capture-40Step 3 — Embed well
步骤3 — 优化嵌入效果
-
Meaningful alt text, always ().
--alt -
Constrain width on large shots with(emits sized
--width).<img> -
Before/after reads best side by side:markdown
| Before | After | | ------------------------------------ | ----------------------------------- | | <img width="380" src="…/before.png"> | <img width="380" src="…/after.png"> | -
Motion: GitHub markdown won't autoplay MP4 URLs — prefer a GIF, or a still image that links to the video URL.
-
Write bodies to a file and use/
gh pr edit --body-filerather than inline HEREDOCs.gh issue comment --body-file
-
始终添加有意义的替代文本(使用参数)。
--alt -
使用参数限制大截图的宽度(生成带尺寸的
--width标签)。<img> -
前后对比图并排展示效果最佳:markdown
| 之前 | 之后 | | ---------------------------------- | ---------------------------------- | | <img width="380" src="…/before.png"> | <img width="380" src="…/after.png"> | -
动态内容:GitHub Markdown 不会自动播放 MP4 URL——优先使用 GIF,或使用静态图片链接到视频 URL。
-
将正文写入文件,使用/
gh pr edit --body-file命令,而非内联 HEREDOC。gh issue comment --body-file
Setup and escalation
安装与故障排查
- No shell? Use the hosted MCP. Do not install the CLI.
- CLI missing on a machine with a shell?
npm install --global @buildinternet/uploads - Not authenticated on the CLI? (one-time, opens a browser), then
uploads loginto verify. Hosted MCP uses OAuth on first tool call.uploads doctor - Everything deeper — flags, key layouts, MCP tool contracts, metadata and
search, galleries, config defaults, output formats, exit codes — lives in
the uploads-cli skill and .
uploads <command> --help
- 无 Shell 环境?使用托管式 MCP。不要安装 CLI。
- 有 Shell 环境但缺少 CLI?执行
npm install --global @buildinternet/uploads - CLI 未认证?执行 (一次性操作,会打开浏览器),然后执行
uploads login验证。托管式 MCP 在首次调用工具时使用 OAuth 认证。uploads doctor - 更深入的内容——参数、键路径、MCP 工具约定、元数据与搜索、画廊、配置默认值、输出格式、退出码——请参考 uploads-cli 技能和 。
uploads <command> --help
Cautions
注意事项
- Uploads are public and effectively permanent until deleted. GitHub repo
visibility is not an access control, and keys are predictable. Never upload secrets, tokens, or customer PII — crop/redact first.
gh/<owner>/<repo>/pull/<num>/… - Private repos get an unguessable URL automatically. When the uploads
GitHub App can see a target repo is private, attachments key under
instead — no flag needed. The id is durable, not access-controlled: anyone who gets the URL can read it until you rotate it (
gh/private/<id>/…). See docs/private-attachments.md for the full model.uploads github rotate-prefix
- 上传内容为公开且永久有效,除非手动删除。GitHub 仓库可见性不构成访问控制,路径可预测。切勿上传密钥、令牌或客户隐私信息——上传前先裁剪/打码。
gh/<owner>/<repo>/pull/<num>/… - 私有仓库会自动生成不可猜测的 URL。当 uploads GitHub App 检测到目标仓库为私有仓库时,附件会存储在 路径下——无需额外参数。该 ID 是持久化的,但不提供访问控制:任何人获取 URL 后都可访问,直到你执行
gh/private/<id>/…旋转路径。完整模型请参考 docs/private-attachments.md。uploads github rotate-prefix
Need to point at something in the screenshot?
需要在截图中标记内容?
Boxes, arrows, labels, freeform strokes, and redaction (solid for secrets
caught in a capture — blurred text can be recoverable) get baked onto a
screenshot with or — see the annotate-screenshots
skill for the spec format and workflow, then come back here to attach.
uploads screenshot --annotateuploads annotate可使用 或 在截图上添加方框、箭头、标签、自由线条和打码(针对捕获到的敏感信息使用实心打码——模糊文本可能被恢复)——请参考 annotate-screenshots 技能的规范格式和工作流,然后回到此处完成附加操作。
uploads screenshot --annotateuploads annotate