agentleFS
mthinesmthines/agent-skills/skills/delivery/attach-media/SKILL.md

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

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
  1. Distinctive:

    Put real screenshots and recordings into a GitHub PR or issue, so a reviewer sees the change without running it.

    line 25
  2. Distinctive:

    Every skill that wants media on a PR delegates here, so the upload method lives in exactly one place.

    line 26
  3. Distinctive:

    Check 4 is mandatory because an upload is permanent and visible to everyone who can read the repo.

    line 54
  4. Very specific:

    Remove any local path you find and list its file as not attached (upload failed: <reason>).

    line 95
  5. Very specific:

    Attach after the PR exists: Never fold --attach into a caller's gh pr create.

    line 111

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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]")
ArgumentDefaultMeaning
<pr-or-issue-ref>the current branch's open PRA 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 bodyyesWrite 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>ScreenshotsThe ### 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:

#CheckOn failure
1The file exists and is non-empty.skipped (missing)
2The 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)
2aA 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
3An 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)
4You 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.

RungConditionMethod
1gh pr edit --help lists --attach (gh ≥ 2.99) and gh auth status passesgh pr edit / gh issue edit / gh pr comment with --body-file and one --attach per file
2Rung 1 fails, and a token resolves from gh auth token, $GH_TOKEN, or $GITHUB_TOKENcurl POST to https://uploads.github.com/user-attachments/assets, then write the body over REST
3Neither 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 -->
![Dashboard with the new revenue widget](https://github.com/user-attachments/assets/1f0c…)

<!-- 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:

  1. It contains one https://github.com/user-attachments/assets/ URL per uploaded file.
  2. 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.99

Callers 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 --attach into a caller's gh pr create; one code path owns the region, so re-runs and refreshes stay idempotent.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.