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.

Install View on gitea ↗
▸ CleanShot 2026-04-15 at 09.14.07.png
↳ CleanShot · Shamel Studio Affiliate Referral Code Modal · 2026-04-15 at 09.14.07.png
01The problem

## 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.

02The pipeline

## 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`

03An actual rename

## 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.

Plate i · Five real renames · CleanShot · Apple Screenshot · user-keyword
screenshot-rename · run ii · 2026-05-04 · 196 files
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 ✓
04What's new this revision

## Three additions, one mixed run.

A second batch of files surfaced cases the first run never hit: Apple's own Screenshot filenames, user-typed keyword prefixes, and folders where some files were already renamed. The pipeline now handles all three in a single pass — and the parser learned a new gotcha along the way.

a.
imulti-prefix

### CleanShot and Screenshot, in one run.

The parser now accepts both `CleanShot 2026-MM-DD at HH.MM.SS.png` and Apple's `Screenshot 2026-MM-DD at H.MM.SS PM.png`. Mixed folders no longer need two passes — the manifest builder picks up either prefix.

b.
iikeyword preservation

### Hand-typed prefixes survive.

A file named `jojo travel CleanShot 2026-...png` carries user knowledge the AI doesn't have. The parser strips the keyword phrase, title-cases it, and prepends it to the AI description — so the new filename reads Jojo Travel Flight Australia Melbourne Flightaware Map Route.

c.
iiiidempotent re-runs

### Re-running won't stack descriptions.

The parser now detects names already in the `App - Description - timestamp.ext` form and excludes them from the manifest. You can re-run the skill on a partially-renamed folder without the name growing on every pass.

screenshot-rename · run iii · 2026-05-04 · mixed prefixes
source files20
CleanShot14
Apple Screenshot (with U+202F)5
user-prefixed1
already-renamed (skipped)0
plan validated20 renames · 0 errors
file count before / after20 = 20
renames committed20 ✓
files lost0 ✓
05The rules that prevent data loss

## 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 `mv`s 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.
11. Apple Screenshot files use `U+202F`.The narrow no-break space sits between the seconds and AM/PM. Haiku echoes it as ASCII space, the lookup misses, and every Screenshot file is dropped from the plan with a misleading `NO_DESC` error. Normalize on both sides; emit ASCII space in the new name.
12. Re-runs must skip already-renamed files.Without an `^App - .+ - timestamp.ext$` exclusion rule the parser will pile a second AI description into every name on every run. The pipeline detects and excludes them.
13. User-typed keyword prefix is signal.A name like `jojo travel CleanShot ...` carries knowledge the AI doesn't have. Strip the keyword phrase, title-case it, and prepend it to the description before assembly. Don't drop it.

06Use cases

## 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
07A session, end to end

## What it looks like when you ask.

The skill is conversational at the top, mechanical underneath. You ask in plain English; ten Haiku agents fan out in a single round-trip; Python validates the plan and applies it under the file-count audit. The whole thing fits on one page.

Plate ii · A session, end to end · 10 agents · ~3 min · zero loss
08Install & run

## 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"