screenshot-rename
A claude code skill · vision-described renames

A folder
of timestamps,
turned into a manifest.

Two hundred screenshots, all named CleanShot 2026-04-15 at 09.14.07.png. Run this skill: ten Haiku subagents read each one in parallel, write a six-to-eight word description, and rename the file in place — atomically, with the safety nets the author cost himself four files to learn.

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

You can't find a screenshot you took six months ago.

  • CleanShot 2025-09-26 at 16.27.39.png
  • CleanShot 2025-11-19 at 13.12.36.png
  • CleanShot 2025-12-05 at 11.24.33.png
  • CleanShot 2026-02-18 at 12.48.31.png
  • CleanShot 2026-03-04 at 06.13.44.png
  • CleanShot 2026-03-17 at 22.10.20.mp4
  • CleanShot 2026-03-21 at 11.46.42.png
  • CleanShot 2026-04-08 at 12.09.10.png
  • …and 187 more

A timestamp tells you when a screenshot exists. It doesn't tell you what's in it. Spotlight indexes the pixels reluctantly; iCloud-synced folders less reliably still. The only way most people find an old screenshot is by remembering, roughly, what they were doing the week they took it — and scrolling.

The real cost isn't filesystem clutter. It's the screenshots you stopped taking, because past you knew future you wouldn't be able to surface them.

196 →

files renamed in the first run that motivated this skill, in three minutes, with zero loss after the second pass. The first pass cost four files. That's why the safety rules below are written the way they are.

Four stages, in two minutes.

The skill does as little as possible, and validates as much as possible. Subagents handle the work that benefits from parallelism (vision); Python handles the work that benefits from being correct (filename mutation, collision detection, the actual os.rename).

Stage 01

Prep.

Extract the first frame from every .mp4 and .pdf. Resize every image to 1568px max — Read's image cap is real. Build a manifest TSV.

ffmpeg · sips · /tmp/screenshot-rename/full-batch-NN

Stage 02

Describe.

Dispatch one Haiku subagent per batch, in parallel — ten at a time. Each agent reads its 19 images and writes 6–8 word descriptions to desc-full-NN.tsv.

model · "haiku" · ~$0.30 / 200 files

Stage 03

Plan.

Aggregate. Validate every line: 6+ words, alnum only, source exists, target doesn't, no plan-internal collisions. Build the full rename map in memory.

plan-full.tsv · zero-error policy

Stage 04

Execute.

One os.rename per row, with pre-existence check. Audit len(listdir) before and after — it must be equal. That equality is your only proof no overwrites happened.

before == after · ok / fail

Before a timestamp.
After, a sentence.

A real rename from the run that motivated this skill. The description was generated by Haiku in roughly two seconds.

Before
CleanShot 2026-03-17 at 22.10.20.mp4
Length36 chars
Searchableby date only
Tells youwhen
After
CleanShot · Claude Conversation About Context Calculator Implementation · 2026-03-17 at 22.10.20.mp4
Length91 chars
Searchableby content + date
Tells youwhat, when

The original timestamp survives unchanged. Sorting still works. The description sits between, set off by em-dashes.

screenshot-rename · run log · 2026-05-04
source files196
resized to 1568px196
frames extracted (mp4 / pdf)9
batches dispatched10 · parallel
haiku descriptions returned196
plan validated189 renames · 0 errors
plan collisionsnone
file count before195
file count after195
renames committed189 ✓
files lost0 ✓

Every rule below was paid for.

During development, four files were destroyed by a one-line bash mistake. Each rule names the failure mode that earned its place. None are aspirational.

  1. Resize before vision.Retina screenshots exceed Read's image cap. Use sips -Z 1568 -s format jpeg first. The agent will fail mid-batch otherwise.
  2. Frames, not videos.The vision tool can't read .mp4 or multi-page .pdf. Extract a frame with ffmpeg -ss 1 -frames:v 1 and describe that.
  3. Never trust bash regex on filenames.zsh's [[ =~ ]] does not populate BASH_REMATCH. Pattern silently fails, target name is empty, multiple mvs collide. Use Python.
  4. mv overwrites silently.One off-by-one in target construction destroys data with no error. Use mv -n in shell, or os.rename after an os.path.exists check in Python.
  5. Plan the full rename in memory first.Build every (src, dst) tuple. Verify each dst is unique, doesn't exist, and corresponds to a real src. Then mutate disk.
  6. File-count audit, every time.len(listdir(DEST)) before and after must be equal. Inequality is the only evidence of silent loss you'll get.
  7. iCloud snapshots are stubs, not bytes.Files in a Time Machine local snapshot inside an iCloud-synced tree are file-provider stubs. cat them and the read times out. Real recovery comes from external backups.
  8. Run renames foreground.Bash run_in_background with while read may exit early with no progress. Run via Python in the same shell — os.rename is just a syscall.
  9. Validate the filename column.Haiku occasionally returns the resized .jpg name instead of the original .png. The plan-builder must try alternate extensions when the claimed source isn't found.
  10. Preserve the original extension.The pipeline reads from a resized JPEG but renames the original .mp4 / .pdf. Write the source extension back into the new name.

What this looks like in practice.

The skill earns its keep when "Spotlight will find it" stops being true. Four scenarios where it has.

A · Archive

An audit of a year of work.

Run the skill on a ~year-old screenshot folder. The output is a chronologically-sorted narrative of what you were thinking about, week by week — readable from the filename column in Finder. No app needed.

CleanShot · Synqora Audit Context Calculator Discussion Continued · 2026-03-15 at 08.08.29.png
B · Recall

"Find the screenshot of the bug from last March."

Renaming once buys you free-text search forever. mdfind "synqora session load" surfaces the right file in a fraction of a second, with no manual tagging.

CleanShot · Synqora Session Load Failed Disconnect Reconnecting Error · 2026-04-18 at 13.37.12.png
C · Onboarding

Designer joins. Hands them the folder.

Instead of curating a deck of "what we've shipped this quarter," point them at the renamed screenshot folder. The filenames are the deck. Categorize by app, by feature, by timeline — the descriptions are already there.

CleanShot · Xcode Preview Swiftui Render Table Comparison Tools · 2026-03-21 at 10.47.26.png
D · Memory

A searchable design memory.

Pair with a periodic re-run on new captures. The folder becomes a queryable artifact: every screenshot you took, with what was in it, in plain text, in the filesystem you already use. No new tool to adopt.

CleanShot · Storyboard Browser With Harry Bridges 1933 Rally Shots · 2026-05-03 at 07.58.27.png

Three commands, one folder.

The skill installs as a Claude Code skill. Once cloned into ~/.claude/skills/, it activates automatically when you ask Claude to rename a screenshot folder. It can also be driven from the command line.

install# clone into your Claude Code skills directory
git clone https://gitea.tojo.team/cardinale/screenshot-rename.git \
       ~/.claude/skills/screenshot-rename

Driven by Claude Code

Open Claude Code in any project and say it conversationally. The skill activates from its description and runs the workflow end to end.

claude code> rename all the cleanshots in
  ~/Documents/Screenshots/
  based on their content.

Driven directly from the shell

For folders too large for a single session, run each stage by hand. Dispatch the Haiku subagents from a Claude Code session in between.

clipython3 pipeline.py prep    --src "./shots"
# dispatch one haiku agent per batch...
python3 pipeline.py plan    --src "./shots"
python3 pipeline.py execute --src "./shots"