Skill
Batch file renamer for Claude Code. Matches your folder's naming convention, previews changes, logs every batch for undo.
npx -y skills add meturley/rename-by-content --skill skillAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 12 days oldThe repository was created 12 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Batch-rename files based on what is actually inside them, matching the naming convention already used in the destination folder. Use this whenever someone has a pile of files with useless names — IMG_4821.jpg, Screenshot 2026-07-24 at 3.41.02 PM.png, doc(3).docx, Untitled 7.xlsx, scan.pdf — and wants them named properly. Trigger it even when the word "rename" never appears: "I just dumped 40 files in my downloads and have no idea what any of them are", "can you clean up this folder", "sort out these screenshots", "make these match how I name things", "what even is doc(3)", or "I need to file these receipts" all mean this skill. Also use it for a single stubborn file, and for reverting a rename batch that went wrong.
SKILL.md
11.1 KB, ~2.6k tokens by cl100k_base, as published. Nobody here has run it
Rename by content
Someone drags in a folder of files named IMG_4821.jpg, Scan 12.pdf, doc(3).docx. The
information needed to name them well is sitting inside each file. The job is to get it out,
shape it into names that match how this person already names things, and rename in one pass —
without the person having to open forty files to check your work.
Two things make this safe enough to be fast: nothing is renamed until they've seen the diff,
and every batch writes an undo log so a bad call is one command away from being reversed.
rename_batch.py enforces both — it dry-runs unless given --apply, and it writes
.rename_history/ on every apply. Use the script rather than mv for exactly this reason.
Workflow
1. Find the files
Get the target folder. If they said "my downloads" or dragged files in, use those paths. If a
folder holds both files to rename and files already named well, only the badly-named ones are in
scope — inspect_files.py flags these as name_is_uninformative: true, but use judgment: a file
named notes.docx isn't junk-patterned yet still says nothing.
2. Inspect everything in one shot
python3 scripts/inspect_files.py "/path/to/folder" --convention "/path/to/folder"
This returns, per file, the text worth naming from: document body and headers, Office title
metadata, spreadsheet sheet names and header rows, CSV columns, slide text, image dimensions and
EXIF capture date, plus any dates found in the content. It also reports what the folder's existing
filenames look like. Pass files individually if only some are in scope; --convention can point at
a different folder than the files (useful when they're being filed into somewhere).
Run this before opening anything by hand. Forty individual file reads is slow and floods context; the digest is usually all you need.
The output separates facts from advice: everything except agent_notes is data about the files,
and agent_notes maps whichever findings turned up to what to do about them. Read the notes first
to see what needs attention, then go to the data. --no-notes drops the block if you only want
the data. Per-file warnings mean a file parsed partially — a malformed sheet or unreadable
metadata — so treat thin content there as missing rather than as evidence the file is empty.
3. Open what the digest can't reach
Anything listed under requires_opening_directly — images, screenshots, PDFs — needs your eyes.
Read those files directly. This is where screenshots earn their name: a screenshot's entire
identity is what's on screen (the app, the error message, the chart, the conversation), and no
metadata captures it. Read them in parallel batches rather than one at a time.
4. Settle the convention
Check naming_convention in the digest first. If is_user_configured is true, the person has
written down the pattern they want — in .namerules or rename.config.json in the folder, or in
~/.config/rename-by-content/config.json. Follow it exactly. A stated preference outranks anything
you could infer from the filenames, and quietly overriding it is the fastest way to lose their
trust. If they name a different convention in conversation, pass it through instead:
python3 scripts/inspect_files.py "/path/to/folder" --convention "/path/to/folder" \
--format 'YYYY-MM-DD_{type}_{subject}'
If naming_convention.error is set, their config file is broken. Tell them what's wrong in one
line and proceed with the default — don't silently ignore a file they wrote on purpose.
With no configured convention, fall back to what the folder shows. convention.verdict tells you
where you stand:
-
pattern_found— match it. Separator, case, date format and position, roughly how many fields. Read thesample_namesyourself too; the statistics describe the shape but the samples show the vocabulary (do they writeinvoiceorinv?bofaorbank-of-america?). -
weak_patternorinsufficient_evidence— don't reverse-engineer a style out of three inconsistent files. Use the default below and tell them in one line rather than stopping to ask:No clear naming pattern in this folder, so I used
YYYY-MM-DD_subject.ext. Tell me a different convention and I'll redo it.They can redirect after seeing the preview, which costs them nothing. Blocking on a question before they've seen a single result costs them a round trip.
Default convention: YYYY-MM-DD_{type}_{subject}.ext — ISO date first so the folder sorts
chronologically, lowercase, hyphens inside a field, underscores between fields.
If they tell you a convention they want to keep, offer to save it so they only say it once:
echo '{"format": "YYYY-MM-DD_{type}_{subject}", "case": "lower"}' > /path/to/folder/.namerules
Ask before writing the file — it persists, and that's their call to make.
5. Write the names
This is the part that actually matters, and it's judgment, not formatting. The test for a good name: someone scanning the folder six months from now can pick the right file without opening anything.
- Lead with what distinguishes this file from its neighbors. In a folder of forty receipts,
receiptis noise andhome-depot_84-12is signal. Restating the folder's own name in every file wastes the width. - Pick the date the file is about, not the day it landed on disk. Priority: a date in the
content (invoice date, report period, meeting date) > EXIF capture date > filesystem created
date. Content dates come back in
dates_in_content. - A date you don't have is better omitted than faked.
acme-invoice-4821.pdfbeatsunknown-date_acme-invoice-4821.pdf. Never writeunknown,untitled, ormiscinto a name — those are the names you were hired to remove. - Keep proper nouns, drop filler.
bluecross,1420-oak-st,q3-board-deckcarry weight;the,final,v2,copydon't. Aim for roughly 3-8 words. - Keep the extension exactly as it was. Renaming
.jpegto.jpgbreaks links and isn't what was asked. - Two files can describe the same thing. If both genuinely are
2026-03-14_acme-invoice, let the script suffix the second one rather than inventing a distinction that isn't in the file.
Duplicates. inspect_files.py reports identical_files — groups that are byte-for-byte the
same, confirmed by hash rather than guessed from matching sizes. Folders accumulate these silently
(report.pdf alongside report(1).pdf), and surfacing them is often worth more than the renaming
itself. Give the redundant copies the original's name plus _duplicate so they sort adjacent and
can be deleted in one selection. Never delete them yourself — that's a different decision from
renaming, and not the one you were asked to make. Sweeping them into a .duplicates/ subfolder is
a reasonable variation, but ask first: moving files isn't what was approved.
Near-duplicates — same text, different size — are a different animal. Don't invent a version
history you can't see: _v1/_v2 asserts an order you'd be guessing at. Label what's observable
instead, like _full and _text-only for a 712 KB and a 9 KB copy of one memo. A 9 KB .docx
can't hold figures, so that distinction is real; which one came first isn't.
Write the plan to a scratch file:
[
{"path": "/abs/path/IMG_4821.jpg", "new_name": "2026-03-14_receipt_home-depot_84-12.jpg",
"confidence": "high", "reason": "receipt photo, Home Depot header, total $84.12, dated 3/14/26"},
{"path": "/abs/path/doc(3).docx", "new_name": "lease_1420-oak-st_signed.docx",
"confidence": "low", "reason": "lease for 1420 Oak St; no date anywhere in the document"}
]
confidence is high / medium / low and reason is one clause of evidence. Both show up in
the preview so they can zero in on the two files you were unsure about instead of auditing all
forty. Be honest with low — a flagged guess that turns out right costs a glance; an unflagged
guess that turns out wrong costs trust in the whole batch.
6. Preview, then apply
python3 scripts/rename_batch.py --plan plan.json
Show them the diff. Say in one line what convention you used and which files you flagged. Then wait — this is the approval step, and it's the reason the rest can move fast.
On their go-ahead:
python3 scripts/rename_batch.py --plan plan.json --apply
Report what changed and mention the undo is there. If they push back on specific names, edit the plan and re-preview; don't re-inspect the files.
Undo
python3 scripts/rename_batch.py --undo --dir "/path/to/folder" # preview the revert
python3 scripts/rename_batch.py --undo --dir "/path/to/folder" --apply # revert
python3 scripts/rename_batch.py --history --dir "/path/to/folder" # list past batches
Undo reverts the most recent batch that hasn't already been undone. It refuses to revert a file that's been edited or moved since — a stale rollback would be worse than none — and says which files it skipped and why. Repeat to walk further back.
When things are messier than expected
optional_tools_missingin the digest —pdftotextor Pillow isn't installed. Nothing is broken; those files just need opening one at a time instead of reading in bulk. Mention the install command once at the end if it slowed the run down. Don't stop to ask about it.duplicate_check_incomplete— a file couldn't be hashed, so it can't be cleared as unique. Don't state that a folder has no duplicates when this is present; say which files went unchecked.erroron a file — usually a legacy.doc/.xlsor a corrupt download. Open it with Read if it might be text; otherwise leave it out of the plan and mention it. Leaving a file alone is a fine outcome and better than naming it from a guess.- The digest is empty or boilerplate (a scanned page with no text layer, a template with only headers) — look at the file directly before falling back to a generic name.
- Sensitive content. Medical records, pay stubs, legal documents: name them by type and party, not by diagnosis, amount, or case detail. Filenames show up in previews, backups, and shared screens, and are the least private part of any file.
- Very large batches (100+). Inspect all at once — the script is cheap — but preview in the same single table. Splitting the approval into chunks turns one decision into ten.
What ships with it: 3 files
45.7 KB alongside SKILL.md, 3 of them executable
scripts/
- inspect_files.pyruns28.1 KB
- naming_config.pyruns7.6 KB
- rename_batch.pyruns10.0 KB