attach-media
Skill20 starsChanged 14 days agoMITView on GitHub
Uploads local screenshots and recordings to GitHub and embeds them in a PR or issue body or comment as inline-rendering user-attachments URLs, via `gh --attach` with a curl fallback; never writes placeholders. Triggers on "attach screenshots to the PR", "upload this recording to the PR", "/attach-media".
- Reads credentials
- Commits and pushes
1 other project uses a version of this.
Adopted by
Most recently taken up by
- angusfretwell/skillstheir own version, first seen Nov 4, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- angusfretwell/skills★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository48 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- skills/workflow/autonomous-workflow/CLAUDE.mdCLAUDE.md
- ideateSkill
- interviewSkill
- playwright-trace-analyzerSkill
- profile-optimizerSkill
- rum-trackingSkill
- screencastSkill
- video-analyserSkill
- youtube-transcriptSkill
- create-skillSkill
- docsSkill
- handoffSkill
- optimize-claude-mdSkill
- persistent-memorySkill
- ci-auto-fixSkill
- create-prSkill
- github-actions-authorSkill
- resolve-conflictsSkill
- animations-nativeSkill
- animationsSkill
- behavioral-designSkill
- chartingSkill
- storybookSkill
- uxSkill
- visual-designSkill
- ai-engineeringSkill
- confidenceSkill
- criticalSkill
- impact-mapSkill
- jev-assertSkill
- measurableSkill
- optimize-approachSkill
- polishSkill
- pr-reviewSkill
- review-loopSkill
- tddSkill
- verify-behaviorSkill
- aw-verifySkill
- e2e-testing-mobileSkill
- e2e-testingSkill
- telemetry-verifySkill
- ui-verifySkill
- autonomous-workflowSkill
- aw-create-planSkill
- aw-create-walkthroughSkill
- fix-bugSkill
- implement-suggestionSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 3 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 25
Put real screenshots and recordings into a GitHub PR or issue, so a reviewer sees the change without running it.
- Distinctive: line 26
Every skill that wants media on a PR delegates here, so the upload method lives in exactly one place.
- Distinctive: line 54
Check 4 is mandatory because an upload is permanent and visible to everyone who can read the repo.
- Very specific: line 95
Remove any local path you find and list its file as not attached (upload failed: <reason>).
- Very specific: line 111
Attach after the PR exists: Never fold --attach into a caller's gh pr create.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Attach Media
Put real screenshots and recordings into a GitHub PR or issue, so a reviewer sees the change without running it. Every skill that wants media on a PR delegates here, so the upload method lives in exactly one place.
Skill("attach-media", "<pr-url|#n> <file>[#alt] ... [--to body|comment|urls] [--heading <text>] [--dry-run]")| Argument | Default | Meaning |
<pr-or-issue-ref> | the current branch's open PR | A PR or issue URL, or #<n> in the current repo. |
<file>[#alt] | — (required, 1–50) | A local file. Text after # is the image's alt text; video has none. |
--to body | yes | Write into the owned region of the PR or issue body. Re-runs merge into the region by filename. |
--to comment | — | Post one new comment instead. Use for evidence attached to a specific event. |
--to urls | — | Upload only, through rung 2, and print one Markdown line per file for the caller to embed. Use it for a review thread or any body the caller writes itself. Writes nothing to GitHub except the upload. |
--heading <text> | Screenshots | The ### heading inside the owned region. |
--dry-run | — | Run the preflight and print the planned region. Upload nothing. |
Step 1: Preflight every file
Drop a file from the run, and name it in the report, when any check fails:
| # | Check | On failure |
| 1 | The file exists and is non-empty. | skipped (missing) |
| 2 | The extension is png, jpg, jpeg, gif, webp, svg, mp4, mov, or webm. | Convert other video (avi, mkv) with ffmpeg -i in.avi -c:v libx264 -pix_fmt yuv420p -an out.mp4; else skipped (unsupported type) |
| 2a | A recording is a video, not a GIF. | Convert an animated .gif (a browser-extension recording) to .mp4: ffmpeg -i x.gif -movflags +faststart -vf "scale=1280:-2,format=yuv420p" -c:v libx264 -crf 28 -an x.mp4. It is ~20× smaller, and its bare URL renders as a player; a GIF renders only as an image embed |
| 3 | An image or GIF is ≤ 10 MB; a video is ≤ 10 MB (100 MB on a paid plan). | Re-encode a video once: ffmpeg -i in.webm -vf scale=1280:-2 -c:v libx264 -crf 30 -an out.mp4; else skipped (too large) |
| 4 | You looked at it. Open every image with the Read tool — for a light/dark pair rendered from one page (impact-map), one view covers both, and a view the caller already made this run counts only when the file was not re-rendered or edited after it; for a video, open the screencast contact sheet beside it (<stem>.sheet.png, one frame per step) when it exists, else extract three frames (ffmpeg -i v.webm -vf fps=1/3 -frames:v 3 /tmp/f%d.png) and open them. | skipped (contains <secret/token/PII>) — never upload it |
Check 4 is mandatory because an upload is permanent and visible to everyone who can read the repo. Refuse any frame showing an API key, token, password, session cookie, a real customer's name or email, or a production data row. A test fixture's fake data is fine.
Step 2: Upload through the first rung that works
Full procedure: rules/upload-ladder.md.
| Rung | Condition | Method |
| 1 | gh pr edit --help lists --attach (gh ≥ 2.99) and gh auth status passes | gh pr edit / gh issue edit / gh pr comment with --body-file and one --attach per file |
| 2 | Rung 1 fails, and a token resolves from gh auth token, $GH_TOKEN, or $GITHUB_TOKEN | curl POST to https://uploads.github.com/user-attachments/assets, then write the body over REST |
| 3 | Neither rung can run (no token, GitHub Enterprise Server, MCP-only host, no write access) | Upload nothing; report not attached (<reason>) with the local paths |
Step 3: Write the owned region
Under --to urls, skip this step and print the lines from rules/upload-ladder.md § --to urls.
Full contract: rules/body-region.md.
The region is delimited by <!-- attach-media:v1 --> … <!-- /attach-media:v1 -->.
There is at most one per body, and a re-run merges by filename.
<!-- attach-media:v1 -->
### Screenshots
<!-- attach-media:file=revenue-widget.png -->

<!-- attach-media:file=spec-1.webm -->
https://github.com/user-attachments/assets/9a2d…
<!-- /attach-media:v1 -->Step 4: Verify and report
Re-read the region or comment you wrote, then confirm both of these:
- It contains one
https://github.com/user-attachments/assets/URL per uploaded file. - It contains no local path, meaning no
./,/Users/,/home/,/tmp/, or.agent/reference.
Remove any local path you find and list its file as not attached (upload failed: <reason>).
attach-media: <N> attached, <S> skipped, <F> not attached — <pr-url>
attached: <file> → <asset-url>
skipped: <file> (<reason>)
not attached: <file> (<reason>) # rung 3 adds: run `gh pr edit <n> --attach <file>` on gh ≥ 2.99Callers relay the first line verbatim.
Hard rules
- Never write placeholder text. That means no
TODO: add screenshots, no<!-- screenshots here -->, no_Screenshots coming soon_, and no local path a reader cannot open. An absent region is honest; a placeholder claims work that never happened. - Never commit media to the repo to get a URL, and never upload to a third-party host. Rationale:
references/rationale.md. - Never upload a file you have not looked at (Step 1, check 4).
- Attach after the PR exists. Never fold
--attachinto a caller'sgh pr create; one code path owns the region, so re-runs and refreshes stay idempotent.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

