From gh-file-attach
Upload files to GitHub and get permanent, shareable URLs via the Releases API. Use this skill whenever a file needs a URL for embedding in a PR, issue, commit message, README, or docs. Triggers on "attach", "embed", "share", "host", or "upload" a file to GitHub — with or without a specific file path. When no path is given, scans the project for uploadable media and lets the user choose. Supports explicit PR/issue targeting by number, auto-embeds via gh pr edit, bulk uploads, and storage housekeeping. If a file needs a GitHub-hosted link, use this skill — even if the user doesn't say "attach" explicitly.
How this skill is triggered — by the user, by Claude, or both
Slash command
/gh-file-attach:file-attachThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Get permanent, browser-accessible URLs for files using the GitHub Releases API. This plugin bundles the [`gh-file-attach`](https://github.com/vindu939/gh-file-attach) CLI tool at `${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach`.
Get permanent, browser-accessible URLs for files using the GitHub Releases API. This plugin bundles the gh-file-attach CLI tool at ${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach.
How it works: On first use in a repo, the tool creates a GitHub Release tagged _attachments to host uploaded files. This release appears in the repo's Releases tab — that's expected. All subsequent uploads go into the same release as timestamped assets (e.g. screenshot-20260410-a1b2c3d4.png). It's a storage container, not a code version. You can view and manage all uploads at https://github.com/<owner>/<repo>/releases/tag/_attachments.
gh) v2.0+ must be installed and authenticated with repo scope.gh auth login then gh auth refresh -s repo if scope is missing.If gh-file-attach is not present, the user can install it as a gh extension: gh extension install vindu939/gh-file-attach.
${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach --public -m "Label:path/to/file"
Three things to always include:
--public — without it, the release stays as a draft and URLs won't render in browsers or PR descriptions. Always use for URLs meant to be shared.-m (or --markdown) — produces ready-to-paste markdown with type-aware formatting (see table below)."Label:path" syntax — "Before fix", "Error log from staging", not the raw filename. If no label is given, the filename is used.If a file path itself contains a colon and exists on disk, the tool treats it as a plain path (not label:path).
The -m flag formats output based on what's being uploaded:
| Type | Format | Example |
|---|---|---|
| Images |  | Renders inline |
| Videos | [▶ label](url) | Clickable link |
| Audio | [🔊 label](url) | Clickable link |
| Documents | [📄 label](url) | Clickable link |
| Code | [📝 label](url) | Clickable link |
| Archives | [📦 label](url) | Clickable link |
| Other | [📎 label](url) | Clickable link |
When the user gives an explicit path — "upload /tmp/mockup.png to PR #1244" — skip discovery:
ls -lh <path>. If not, say so and stop.references/discovery-and-formatting.md).# Upload
${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach --public -m "UI mockup – settings page:/tmp/mockup.png"
# Safe embed — mktemp avoids predictable filenames (symlink attacks on shared systems)
tmpfile=$(mktemp /tmp/pr-body-XXXXXX.md)
gh pr view 1244 --json body -q .body > "$tmpfile"
if [ $? -ne 0 ]; then rm "$tmpfile"; echo "ERROR: could not fetch PR body"; exit 1; fi
printf '\n\n## Screenshots\n\n\n' >> "$tmpfile"
gh pr edit 1244 --body-file "$tmpfile"
rm "$tmpfile"
Choose the section heading based on content: "## Screenshots" for images, "## Recordings" for videos, "## Attachments" for mixed types. For issues: gh issue edit <number> --body-file works the same way.
For other targets (READMEs, wikis, docs), print the markdown output and let the user place it — or offer to insert it into the file directly if the file is in the repo.
Never use gh pr edit --body "$(gh pr view ...)" — backticks and $ in the existing body will be interpreted by the shell and corrupt it.
When the user says "add screenshots" or "attach files" without specifying paths, run the full discovery flow.
Read references/discovery-and-formatting.md for the complete flow, including the 5-layer scan, format-aware metadata display, smart labeling, before/after comparison formatting, collapsible sections, and URL verification.
Quick start:
# Full 5-layer scan
bash ${CLAUDE_PLUGIN_ROOT}/skills/file-attach/scripts/scan-media.sh
# Scan a specific directory
bash ${CLAUDE_PLUGIN_ROOT}/skills/file-attach/scripts/scan-media.sh screenshots/
# Before/after screenshots
${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach --public -m "Before fix:before.png" "After fix:after.png"
# Demo recording
${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach --public -m "Demo – dark mode:demo.mp4"
# Logs and data for an issue
${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach --public -m "Crash log:logs/crash.log" "Heap dump:heap.json"
# To a different repo
${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach --public --repo owner/repo -m "Coverage:coverage.html"
# Custom release tag (instead of default _attachments)
${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach --public --tag design-assets -m "Mockup:design.png"
For listing or storage queries ("what have I uploaded?", "how much space?"), just run the relevant command and present results — don't trigger discovery or upload.
# List all uploads (name, size, date)
${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach --list
# Storage breakdown by file type (with GitHub plan limits)
${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach --stats
Cleanup permanently breaks markdown links referencing deleted assets. Before running cleanup, read references/cleanup-safeguards.md and follow the safeguard sequence.
The tool has a built-in confirmation prompt (Proceed? (y/N)) but the safeguard guide adds a dry-run preview and impact analysis on top of that.
# Delete assets older than 30 days
${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach --cleanup 30d
# Keep only the 50 most recent
${CLAUDE_PLUGIN_ROOT}/bin/gh-file-attach --cleanup 50
| Flag | Description |
|---|---|
--public | Publish the release so URLs work in browsers and PRs |
-m / --markdown | Output as type-aware markdown (see format table above) |
-c / --clipboard | Copy output to clipboard |
-r / --repo OWNER/REPO | Target a specific repository |
-t / --tag TAG | Custom release tag (default: _attachments) |
--list | List all uploaded attachments |
--stats | Show storage usage breakdown by type |
--cleanup <Nd|N> | Delete old assets by age (30d) or keep-count (100) |
--version | Print version |
--help | Print full usage |
| Category | Formats | Max size |
|---|---|---|
| Images | PNG, JPG, GIF, WebP, SVG, BMP, ICO, TIFF, AVIF | 50 MB |
| Videos | MP4, MOV, WebM, AVI, MKV | 200 MB |
| Audio | MP3, WAV, OGG, FLAC, AAC, M4A | 50 MB |
| Documents | PDF, DOCX, PPTX, XLSX, XLS, RTF, DOC, ODT, ODS, ODP | 25 MB |
| Code | PY, JS, TS, TSX, JSX, Java, C, CPP, Go, RS, RB, SH, SQL, HTML, CSS, XML, YAML, and more | 10 MB |
| Archives | ZIP, GZ, TGZ, TAR, BZ2, XZ, 7Z, RAR | 50 MB |
| Text/Data | TXT, MD, CSV, TSV, LOG, JSON, TOML, INI, CFG, CONF | 25 MB |
Rejected: executables (.exe, .dmg, .iso, .deb, .rpm) and symlinks.
GitHub repo storage limits: Free/Pro/Team: 5 GB (warning at 1 GB). Enterprise: 100 GB. Release assets count toward total repo size — use --stats to monitor.
| Symptom | Likely cause | Fix |
|---|---|---|
not authenticated / 401 | gh CLI not logged in | gh auth login |
repo scope missing | Token lacks repo scope | gh auth refresh -s repo |
release not found / 404 | First use or insufficient permissions | Check repo write access |
file not found | Wrong path | Verify with ls |
| File rejected | Exceeds type-specific size limit or is an unsupported type (.exe, etc.) | Check limits table; compress if needed |
403 forbidden | No write access | User needs write permission to the repo |
rate limit | Too many uploads | Wait a few minutes |
If the tool exits non-zero and the error isn't listed, surface the full stderr.
references/discovery-and-formatting.md.--public for URLs meant to be shared in PRs, issues, or docs. Without it, the release stays as a draft and URLs may not render. Private repo caution: on private repos, --public may make uploaded files accessible via direct URL even to non-collaborators. Confirm with the user before using on private repos with sensitive content.--list first and reuse existing URLs.references/cleanup-safeguards.md before any cleanup..gitignore for screenshot/recording directories that are now hosted via Releases.git add, offer to upload as Release assets instead.Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
npx claudepluginhub vindu939/gh-file-attach-plugin --plugin gh-file-attach