Your Downloads folder, ruled by one YAML file.

Rule-based organization from the terminal. Define patterns once in YAML — fo previews every move, then puts every file where it belongs. Watch mode and undo included.

PNG
Screenshot 2026-08-29 at 03.14.png
PDF
invoice-2026-08.pdf
MP4
VID_20260712_194302.mp4
ZIP
archive_final_v2(3).zip
JPG
IMG_2024.jpg
LOG
server_2026-08-30.log
Downloads — fo organize --dry-run
~/Downloads 5 files · 1 conflict
Screenshot 2026-08-29 at 03.14.png screenshots/2026-08/
invoice-2026-08.pdf documents/pdf/2026/
VID_20260712_194302.mp4 video/2026/07/
archive_final_v2(3).zip archives/ (conflict: file exists)
IMG_2024.jpg images/2024/08/

dashed = previewed · solid = moved · doubled = conflict

Install — v0.1.0-rc.1

$git clone https://github.com/PabloJustDevelops/file-organizer-cli && cd file-organizer-cli && bun install && bun run build:cli

Pre-release v0.1.0-rc.1 · API stable · npm name pending — clone & build for now.

Define rules in YAML. Run one command. Files land where they belong.

A single .file-organizer.yaml defines what gets organized where. Conditions add precision: filter by size, date, or regex. Priority controls which rule wins.

patterns

Glob patterns, regex, size thresholds, and date ranges. Combine conditions to target exactly the files you want.

destinations

Variables like {year}, {month}, {extension} build paths from each file's metadata.

dry-run

fo organize --dry-run shows every move without touching anything. Review, then execute.

watch

fo watch ~/Downloads monitors a folder and organizes new files automatically.

undo

fo undo reverts the last operation. History persists between sessions — no surprises, no lost files.

.file-organizer.yaml
~/.file-organizer.yaml YAML
# Define your rules rules: - name: Images patterns: ["*.jpg", "*.png"] destination: "./images/{year}/{month}"   - name: Large files patterns: ["*"] condition: type: size minSize: 10485760
my-plugin.js
plugins: ["./my-plugin.js"] JS
// Plain object, zero imports export default { name: "log-remapper", version: "1.0.0", async transform(file) { return { ...file, extension: file.extension === "log" ? "txt" : file.extension }; },   async beforeOrganize(context) { console.log(context.files.length + " files"); } };

Teach fo new tricks. In plain JavaScript.

A plugin is a plain object with a default export. No imports required. Add lifecycle hooks, custom matching rules, or transforms that remap file metadata before organizing.

A failing plugin never aborts a run: errors are isolated per item and reported in the result. Register it once and it loads before any file is touched.

Full plugin guide →

Nothing moves without your say-so.

fo watch

fo watch ~/Downloads monitors the folder and organizes new files as they arrive. Set it once, forget it.

fo undo

fo undo reverts the last operation — history persists between sessions.

op 0412 4 files moved reversible: ready to undo
op 0411 11 files moved reversible: ready to undo
op 0410 2 files moved undone: already reverted
conflicts

When a destination exists, you choose: rename, overwrite, skip, or newest. The preview marks every collision before anything moves.

Ready to organize?

Stop sorting Downloads by hand.

One config file. One command. Every file in its place.

Install fo