NAME
hazelnut โ ๐ฐ Terminal-based automated file organizer inspired by Hazel. Watch folders and organize files with rules.
SYNOPSIS
brew install ricardodantas/tap/hazelnutINFO
DESCRIPTION
๐ฐ Terminal-based automated file organizer inspired by Hazel. Watch folders and organize files with rules.
README
๐ฐ Hazelnut
A terminal-based automated file organizer inspired by Hazel
Watch your folders and automatically organize files based on rules you define โ all from your terminal.
๐ Table of Contents
- โจ Features
- ๐ Quick Start
- โ๏ธ Configuration
- ๐ Rules
- โจ๏ธ Keybindings
- ๐จ Themes
- ๐๏ธ Architecture
- ๐ง Building from Source
- ๐ค Contributing
- ๐ License
โจ Features
๐ Smart File WatchingWatch any folder for new and changed files with configurable debouncing and recursive monitoring. Paths support ๐ฏ Flexible Rules EngineDefine powerful rules with conditions based on name, extension, size, age, and more. Multiple rules can match the same file โ all matching rules execute in order. โก Powerful ActionsMove, copy, rename, delete, archive files or directories, send to trash, or run custom scripts โ all automated. Cross-filesystem moves are handled transparently. |
๐ฅ๏ธ Beautiful TUIA gorgeous terminal interface for managing rules and monitoring activity in real-time. ๐ง Background DaemonSet it and forget it โ the daemon runs quietly and applies rules 24/7. ๐ Simple ConfigurationHuman-readable TOML config that's easy to write and maintain. |
Feature Highlights
| Feature | Description |
|---|---|
| ๐ Pattern Matching | Glob patterns and regex for precise file matching |
| ๐ Size Conditions | Filter files by size (greater than, less than) |
| ๐ Age Conditions | Match files by modification date |
| ๐ท๏ธ Multiple Extensions | Match any of multiple file types |
| ๐ Recursive Watching | Monitor subdirectories automatically |
| ๐จ 15 Built-in Themes | From Dracula to Cyberpunk |
| ๐ Desktop Notifications | Get alerted on errors (cross-platform) |
| ๐ Activity Log | Full history of all file operations |
๐ Quick Start
Installation
macOS
# Homebrew (recommended - fast, pre-built binary)
brew install ricardodantas/tap/hazelnut
Linux
# Homebrew brew install ricardodantas/tap/hazelnutOr via Cargo
cargo install hazelnut
Arch Linux (pacman)
pacman -S hazelnut
Windows
# Via Cargo (requires Rust toolchain) cargo install hazelnutOr download pre-built binary from GitHub Releases:
https://github.com/ricardodantas/hazelnut/releases
From Source
git clone https://github.com/ricardodantas/hazelnut
cd hazelnut
cargo install --path .
Note: The daemon (
hazelnutd) is only available on macOS and Linux. On Windows, only the TUI (hazelnut) is available.
First Run
Hazelnut needs two things to work:
- Watch folders โ which directories to monitor
- Rules โ what to do with files in those folders
โ ๏ธ Important: Rules alone won't do anything! You must also configure at least one watch folder.
- Create a config file at
~/.config/hazelnut/config.toml:
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ # STEP 1: Define which folders to watch # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ [[watch]] path = "/home/youruser/Downloads" # Full path, ~, $HOME all work recursive = false # Set true to include subfoldersโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
STEP 2: Define rules for what to do with files
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
[[rule]] name = "Organize PDFs"
[rule.condition] extension = "pdf"
[rule.action] type = "move" destination = "/home/youruser/Documents/PDFs"
- Launch the TUI to manage and monitor:
hazelnut
- Or start the daemon to run in the background:
hazelnutd start
โ๏ธ Configuration
Hazelnut uses TOML for configuration. The config file is always located at:
~/.config/hazelnut/config.toml
Full Configuration Example
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ # General Settings # โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ[general]
Logging level: trace, debug, info, warn, error
log_level = "info"
Optional log file path
log_file = "~/.local/share/hazelnut/hazelnut.log"
Wait time (seconds) before processing a file after change detected
debounce_seconds = 2
How often to check for file changes (seconds)
polling_interval_secs = 5
Desktop notifications on errors (cross-platform)
notifications_enabled = true
Theme for the TUI
theme = "catppuccin-mocha"
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Watch Folders
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
[[watch]] path = "~/Downloads" recursive = false
[[watch]] path = "~/Desktop" recursive = false
Only apply specific rules to this folder
rules = ["screenshots", "temp-files"]
[[watch]] path = "~/Documents/Inbox" recursive = true # Watch subdirectories too
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Rules
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
[[rule]] name = "Organize PDFs" enabled = true stop_processing = false # Continue checking other rules
[rule.condition] extension = "pdf"
[rule.action] type = "move" destination = "~/Documents/PDFs" create_destination = true overwrite = false
[[rule]] name = "Screenshots" enabled = true
[rule.condition] name_matches = "Screenshot*.png"
[rule.action] type = "move" destination = "~/Pictures/Screenshots"
[[rule]] name = "Clean Old Downloads" enabled = true
[rule.condition] age_days_greater_than = 30 extensions = ["tmp", "log", "bak"]
[rule.action] type = "trash"
See docs/configuration.md for the complete reference.
Watch Editor (TUI)
You can manage watch folders directly in the TUI:
- Add a new watch: Press
aornin the Watches view - Edit an existing watch: Select a watch and press
e - Delete a watch: Select a watch and press
d
The watch editor dialog allows you to configure:
- Path - Path to the folder to watch (supports
~,$VAR,${VAR}, or absolute paths) - Recursive - Whether to include subdirectories
Use Tab to move between fields, Enter to save, and Esc to cancel.
๐ Rules
Rules are the heart of Hazelnut. Each rule has a condition (what files to match) and an action (what to do with them).
Conditions
All conditions in a rule must match for the rule to apply.
File Name
[rule.condition] # Glob pattern matching name_matches = "Screenshot*.png"Regex pattern matching
name_regex = "^invoice_\d{4}\.pdf$"
File Extension
[rule.condition] # Single extension extension = "pdf"Multiple extensions (match any)
extensions = ["jpg", "jpeg", "png", "gif", "webp"]
File Size
[rule.condition]
# Size in bytes
size_greater_than = 10485760 # > 10 MB
size_less_than = 1048576 # < 1 MB
File Age
[rule.condition]
# Age in days (based on modification time)
age_days_greater_than = 30 # Older than 30 days
age_days_less_than = 7 # Newer than 7 days
File Type
[rule.condition]
is_directory = false # Match only files
is_hidden = true # Match hidden files (starting with .)
Actions
Move
[rule.action]
type = "move"
destination = "~/Documents/Archive"
create_destination = true # Create folder if missing
overwrite = false # Don't overwrite existing files
Copy
[rule.action]
type = "copy"
destination = "~/Backup"
create_destination = true
overwrite = false
Rename
[rule.action]
type = "rename"
pattern = "{date}_{name}.{ext}"
Available variables:
| Variable | Description | Example |
|---|---|---|
{name} | Filename without extension | document |
{filename} | Full filename | document.pdf |
{ext} | Extension | pdf (empty if none) |
{path} | Full path | /home/user/document.pdf |
{dir} | Parent directory | /home/user |
{date} | Current date | 2024-01-15 |
{datetime} | Current datetime | 2024-01-15_14-30-00 |
{date:FORMAT} | Custom format | {date:%Y%m%d} โ 20240115 |
Trash
[rule.action]
type = "trash"
Moves files to the system trash (recoverable).
Delete
[rule.action]
type = "delete"
โ ๏ธ Warning: This permanently deletes files!
Run Command
[rule.action]
type = "run"
command = "convert"
args = ["{path}", "-resize", "50%", "{dir}/{name}_small.{ext}"]
Archive
[rule.action]
type = "archive"
destination = "~/Archives"
delete_original = false
Rule Editor (TUI)
You can create and edit rules directly in the TUI without editing the config file:
- Create a new rule: Press
nin the Rules view - Edit an existing rule: Select a rule and press
e - Delete a rule: Select a rule and press
d
The rule editor dialog allows you to configure:
- Name - A descriptive name for your rule
- Enabled - Toggle the rule on/off
- Conditions - Extension, name patterns (glob/regex), size limits, age limits, is_directory, is_hidden
- Action - Move, Copy, Rename, Trash, Delete, Run Command, or Archive
Use Tab to move between fields, Enter to save, and Esc to cancel.
๐ก Remember: Rules only apply to files in watched folders. Make sure you've configured at least one
[[watch]]entry in your config, or add one via the Watches view.
Example Rules
๐ธ Organize Screenshots
[[rule]]
name = "Screenshots to folder"
[rule.condition]
name_matches = "Screenshot*.png"
[rule.action]
type = "move"
destination = "~/Pictures/Screenshots"
๐ Sort Documents by Type
[[rule]]
name = "PDFs to Documents"
[rule.condition]
extension = "pdf"
[rule.action]
type = "move"
destination = "~/Documents/PDFs"
[[rule]]
name = "Spreadsheets to Documents"
[rule.condition]
extensions = ["xlsx", "xls", "csv"]
[rule.action]
type = "move"
destination = "~/Documents/Spreadsheets"
๐๏ธ Clean Old Files
[[rule]]
name = "Delete old temp files"
[rule.condition]
age_days_greater_than = 30
extensions = ["tmp", "log", "bak"]
[rule.action]
type = "trash"
๐ Date-Prefix Invoices
[[rule]]
name = "Prefix invoices with date"
[rule.condition]
name_regex = "^invoice.*\\.pdf$"
[rule.action]
type = "rename"
pattern = "{date:YYYY-MM-DD}_{filename}"
๐ผ๏ธ Compress Large Images
[[rule]]
name = "Compress large images"
[rule.condition]
extensions = ["jpg", "png"]
size_greater_than = 5242880 # > 5 MB
[rule.action]
type = "run"
command = "convert"
args = ["{path}", "-quality", "80", "{path}"]
โจ๏ธ Keybindings
Global
| Key | Action |
|---|---|
Tab | Next view |
Shift+Tab | Previous view |
1 2 3 4 | Jump to view (Dashboard, Rules, Watches, Log) |
s | Open settings |
t | Open theme picker |
A | About Hazelnut |
? / F1 | Show help |
q | Quit (from Dashboard) |
Ctrl+c / Ctrl+q | Force quit |
Navigation
| Key | Action |
|---|---|
โ / k | Move up |
โ / j | Move down |
g / Home | Go to first item |
G / End | Go to last item |
PageUp | Page up |
PageDown | Page down |
Rules View
| Key | Action |
|---|---|
Enter / Space | Toggle rule enabled/disabled |
e | Edit selected rule |
n | Create new rule |
d / Delete | Delete selected rule |
Watches View
| Key | Action |
|---|---|
a / n | Add new watch folder |
e | Edit selected watch |
d / Delete | Delete selected watch |
o / Enter | Open folder |
Log View
| Key | Action |
|---|---|
c | Clear log |
Theme Picker
| Key | Action |
|---|---|
โ / k | Previous theme (with live preview) |
โ / j | Next theme (with live preview) |
Enter | Apply selected theme |
Esc | Cancel |
๐จ Themes
Hazelnut includes 15 beautiful themes based on popular terminal and editor color schemes.
Press t in the TUI to open the theme picker with live preview.
Available Themes
| Theme | Description |
|---|---|
| ๐ฆ Dracula | Dark purple aesthetic (default) |
| ๐ One Dark Pro | Atom's iconic dark theme |
| โ๏ธ Nord | Arctic, bluish color palette |
| ๐ฑ Catppuccin Mocha | Warm pastel dark theme |
| โ Catppuccin Latte | Warm pastel light theme |
| ๐ธ Gruvbox Dark | Retro groove colors |
| ๐ Gruvbox Light | Retro groove, light variant |
| ๐ Tokyo Night | Futuristic dark blue |
| ๐ Solarized Dark | Precision colors, dark |
| ๐ Solarized Light | Precision colors, light |
| ๐จ Monokai Pro | Classic syntax highlighting |
| ๐น Rosรฉ Pine | All natural pine with soho vibes |
| ๐ Kanagawa | Inspired by Katsushika Hokusai |
| ๐ฒ Everforest | Comfortable green forest theme |
| ๐ Cyberpunk | Neon-soaked futuristic theme |
๐๏ธ Architecture
Hazelnut consists of two binaries that work together:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ User โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ hazelnut (TUI) โ
โ โข Manage rules โ
โ โข Monitor activity โ
โ โข Change themes โ
โ โข View logs โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
Unix Socket
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ hazelnutd (Daemon) โ
โ โข Watch folders โ
โ โข Evaluate rules โ
โ โข Execute actions โ
โ โข Run 24/7 in background โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ File System โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
hazelnut โ The TUI
Interactive terminal interface for:
- Viewing and managing rules
- Monitoring watch folders
- Viewing activity logs
- Changing themes
- Sending commands to the daemon
hazelnut # Launch TUI
hazelnut list # List all rules
hazelnut check # Validate config
hazelnut run # Run rules once (dry-run)
hazelnut run --apply # Run rules once (for real)
hazelnut status # Check daemon status
hazelnutd โ The Daemon
Background service that does the actual work:
hazelnutd start # Start daemon (background)
hazelnutd stop # Stop daemon
hazelnutd restart # Restart daemon
hazelnutd status # Show daemon status
hazelnutd reload # Reload configuration (hot-reload, no restart)
hazelnutd run # Run in foreground (for debugging)
Daemon Commands
| Command | Description |
|---|---|
start | Start daemon in background, detached from terminal |
stop | Gracefully stop the daemon (SIGTERM) |
restart | Stop and start the daemon |
status | Show running state, PID, uptime, and log location |
reload | Hot-reload config via SIGHUP (no restart needed) |
run | Run in foreground with live logging (for debugging) |
Status Output
$ hazelnutd status
๐ฐ Hazelnut daemon is running
PID: 12345
PID file: ~/.local/state/hazelnut/hazelnutd.pid
Log file: ~/.local/state/hazelnut/hazelnutd.log
Uptime: 2h 15m 30s
File Locations
All files use consistent paths across Linux and macOS:
| File | Path | Purpose |
|---|---|---|
| Config | ~/.config/hazelnut/config.toml | Rules and settings |
| PID file | ~/.local/state/hazelnut/hazelnutd.pid | Tracks running daemon |
| Log file | ~/.local/state/hazelnut/hazelnutd.log | Daemon activity log |
Typical Workflow
# 1. Edit your rules in the TUI or config file hazelnut2. Start the daemon
hazelnutd start
3. Check it's running
hazelnutd status
4. After editing rules, reload without restart
hazelnutd reload
5. View logs if needed
tail -f ~/.local/state/hazelnut/hazelnutd.log
๐ง Building from Source
Requirements
- Rust 1.93+ (uses Edition 2024 features)
- Linux or macOS
Build
# Clone the repository git clone https://github.com/ricardodantas/hazelnut cd hazelnutBuild release binary
cargo build --release
The binaries will be at:
- target/release/hazelnut
- target/release/hazelnutd
Or install directly
cargo install --path .
Development
# Run TUI in development cargo runRun daemon in foreground
cargo run --bin hazelnutd run
Run tests
cargo test
Run linter
cargo clippy
Format code
cargo fmt
๐ค Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
Quick Start for Contributors
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Run tests:
cargo test - Run clippy:
cargo clippy - Format:
cargo fmt - Commit:
git commit -m "Add amazing feature" - Push:
git push origin feature/amazing-feature - Open a Pull Request
Project Structure
hazelnut/
โโโ src/
โ โโโ main.rs # TUI entry point
โ โโโ daemon.rs # Daemon entry point
โ โโโ lib.rs # Library root
โ โโโ theme.rs # Color themes
โ โโโ app/ # TUI application
โ โ โโโ events.rs # Key event handling
โ โ โโโ state.rs # Application state
โ โ โโโ ui.rs # UI rendering
โ โโโ config/ # Configuration loading
โ โโโ rules/ # Rule engine
โ โ โโโ action.rs # Rule actions
โ โ โโโ condition.rs # Rule conditions
โ โ โโโ engine.rs # Rule evaluation
โ โโโ watcher/ # File system watcher
โ โโโ ipc/ # TUI-daemon communication
โโโ docs/
โ โโโ configuration.md # Full config reference
โโโ screenshots/ # Screenshots for docs
โโโ tests/ # Integration tests
๐ License
This project is licensed under the GPL-3.0-or-later license โ see the LICENSE file for details.
Built with ๐ฆ Rust and โค๏ธ by Ricardo Dantas