DEV Community

Cover image for gh 2.99 Can Attach Screenshots Now: 9 gh Commands to Hand Your Coding Agent
Gabriel Anhaia
Gabriel Anhaia

Posted on AI-assisted

gh 2.99 Can Attach Screenshots Now: 9 gh Commands to Hand Your Coding Agent


You ask a coding agent to fix a header color in a private repo and to put before-and-after screenshots on the pull request. The agent hits a wall. An image committed to a private repo shows up broken for reviewers, and GitHub's CLI had no way to upload one. In a lab test by Glow Labs, Claude Code running Opus 5 found its own way out: it created "a new public repo, sweeper-demo/pr-assets, holding the two screenshots pinned to a commit SHA."

That lab test sits inside a larger finding. Glow's report, published September 29, 2026, counts over 13,000 internal images published openly on GitHub, from developers at more than 300 organizations, across 900+ repositories. In 93% of the cases the images sat in a repo an employee had created under their own username, outside the company's GitHub organization. Help Net Security and The Hacker News have the coverage. One case involved billing records for a utility company, and The Hacker News reports the images were still public when Glow told the company.

The gap the agent was working around is closed. GitHub CLI 2.99.0, released September 1, added a repeatable --attach flag that uploads a local image or video into an issue, pull request or comment (changelog). The upload goes to GitHub's user-attachments endpoint (PR #14180), and GitHub's attachments docs say that in private and internal repos "only people with access to the repository can view the uploaded files." No second repo needed.

A small robot holding a camera stands between an open glass display case facing a crowd and a locked orange drawer marked with a pull-request arrow
Two places a screenshot can go. Only one of them is visible to the whole internet.

Here are nine gh commands to give your agent instead of a browser or a workaround, in the order a task uses them, each with the flag that makes it work for an agent. The same release also made gh print text-only progress instead of animated spinners when it detects a coding agent (PR #14191), so the output reads cleanly in an agent's transcript.

Start from the issue, end with a PR

1. gh issue develop --checkout --worktree

gh issue develop 123 --checkout \
  --worktree ../wt-issue-123
Enter fullscreen mode Exit fullscreen mode

This creates a branch linked to issue 123 and checks it out in a new git worktree, so your current working copy stays as it is. The --worktree option arrived in 2.99.0, along with a fix that refuses a non-empty worktree folder before any branch is created (release notes). gh issue develop --list 123 shows the branches already linked to an issue (manual).

2. gh pr create --fill

git push -u origin HEAD
gh pr create --fill --draft \
  --head "$(git branch --show-current)"
Enter fullscreen mode Exit fullscreen mode

--fill takes the title and body from the commits (manual). Use --fill-verbose if the commit bodies carry the useful detail. Push first and pass --head: when the branch isn't fully pushed, gh asks where to push it, and the manual says --head skips "any forking or pushing behavior," so the agent never sits waiting on a prompt it can't answer. --draft marks the PR as not ready for review yet.

Show the result with --attach

3. --attach on a comment, an edit or a new PR

gh pr comment "$(git branch --show-current)" \
  --body "Header after the fix" \
  --attach './after.png#Header in the new color'
Enter fullscreen mode Exit fullscreen mode

The text after # is the alt text. Leave it out and gh uses the file name (docs). If the body already points at a local file, gh rewrites that reference to the uploaded URL in place, so an agent can write the PR description it wants and attach the files in one call:

## Before / after

![Header before the fix](./before.png)
![Header after the fix](./after.png)
Enter fullscreen mode Exit fullscreen mode
gh pr edit --body-file body.md \
  --attach ./before.png --attach ./after.png
Enter fullscreen mode Exit fullscreen mode

What it needs, from the changelog, the docs and the release notes:

  • Write access to the repository. A read-only account is refused before any upload (PR #14180).
  • The OAuth token from gh auth login or a classic personal access token.
  • GitHub.com or GitHub Enterprise Cloud. GitHub Enterprise Server isn't supported in this release.
  • PNG, JPEG, GIF, WebP, SVG, MP4, MOV or WebM. Images up to 10 MB, video up to 10 MB on free plans and 100 MB on paid plans.
  • No more than 50 files per command (PR #14289), and the same file only once.

It works on gh issue create, gh issue edit, gh issue comment, gh pr create, gh pr edit and gh pr comment. On a public repo, the uploaded file is public too: GitHub's attachments docs say public-repo uploads "can be accessed without authentication." The flag fixes where the screenshot lives. It doesn't decide what's in it, so a screenshot of a customer screen still doesn't belong on a public repo's PR.

Let CI and reviewers talk to the agent

4. gh pr checks --watch --fail-fast

gh pr checks "$(git branch --show-current)" \
  --watch --fail-fast
Enter fullscreen mode Exit fullscreen mode

--watch waits until the checks finish and --fail-fast leaves watch mode on the first failure (manual). Without --watch, exit code 8 means checks are still pending, which is handy in a loop. Add --required to ignore the checks that can't block the merge.

5. gh run view --log-failed

run=$(gh run list --status failure --limit 1 \
  --branch "$(git branch --show-current)" \
  --json databaseId --jq '.[0].databaseId')
gh run view "$run" --log-failed
Enter fullscreen mode Exit fullscreen mode

--log-failed prints the log for the failed steps only (manual). That is the part the agent needs, without thousands of lines of passing setup steps filling its context. gh run list takes --branch and --status, and databaseId is the run ID (manual).

6. gh pr diff --name-only

gh pr diff --name-only --exclude '*.lock'
Enter fullscreen mode Exit fullscreen mode

A list of the files the PR changed, without the diff (manual). Have the agent print it before asking for review and compare it with the task. A header color fix that touched a CI workflow should be explained before anyone reads line one. --exclude takes globs for files you don't want in the list.

7. gh api graphql for unresolved review threads

gh api graphql -F owner='{owner}' -F name='{repo}' \
  -F pr=123 -f query='
query($owner: String!, $name: String!, $pr: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $pr) {
      reviewThreads(first: 100) {
        nodes { isResolved path line
          comments(first: 1) { nodes { body } } }
      }
    }
  }
}' --jq '.data.repository.pullRequest | .reviewThreads
  | .nodes[] | select(.isResolved | not)'
Enter fullscreen mode Exit fullscreen mode

Review threads, with whether each one is resolved, the file path and the line, come from the reviewThreads connection on a pull request in GitHub's GraphQL API. gh api fills {owner} and {repo} from the current repository, and -F turns 123 into an integer (manual). The agent gets only the open threads, each with its first comment.

Audit what your agent made public

The last two are for you, not the agent. Glow's advice is to look beyond your organization, starting with the people who commit to your private repos, and its checklist says: "Check releases and gists, not just files."

8. gh repo list --visibility public

me=$(gh api user --jq .login)
gh repo list "$me" --visibility public --limit 200 \
  --json name,createdAt,url \
  --jq 'sort_by(.createdAt) | reverse | .[]'
Enter fullscreen mode Exit fullscreen mode

Your public repos, newest first (manual). Anything named like pr-assets or screenshots that you don't remember creating is worth opening. Glow notes that images attached to a release leave the file listing looking empty, so for a suspicious repo also run gh release list --repo "$me/<name>".

9. gh gist list

gh gist list --limit 100
gh gist list --secret --limit 100
Enter fullscreen mode Exit fullscreen mode

Run both (manual). GitHub's own gist docs are blunt: "Secret gists aren't private." Anyone with the URL can see one.

Then tell the agent, in the instruction file it reads (AGENTS.md, CLAUDE.md):

- Put screenshots on PRs and issues with `gh ... --attach`.
- Never create a repository, gist or release to host files.
- If `--attach` fails, stop and tell me why.
Enter fullscreen mode Exit fullscreen mode

The agent can still ignore an instruction file. Glow's prevention advice goes further: a review step before an agent creates a public repo, pushes to a personal account or gist, or makes a private repo public.

Where these go in a Hermes task

I build Hermes IDE, so weigh this section with that in mind. Hermes runs each agent in a real terminal, so gh behaves there the same as in any other terminal, with whatever gh auth login you already did. Hermes never asks for your tokens.

⌘N (Ctrl+Shift+N on Windows and Linux) starts a task on its own hermes/<name> branch in its own worktree, with the task as the agent's first prompt. That covers the worktree half of item 1. Put the issue number and the three instruction lines from above in the task text.

Hermes IDE 2.3.4 New task sheet with a refund-endpoint task typed and chips for Claude Code, the orders-api project, a new hermes worktree and Accept edits
The ⌘N New task sheet in Hermes 2.3.4: Claude Code, the orders-api project, a new hermes/ worktree, Accept edits, and the "Hermes will run" preview of the claude command.

While the agent works, items 4 to 6 run in its terminal. Local checks belong in the repo's .hermes/worktree.toml as done_when (recipe docs). CI with gh pr checks is the remote half of the same question.

Before anything reaches GitHub, the Review Desk (⌘G, or Ctrl+Shift+G on Windows and Linux) shows the agent's changes by turn or by file, with risk flags. Then Land commits, opens a pull request or merges locally into the branch the task started from, and can be undone. In a Hermes task, Land takes the place of item 2.

Hermes IDE 2.3.4 Review Desk in By turn view, listing two turns with a diff of src/db.ts and a drafted commit message
The Review Desk (⌘G) in By turn view: two turns, turn 1's diff of src/db.ts, the changed files and a commit message drafted from the turns.

Once Land has opened the PR, items 3 and 7 run against its number: the agent attaches its screenshots with gh pr comment <number> --attach and reads the unresolved threads. Items 8 and 9 stay with you.


If this was useful

Hermes IDE is free, source-available and runs on macOS, Windows and Linux. Download it, and if it saves you a messy merge, star it on GitHub. It isn't affiliated with Nous Research, Anthropic, OpenAI or any agent vendor.

Where a file is stored decides who can read it, and the screenshot leak is that decision made by an agent in a hurry. System Design Pocket Guide: Fundamentals is the short read on the core building blocks underneath the systems your agents push to. It's one of 8 short Pocket Guides for Developers, on agents, RAG, prompts, observability, events, databases and system design.

System Design Pocket Guide: Fundamentals — Core Building Blocks for Scalable Systems

Top comments (0)