Documentation

Everything you need to know about using Hazelnut to organize your files.

Installation

Homebrew (Recommended)

The easiest way to install Hazelnut on macOS or Linux:

Homebrew
brew install ricardodantas/tap/hazelnut

Cargo

If you have Rust installed, you can use Cargo:

From crates.io
cargo install hazelnut

From Source

Build from source
git clone https://github.com/ricardodantas/hazelnut.git
cd hazelnut
cargo build --release

Requirements

  • Rust 1.93+ (only for Cargo/source installation)
  • Linux or macOS

Quick Start

⚠️ Important: Hazelnut needs two things to work:
  1. Watch folders — which directories to monitor
  2. Rules — what to do with files in those folders
Rules alone won't do anything without at least one watch folder configured!

Get up and running in these steps:

1

Configure watches and rules

Edit ~/.config/hazelnut/config.toml:

# Watch your Downloads folder
[[watch]]
path = "/home/youruser/Downloads"

# Move PDFs to Documents
[[rule]]
name = "Organize PDFs"
[rule.condition]
extension = "pdf"
[rule.action]
type = "move"
destination = "/home/youruser/Documents/PDFs"

💡 Use full paths — the ~ shortcut is not expanded.

2

Start the daemon

The daemon runs in the background, watching folders and applying rules:

hazelnutd start
3

Launch the TUI

Open the terminal interface to manage rules and monitor activity:

hazelnut

Architecture

Hazelnut consists of two main components:

hazelnut

The TUI (Terminal User Interface) for managing rules, viewing logs, and monitoring file organization activity.

hazelnutd

The background daemon that watches folders and applies rules in real-time. Communicates with the TUI via Unix socket.

Config File

Hazelnut uses TOML for configuration. The default location is:

~/.config/hazelnut/config.toml

Here's a complete example configuration:

config.toml
[general]
log_level = "info"
log_file = "~/.local/share/hazelnut/hazelnut.log"
dry_run = false
debounce_seconds = 2

# Watch folders
[[watch]]
path = "~/Downloads"
recursive = false

[[watch]]
path = "~/Desktop"
recursive = false

# Rules
[[rule]]
name = "Move PDFs"
enabled = true

[rule.condition]
extension = "pdf"

[rule.action]
type = "move"
destination = "~/Documents/PDFs"

General Settings

Setting Type Default Description
log_level string "info" Logging level (trace, debug, info, warn, error)
log_file string none Path to log file
dry_run bool false Preview actions without executing
debounce_seconds int 2 Wait time before processing a file

Watch Folders

Configure which directories Hazelnut monitors for changes:

💡 TUI Tip: You can manage watches directly in the terminal interface! Press a to add, e to edit, d to delete.
[[watch]]
path = "/home/user/Downloads"  # Use full paths
recursive = false
rules = []  # Empty = all rules apply
Field Type Default Description
path string required Directory to watch (use full paths, ~ not expanded)
recursive bool false Watch subdirectories
rules array [] Rule names to apply (empty = all)

Watch Editor Keybindings

Key Action
a / n Add new watch folder
e Edit selected watch
d Delete selected watch

Conditions

All conditions must match for a rule to apply. Omit conditions you don't need.

File Name

[rule.condition]
name_matches = "Screenshot*.png"  # Glob pattern
name_regex = "^invoice_\\d+\\.pdf$"  # Regex pattern

File Type

[rule.condition]
extension = "pdf"  # Single extension
extensions = ["jpg", "jpeg", "png", "gif"]  # Multiple
is_directory = false
is_hidden = true  # Files starting with .

File Size

[rule.condition]
size_greater_than = 10485760  # > 10 MB (in bytes)
size_less_than = 1048576  # < 1 MB

File Age

[rule.condition]
age_days_greater_than = 30  # Older than 30 days
age_days_less_than = 7  # Newer than 7 days

Actions

Move

[rule.action]
type = "move"
destination = "~/Documents/PDFs"
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 pattern variables:

  • {name} - Filename without extension
  • {filename} - Full filename
  • {ext} - Extension
  • {path} - Full path
  • {dir} - Parent directory
  • {date} - Current date (YYYY-MM-DD)
  • {datetime} - Current datetime
  • {date:FORMAT} - Custom date format

Trash / Delete

[rule.action]
type = "trash"  # Safe, recoverable

# Or permanently delete (⚠️ dangerous!)
type = "delete"

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

Examples

Organize Screenshots

[[rule]]
name = "Screenshots"

[rule.condition]
name_matches = "Screenshot*.png"

[rule.action]
type = "move"
destination = "~/Pictures/Screenshots"

Clean Old Downloads

[[rule]]
name = "Clean old downloads"

[rule.condition]
age_days_greater_than = 30
extensions = ["tmp", "log", "bak"]

[rule.action]
type = "trash"

Sort Media Files

[[rule]]
name = "Sort Images"

[rule.condition]
extensions = ["jpg", "jpeg", "png", "gif", "webp"]

[rule.action]
type = "move"
destination = "~/Pictures/Unsorted"

[[rule]]
name = "Sort Videos"

[rule.condition]
extensions = ["mp4", "mov", "avi", "mkv"]

[rule.action]
type = "move"
destination = "~/Videos/Unsorted"

Date-Prefix Invoices

[[rule]]
name = "Date prefix invoices"

[rule.condition]
name_matches = "invoice*.pdf"

[rule.action]
type = "rename"
pattern = "{date:YYYY-MM-DD}_{name}.{ext}"

TUI Overview

The TUI provides a beautiful interface for managing Hazelnut. Launch it with:

hazelnut

Keyboard Shortcuts

Navigation

Key Action
? Show help
q Quit
1-4 Switch tabs (Dashboard, Rules, Watches, Log)
Tab Next tab
j/k or ↑/↓ Navigate list
g/G Go to first/last item

Rules View

Key Action
n Create new rule
e Edit selected rule
d Delete selected rule
Enter / Space Toggle rule enabled/disabled

General

Key Action
t Open theme picker
s Open settings
A About dialog

Watches View

Key Action
a / n Add new watch
e Edit selected watch
d Delete selected watch

Rule Editor / Watch Editor

Key Action
Tab Next field
Shift+Tab Previous field
Enter Save
Esc Cancel