Files
screenshot-rename/README.md
T
Anthony Cardinale 0728ae6592 docs: enhance README and homepage with two screenshot plates
- Add assets/before-after.png — Plate i: five real renames laid out as a
  typeset table; mulberry highlight on the description segment; visual
  callouts for the U+202F gap and the user-keyword preservation case
- Add assets/session.png — Plate ii: editorial paper frame around an
  ink-dark Claude Code session card showing user prompt, claude
  orchestration, parallel Haiku fan-out across ten batches, and the run
  receipt
- Keep the source HTMLs (assets/{before-after,session}.html) so the
  plates can be regenerated via headless Brave at 1600x1100
- README.md rewritten: centered hero with embedded plate i, dedicated
  "A session, end to end" section embedding plate ii, new highlights
  (multi-prefix, idempotent), new "What the parser accepts" table,
  gotchas extended to 13, real-world impact promoted to a 3-row table
- docs/index.html surgically extended (existing editorial CSS preserved):
  new .plate and .additions components, nav gets what's-new and session
  links, new section 04 "What's new" with three additions cards plus a
  run-iii receipt, original receipt relabeled run-ii, gotchas list
  extended with #11-13, new section 07 "The session" embedding plate ii,
  install renumbered to 08
- Image refs in docs/index.html use absolute gitea raw URLs so they
  resolve when served from gitea pages or viewed locally

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 11:14:12 -04:00

6.7 KiB

screenshot-rename

A Claude Code skill that turns a folder of timestamp-named screenshots
into a folder of human-readable, searchable filenames —
using parallel Haiku vision agents.

Homepage  ·  SKILL.md  ·  pipeline.py  ·  MIT


Before / after — five real renames, including U+202F handling and user-keyword preservation

CleanShot 2026-04-15 at 09.14.07.png
   ↓
CleanShot - Shamel Studio Affiliate Referral Code Modal - 2026-04-15 at 09.14.07.png

Built for CleanShot-style screenshot folders, but works on any directory of .png / .gif / .mp4 / .pdf files named only by timestamp. Recognizes both CleanShot ... and Apple Screenshot ... filenames in the same pass, preserves any leading user-typed keyword prefix, and is safe to re-run on a folder that's already partially renamed.

Highlights

  • Parallel — describes ~200 files in 3 minutes using 10 concurrent Haiku subagents.
  • Safe — pre-builds the full rename plan in memory, validates uniqueness and target collisions, then renames atomically with a file-count audit. Designed after losing 4 files to a mv overwrite during prototyping.
  • Multi-prefix — same pipeline handles CleanShot ..., Apple Screenshot ..., and files with hand-typed leading keywords (e.g. jojo travel CleanShot ...).
  • Idempotent — re-running on a folder skips files already in the renamed App - Description - timestamp.ext form. No description-stacking.
  • Handles video / PDF — extracts the first frame so vision agents can describe them.
  • Resizes for the vision tool — Retina screenshots exceed Read's image cap; pipeline downsamples to 1568 px max.

A session, end to end

Claude Code session — user prompt, parallel Haiku fan-out across ten batches, receipt of the run

The skill activates when you ask Claude conversationally. Behind the scenes it preps the folder, fans out ten Haiku agents in a single round-trip, validates the resulting plan, then applies the renames in a single Python pass with a file-count audit at the end.

Installation

This is a Claude Code skill. Drop the repo into ~/.claude/skills/:

git clone https://gitea.tojo.team/cardinale/screenshot-rename.git \
  ~/.claude/skills/screenshot-rename

In your next Claude Code session, ask:

rename all the cleanshot files in ~/Documents/Screenshots/ based on their content

The skill will activate automatically from its description.

Usage from the command line

You can also drive the pipeline directly:

# 1. Prep — extract frames, resize, build batches
python3 pipeline.py prep --src "/path/to/folder" --batch-size 19

# 2. (In a Claude Code session, dispatch one Haiku subagent per
#     /tmp/screenshot-rename/full-batch-NN file using the prompt template
#     in SKILL.md.)

# 3. Plan — aggregate descriptions, validate, build rename map
python3 pipeline.py plan --src "/path/to/folder"

# 4. Execute — apply the plan, audit file count
python3 pipeline.py execute --src "/path/to/folder"

The dispatch step (#2) currently requires a Claude Code session.

What the parser accepts

Form Recognized Becomes
CleanShot 2026-MM-DD at HH.MM.SS.png yes CleanShot - <description> - 2026-MM-DD at HH.MM.SS.png
Screenshot 2026-MM-DD at H.MM.SS PM.png (with U+202F) yes — U+202F normalized to ASCII space Screenshot - <description> - 2026-MM-DD at H.MM.SS PM.png
<keywords> CleanShot 2026-MM-DD at HH.MM.SS.png yes — keywords title-cased and prepended to the AI description CleanShot - <Keywords + description> - 2026-MM-DD at HH.MM.SS.png
App - <description> - 2026-MM-DD at HH.MM.SS.png already renamed → skipped (unchanged)

The gotchas this skill encodes

This skill exists because every one of these caused real damage during development:

  1. The Read tool has an image-size cap. Resize first.
  2. Vision can't read .mp4 or multi-page .pdf directly. Extract a frame.
  3. Bash regex [[ =~ ]] does NOT populate BASH_REMATCH in zsh. Targets become empty. Loops collide on the same filename. Files vanish. Use Python for any filename mutation.
  4. mv silently overwrites. Use mv -n or os.rename with explicit pre-existence check.
  5. Pre-build the entire rename plan in memory and validate uniqueness before any mv.
  6. Audit len(os.listdir(DEST)) before and after. Equal count == proof no overwrites.
  7. iCloud-synced files in Time Machine local snapshots are file-provider stubs, not bytes. External backups (Backblaze, Time Machine to physical disk) are the real recovery source.
  8. Bash run_in_background may exit early on while read loops. Run renames foreground via Python.
  9. Haiku occasionally returns the resized .jpg filename instead of the original .png. Validator must try alt extensions.
  10. Always preserve the original .mp4 / .pdf extension — describe via the extracted frame, rename the source.
  11. macOS Screenshot filenames contain U+202F (NARROW NO-BREAK SPACE) before AM/PM. Haiku echoes it as ASCII space, so a verbatim filename lookup misses every Screenshot file. Normalize on both sides of the lookup; emit ASCII space in the new name.
  12. Re-running is only safe if the parser skips already-renamed files. Detect ^App - .+ - timestamp.ext$ and exclude.
  13. Leading user-typed keyword prefix is signal, not noise. Title-case the keywords and prepend them to the AI description before assembling the new name.

The full discussion is in SKILL.md.

Real-world impact

Run Files What happened
1 196 CleanShot Lost 4 to the bash-regex-in-zsh gotcha (#3).
2 196 CleanShot Rebuilt with Python and mv -n — 189 renamed cleanly, zero loss.
3 20 mixed (CleanShot + Apple Screenshot + one user-prefixed) First plan attempt dropped every Screenshot file with a misleading NO_DESC error. Diagnosed the U+202F gotcha (#11) via repr() of the live filename. After adding U+202F normalization, multi-prefix support, and keyword preservation — all 20 renamed in one pass.

Roadmap

  • Direct Anthropic API mode (no Claude Code session required) — needs ANTHROPIC_API_KEY
  • Custom prompt templates per-folder
  • Optional preservation of dots in technical strings (v2.1 currently becomes V21)
  • Dry-run flag on execute

License

MIT — see LICENSE.