Skip to content

Tracking: official gh CLI native image/video upload (github/roadmap#1324) #56

Description

@drogers0

Summary

The official CLI now has native image/video attachment.

Status as of 2026-09-08: released. --attach shipped in gh v2.99.0 on 2026-09-01, announced the same day as GitHub CLI: Media in issues, pull requests, and comments and described there as generally available on all plans. The roadmap item picked up a GA label on 2026-08-21 and is still open with no milestone. v2.100.0 (2026-09-03) added only attachment telemetry (cli/cli#14327).

This issue is tracking/awareness only. It exists so the overlap with gh-image is visible and scope, positioning, and README framing can be settled before the release lands.

What upstream --attach does

A repeatable --attach flag on six commands, wired in pkg/cmd/{issue,pr}/{create,edit,comment}:

gh issue create, gh issue edit, gh issue comment, gh pr create, gh pr edit, gh pr comment

--attach file   Attach an image or video file, in '<file>#<image alt text>' format
gh issue comment 87 --repo monalisa/monas-cafe --body "Menu error below:" --attach ./menu-error.png
gh issue comment 12 --attach './login.png#The login error state'

Placement: if the body contains a markdown reference to an attached local path, that reference is rewritten to the uploaded asset URL; otherwise the asset is appended to the end of the body. Images render as ![alt](url); videos render as a bare URL on its own line, or [name](url) when the reference sits inline.

Alt text handling: supplied after #, defaulting to the filename with its extension stripped and remaining dots replaced by spaces, mirroring the web uploader. Alt text is escaped, and refused outright when it cannot be rendered safely. Videos take no alt text.

Constraints as released (internal/attachments at v2.99.0, verified 2026-09-08 — unchanged from the merge)

Upstream gh --attach
File types 9 extensions: .png .jpg .jpeg .gif .webp .svg .mp4 .mov .webm
Size images ≤ 10 MiB, videos ≤ 100 MiB, checked client-side, inclusive
Auth allowlist of gho_ (OAuth), ghp_ (classic PAT), github_pat_ (fine-grained). Everything else → unsupported authentication type, which covers ghs_ (Actions GITHUB_TOKEN, app installation) and ghu_ (user-to-server)
Permission allowlist of ADMIN, MAINTAIN, WRITE, measured against their upload endpoint — the code notes READ and TRIAGE get a 404 there
Hosts GitHub.com and GHEC data-residency tenants (.ghe.com). On-prem GHES is refused: attaching files is not supported on GitHub Enterprise Server
Standalone upload none — the flag exists only inline on those six commands
Download not implemented

Other validation, all client-side: an empty --attach value, stdin, directories, non-regular files, zero-byte files, and the same file attached twice are each rejected before any upload.

Non-image/video attachments are not in scope; that ask became cli/cli#14194, which is open, unassigned, and carries the standard backlog reply — "we are not committing to implementing this feature at this time."

Where gh-image still differs

Upstream now covers the common case: a user with write access on GitHub.com attaching a PNG or MP4 to an issue or PR they are creating or commenting on. The README should stop implying the official CLI cannot do this.

Confirmed gaps

  • File types. Upstream accepts 9 extensions. We map PDF, zip, logs, source files, YAML, tarballs and more (Support uploading non-image files (PDF, zip, etc.) #23). The widest remaining gap.
  • Read-only contributors. Upstream requires ADMIN/MAINTAIN/WRITE. Our browser-session path does not: Write-access requirement is overstated, and invalid sessions fall into the wrong error branch #41 records a successful end-to-end upload against a public repo where the account held pull only, which is why the write-access wording was removed from token.go and the README. The two tools use different endpoints — upstream posts to uploads.github.com/user-attachments/assets with a bearer token and a numeric repository id, while we obtain an uploadToken from the repo page and go through upload/policies/assets → S3 → finalize — so their permission floor does not apply to us. Scope of the test: public repo, read-only. Private-repo read-only and TRIAGE are untested.
  • Standalone upload. We return a URL and markdown usable in any body, commit message, gist, or non-gh tool. There is no attachment command upstream, and the package documentation is explicit that the flag only exists inline and the caller must write the returned markdown to a resource. A standalone primitive was requested in #13256 and not built.
  • Download. Ours shipped in Support downloading attachments from issues/PRs #42/feat: add download subcommand for user-attachments URLs (#42) #46. Upstream has none, and the long-standing request cli/cli#9046 is labeled blocked and extension-idea, with maintainers stating the platform lacks an attachments API and directing requests to GitHub support rather than the CLI repo. cli/cli#11584 was closed as not planned, with the same explanation: no public API exists for attachment upload or download. Demand there is the same agent-driven use case Support downloading attachments from issues/PRs #42 was opened for.

Mostly not a difference

  • CI and automation tokens. Upstream rejects ghs_ and ghu_, so a workflow attaching a screenshot needs a PAT. This is a platform limit rather than a CLI decision, and it binds our bearer path too: cli/cli#14309 reports the endpoint returning 404 for an installation token with write access, where the same request with gho_ succeeds. What remains on our side is the session-cookie path driven by GH_SESSION_TOKEN, which does run in CI but ties automation to a human session.

No longer a difference

  • Enterprise. Upstream refuses on-prem GHES but works on GHEC data-residency tenants. Our on-prem support is still an open request (Github Enterprise Support #37), so their host coverage is currently the broader of the two.
  • Output formatting. Both emit plain markdown — ![name](url) for images, a bare URL for videos, [name](url) for other files. We have no width or HTML flags, and upstream additionally ships alt-text syntax with escaping.

Also worth noting: cli/cli#14261 documents attachment support in the gh Agent Skill. We ship a skill of our own, and it should be reviewed against theirs.

Related: bearer-token upload (#48)

#48 found that gh auth token works as a Bearer against https://uploads.github.com/user-attachments/assets, and that the token path accepts images and video but rejects other content types. The upstream implementation matches that from the other direction: same endpoint, same images/video scope, same requirement for elevated repository permission. The browser-session path remains the broader one for both file types and permissions.

Community datapoint from the #13256 thread (@labilio, Windows, 2026-08-11): released v1.2.0 failed because the browser user_session cookie could not be decrypted in that environment (#4), and a build from main@d59ac2bb with the token-first path uploaded successfully using the existing gh OAuth token. The token path is doing real work for the users the cookie path loses.

What to watch

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions