본문으로 건너뛰기
cccskills
무료GitHub에 공개

github-attachments

Upload images and files to GitHub PRs, issues, and comments so GitHub hosts them instead of committing binaries to the repository. Use when adding screenshots to a PR or issue body, replacing committed screenshots or raw.githubusercontent.com links with hosted attachments, or when `gh` appears to offer no way to attach a file.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

연동 도구GitHub
설치 방법 보기

포함된 파일(1)

  • SKILL.md5.4 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

GitHub Attachments Without Committing Binaries

Screenshots attached to a PR are review ephemera. Committing them puts binaries in git history forever — bloating every clone, with no value to the codebase. The historical workaround (commit the image, link it via a raw.githubusercontent.com URL pinned to a SHA) is the anti-pattern this skill replaces.

gh has no attachment support: no flag on gh pr create, gh pr edit, gh issue create, or gh issue comment. The GraphQL API has no upload mutation. But an undocumented endpoint produces exactly the https://github.com/user-attachments/assets/<uuid> URLs that browser drag-and-drop produces, and it works from curl with a gh token.

This endpoint is undocumented and unofficial. GitHub could change or remove it without notice. Verified working against github.com on 2026-08-04.

Upload one file

repository_id must be a repository you can push to — it is the upload quota's owner, not the destination. It does not have to be the repo the issue or PR lives in, and the resulting URL is not tied to it: an asset uploaded against your fork renders fine on an upstream issue.

So when contributing to a repo you do not own, do not reach for the upstream's id. Pushable means permissions.push is true — being able to open issues or PRs against a public repo does not grant it, and for any upstream you contribute to via a fork it will be false:

gh api repos/OWNER/REPO --jq .permissions

Prefer your own fork (or any repo you own) as the upload target. Using an upstream you lack push on fails with a misleading 404 Not Found rather than a permissions error, which reads like a broken endpoint or a bad asset name.

FILE=screenshot.png
# A repo you can push to — your fork, not the upstream you are filing against.
REPO_ID=$(gh api repos/YOUR-FORK-OWNER/REPO --jq .id)
TOKEN=$(gh auth token)

curl -sS -X POST \
  "https://uploads.github.com/user-attachments/assets?name=$(basename "$FILE")&content_type=image/png&repository_id=$REPO_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json" \
  --data-binary "@$FILE"

HTTP 201 with {"url":"https://github.com/user-attachments/assets/<uuid>"}.

content_type must match the file (image/png, image/jpeg, ...).

Reference the returned URL as ordinary markdown in the body:

![Login screen](https://github.com/user-attachments/assets/<uuid>)

Then apply it: gh pr edit N --body-file body.md (or gh issue edit, gh pr comment --body-file, ...).

Order matters: upload, reference, then verify

An uploaded asset returns HTTP 404 with a 9-byte "Not Found" body until some PR or issue body actually references it. The upload returns 201 and a valid URL immediately, but the URL does not resolve until it is referenced.

This is not propagation delay. Waiting does not help, and re-uploading only creates orphaned assets. Do not diagnose a 404 at this stage as a failed upload.

Two different 404s, distinguished by when they happen: on the POST it means the token cannot push to repository_id (use a repo you own); on fetching an asset URL it means nothing references it yet.

So:

  1. Upload every file, recording the name→URL mapping as you go.
  2. Rewrite the PR/issue body to reference the new URLs.
  3. Apply the body with gh pr edit / gh issue edit.
  4. Only then verify the assets resolve.

Verify by byte count against the source, not by HTTP status — curl -o /dev/null -w '%{http_code}' -L can report a misleading status:

exp=$(wc -c < "$FILE")
got=$(curl -sS -L --max-time 30 "$URL" | wc -c)
[ "$exp" = "$got" ] || echo "MISMATCH: expected $exp, got $got"

A 9-byte response is the literal string Not Found — the asset is not referenced anywhere yet.

Bulk uploads and migrations

For several files, append each name<TAB>url pair to a TSV as you upload, then do the body rewriting with a small Python regex substitution over that mapping. That keeps the fragile per-file step separate from the fragile body-rewriting step, so a failure in one does not force redoing the other.

Under zsh with noclobber set, > and >> silently fail when creating or overwriting a file — which can silently lose the whole mapping. Use : > mapping.tsv to create it, or pipe through tee -a.

To migrate screenshots already committed to a repository:

  1. Extract the blobs with git show <sha>:<path> > out.png. They may live on commits no longer reachable from any branch, so find the SHA from the PR's commit list or the reflog rather than assuming HEAD has them.
  2. Upload them and rewrite the PR bodies to the new URLs.
  3. Verify (order above), then git rm the files.

git rm removes the files from the tree but not the blobs from history; purging those requires rewriting history, which is rarely worth it for a few small images.

Alternatives

gh CLI extensions such as gh-image wrap this same endpoint, and cli/cli#12960 requests native support. The raw curl above needs no dependencies.

Endpoint credit: https://island94.org/2026/08/programmatically-upload-attachments-to-github-issues-pull-requests-comments

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Applies local reliability, viewport, tab-safety, stale-ref, widget, and browser-boundary lessons to every agent-browser automation. Use alongside the upstream agent-browser skill whenever navigating, clicking, filling, testing, extracting, taking screenshots, or debugging any website with agent-browser.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

aspiers/ai-config152026년 10월 9일 업데이트

Size the agent-browser Chromium window to fill its current screen, leaving a configurable bottom margin for the desktop panel. Use before any agent-browser automation that needs the full screen visible without elements overlapping or scrolling off (e.g. Xero, dense web apps).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

aspiers/ai-config152026년 10월 9일 업데이트

Create Claude Code slash commands, OpenCode command files, Pi prompt templates, and Codex custom prompts that delegate to the right subagent or skill. Use when creating new commands, porting commands across agent platforms, or refactoring existing commands to follow platform conventions.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

aspiers/ai-config152026년 10월 9일 업데이트

Adds or changes allowed commands in AI agent permission configs for OpenCode and Claude Code. Use when a command needs adding to an agent's allow list, when permission settings for existing commands need changing, when setting up a new AI tool that requires command permissions, or when the user asks to stop being prompted for a particular command.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

aspiers/ai-config152026년 10월 9일 업데이트

bc

무료

Creates a Beads issue for a described problem or piece of work without doing the work itself. Use when the user invokes `/bc` or `$bc`, or asks to file, log, or record a bead for something. To also carry out the work, use the `bx` skill instead.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

aspiers/ai-config152026년 10월 9일 업데이트

bdr

무료

Stores a persistent memory or learning with `bd remember` so it survives across sessions. Use when the user invokes `/bdr` or `$bdr`, or asks to remember, note, or persist an insight in a Beads workspace.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

aspiers/ai-config152026년 10월 9일 업데이트

aspiers의 스킬 모두 보기

이 스킬의 문제 신고