slugr - a tiny file renaming tool
February 26, 2026I released slugr tonight. It’s a small Rust CLI with almost no deps that renames files and directories into clean, URL-safe slugs. My Résumé (Final).pdf becomes my-resume-final.pdf. That’s basically it.
I built it because I kept running into the same annoyance. Downloads folder full of Screen Shot 2024-01-15 at 3.42.17 PM.png and Invoice (2) FINAL final.pdf and whatever other garbage macOS and the web conspire to produce. I sometimes want to work with these files in the shell and it’s a PITA to escape them, or if I wanted to cleanup a bunch with a sequence of shell one-liners it’s also a PITA since I can never quite remember the incantations and I’m terrified I’ll make a mistake or heaven forbid there’s a shell escape in a filename.. Seemed like a thing that should just exist as a tool.
The core of it is a library crate called fileslug that understands filenames. Most slug libraries are built for URLs and will happily turn archive.tar.gz into archive-tar-gz, which is obviously not what you want. fileslug knows about compound extensions, dotfiles, version numbers (app-1.2.3.dmg stays app-1.2.3.dmg), and all the weird edge cases that I could come up when you’re actually renaming files on disk. It does unicode transliteration via any_ascii so your CJK and accented filenames get sensible ASCII equivalents. Or pass --keep-unicode if you’d rather just normalize the separators.
Dry-run is the default, which feels important for a tool that renames your files. You see what it would do, and then pass -x when you’re happy. It won’t clobber existing files (appends -2, -3, etc. instead), handles case-only renames correctly on macOS’s case-insensitive filesystem, and does recursive directory renames bottom-up so paths don’t break mid-traversal. The kind of stuff that’s boring to describe but annoying to get wrong.
$ slugr "My Résumé (Final).pdf" "Photo 2024_01.JPG"
slugr: dry-run mode (use -x to execute)
My Résumé (Final).pdf -> my-resume-final.pdf
Photo 2024_01.JPG -> photo-2024-01.JPG It supports kebab-case (default), snake_case, and camelCase. The whole thing is about 3,000 lines of Rust across both crates with 250 tests. Available via cargo install slugr, brew install vmunix/tap/slugr, or pre-built binaries for macOS and Linux.
This was another fun project built almost entirely with Claude Code. The whole thing from first commit to published crate took an evening. I still think it’s crazy to rely on these tools too much for “real” projects where you want to be able to reason about the architecture and so on, but for stuff like this I love it.