# FilePilot (CLI prototype)
This is a working prototype of FilePilot's bulk rename engine: regex-based
find/replace renaming and sequential renumbering of files, both with a
collision-safe dry-run-by-default workflow (nothing touches disk until you
pass --apply, and an entire rename batch is validated for name collisions
before a single file is renamed). FilePilot's full product concept is a
dual-pane file manager with an instant launcher/search, live previews, and
configurable rename rule chains; NONE of that is implemented here. Instant
launcher/search is covered by the sibling tool FindPilot. See ../plan.md
for the full product plan and roadmap.
## Build from source
Requires Go 1.24+, no external dependencies.
go build -o filepilot .
Cross-compile for another platform:
GOOS=windows GOARCH=amd64 go build -o filepilot.exe .
GOOS=darwin GOARCH=arm64 go build -o filepilot .
## Usage
filepilot rename
--match "REGEXP" --replace "TEMPLATE" [--recursive] [--apply]
filepilot sequence --pattern "photo-{n}.jpg" [--start 1] [--pad 3] [--sort name|mtime] [--apply]
filepilot help
### rename
Regex find/replace on file basenames.
--match STRING Go regexp matched against each file's BASE NAME (not
full path). Only immediate children of are
considered unless --recursive is given.
--replace STRING Replacement template using Go's regexp
ReplaceAllString syntax: $1, $2, ${name} refer to
capture groups from --match.
--recursive Walk the entire subtree of instead of just its
immediate children.
--apply Actually perform the renames. Without this flag,
filepilot only prints the planned renames (dry run).
For each file whose basename matches --match, FilePilot computes the new
basename by applying --replace, keeping the file in the same directory.
Files whose computed new name is identical to their old name are skipped
as no-ops.
Before renaming anything, FilePilot builds the full list of planned
(old path -> new path) renames and validates it:
- if two different source files would produce the same new path, that
is a COLLISION
- if a planned new path already exists on disk as a file that is not
part of the rename batch itself, that is also a COLLISION
If any collision is found, FilePilot prints every collision it found,
exits nonzero, and renames NOTHING. Only after validation passes with
zero collisions does it either print the dry-run plan (no --apply) or
perform every rename (--apply).
Example:
filepilot rename ./photos --match "IMG_(\d+)\.JPG" --replace "photo_$1.jpg"
filepilot rename ./photos --match "IMG_(\d+)\.JPG" --replace "photo_$1.jpg" --apply
### sequence
Renumbers a batch of files sequentially - the classic "renumber this photo
dump" use case.
--pattern STRING Output name template. The literal token "{n}" is
replaced with the zero-padded counter for each file;
everything else in the pattern is kept as-is. The
file extension is NOT auto-appended - include it
explicitly in the pattern, e.g. "photo-{n}.jpg".
--start INT Starting counter value (default 1).
--pad INT Zero-pad width for the counter (default 3, so
counter 7 with pad 3 becomes "007").
--sort STRING Order files are numbered in: "name" (alphabetical
basename, default) or "mtime" (modification time,
ascending).
--apply Actually perform the renames. Without this flag,
filepilot only prints the planned renames (dry run).
Only files directly inside are considered (non-recursive). Files are
sorted per --sort, then each is assigned the next counter value starting
at --start, zero-padded to --pad digits, substituted for "{n}" in
--pattern.
The same collision-detection-before-any-rename safety as the rename
command applies: a sequence plan will not realistically collide with
itself (counters are unique per file), but a collision with a
pre-existing file outside the batch is still possible and will abort the
whole batch before anything is renamed.
Example:
filepilot sequence ./photos --pattern "photo-{n}.jpg" --start 1 --pad 3 --sort mtime
filepilot sequence ./photos --pattern "photo-{n}.jpg" --start 1 --pad 3 --sort mtime --apply
## Prebuilt binaries
See ../downloads/ for prebuilt binaries (Windows/macOS/Linux) and
CHECKSUMS.txt for their SHA-256 hashes. These are unsigned indie builds -
Windows SmartScreen and macOS Gatekeeper will warn on first run, which is
expected until a code-signing certificate is in place.