- Book: System Design Pocket Guide: Fundamentals
- The series: Pocket Guides for Developers — 8 short books on agents, RAG, prompts, observability, events, databases and system design — the whole series
- My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools
- Me: xgabriel.com | GitHub
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.

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
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)"
--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'
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


gh pr edit --body-file body.md \
--attach ./before.png --attach ./after.png
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 loginor 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
--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
--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'
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)'
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 | .[]'
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
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.
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.

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.

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.

Top comments (0)