Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

autotidy

autotidy

Automatically organize files using declarative rules

About

autotidy is a cross-platform file organization daemon. Define rules in YAML, and it watches your folders for changes, moving, renaming, or organizing files as they appear.

  • Automatic - Runs in the background, watching directories. Triggers your rules when contents change.
  • Declarative - Define your rules in YAML. No code required.
  • Filters - Match files by name, extension, size, date, MIME type, file type.
  • Actions - Move, copy, rename, delete, and trash files that pass your filters.
  • Standalone - Standalone compiled binary. No runtime dependencies.
  • Dry-run - Preview what your config would do before running it with autotidy run.
  • Cross-platform - Linux, macOS, Windows (experimental)
  • Open source - MIT licensed

Quick Start

1. Install

See Installation

2. Verify installation

Verify autotidy is installed and running.

❯ autotidy status
status      🟢 running
config      ~/.config/autotidy/config.yaml
watching    none
rules
  ⚠ none

3. Create your first rule

Edit ~/.config/autotidy/config.yaml:

rules:
  - name: Organize PDFs
    locations: ~/Downloads
    filters:
      - extension: pdf
    actions:
      - move: ~/Documents/PDFs

4. Dry run your rule

Use autotidy run to preview what your rules would do without making changes:

❯ autotidy run
Dry-run mode enabled (pass --dry-run=false to perform a one-off run of all rules)

━━━ Rule: Clean up Desktop images ━━━
~/Downloads/document.pdf
├── filters:
│   └── extension:     ✓
└── actions:
    └── move:          ✓ → ~/Documents/PDFs

5. Reload your rules

Tell the daemon to pick up your config changes:

❯ autotidy reload
Reloaded ~/.config/autotidy/config.yaml

Then verify your rule is active:

❯ autotidy status
status      🟢 running
config      ~/.config/autotidy/config.yaml
watching    1 directories
rules
  🟢 Organize PDFs
    last run: 1 hour ago (2ms, 1 files)

Your rule is now running. Any PDFs added to ~/Downloads will be moved to ~/Documents/PDFs.

Next steps

Installation

Choose your platform:

Linux

Install

curl -fsSL https://raw.githubusercontent.com/prettymuchbryce/autotidy/master/install/linux/install.sh | sh

This downloads the latest release, installs it to ~/.local/bin, sets up a systemd user service, and starts the daemon.

Verify

autotidy status

Note: If autotidy is not recognized, restart your shell or run: export PATH="$HOME/.local/bin:$PATH"

Service management

# Check status
systemctl --user status autotidy

# View logs
journalctl --user -u autotidy -f

# Restart
systemctl --user restart autotidy

# Stop
systemctl --user stop autotidy

Uninstall

curl -fsSL https://raw.githubusercontent.com/prettymuchbryce/autotidy/master/install/linux/uninstall.sh | sh

Alternative: deb/rpm packages

You can also install via .deb or .rpm packages from GitHub Releases:

# Debian/Ubuntu
sudo dpkg -i autotidy_*.deb
systemctl --user enable --now autotidy

# Fedora/RHEL
sudo rpm -i autotidy-*.rpm
systemctl --user enable --now autotidy

macOS

Homebrew

brew install prettymuchbryce/tap/autotidy
brew services start autotidy

Verify

autotidy status

Service management

# Stop
brew services stop autotidy

# Restart
brew services restart autotidy

# View logs
tail -f /tmp/autotidy.out.log
tail -f /tmp/autotidy.err.log

Uninstall

brew services stop autotidy
brew uninstall autotidy

Windows

Note: Windows support is experimental. Please open an issue if you run into problems.

Install

irm https://raw.githubusercontent.com/prettymuchbryce/autotidy/master/install/windows/install.ps1 | iex

This downloads the latest release, installs it to %LOCALAPPDATA%\autotidy, registers it to start at login, and starts the daemon.

Verify

& "$env:LOCALAPPDATA\autotidy\autotidy.exe" status

Service management

# Check if running
Get-Process -Name "autotidy" -ErrorAction SilentlyContinue

# Stop
Stop-Process -Name "autotidy" -Force

# Start
Start-Process -FilePath "$env:LOCALAPPDATA\autotidy\autotidy.exe" -ArgumentList "daemon" -WindowStyle Hidden

Uninstall

irm https://raw.githubusercontent.com/prettymuchbryce/autotidy/master/install/windows/uninstall.ps1 | iex

Nix

autotidy provides a Nix flake with modules for NixOS, nix-darwin, and home-manager.

home-manager

Works on both Linux and macOS:

{
  inputs.autotidy.url = "github:prettymuchbryce/autotidy";

  # Add to your home-manager modules:
  imports = [ inputs.autotidy.homeModules.default ];

  services.autotidy.enable = true;
}

NixOS

{
  inputs.autotidy.url = "github:prettymuchbryce/autotidy";

  # Add to your NixOS modules:
  imports = [ inputs.autotidy.nixosModules.default ];

  services.autotidy.enable = true;
}

nix-darwin

{
  inputs.autotidy.url = "github:prettymuchbryce/autotidy";

  # Add to your darwin modules:
  imports = [ inputs.autotidy.darwinModules.default ];

  services.autotidy.enable = true;
}

Verify installation

autotidy status

Configuration

Configuration for autotidy can be found at the following location:

platformpath
Linux~/.config/autotidy/config.yaml
macOS~/.config/autotidy/config.yaml
Windows%APPDATA%\autotidy\config.yaml

Example

# Moves PDFs and Word docs from Downloads/Desktop to ~/Documents
# organized by extension
rules:
  - name: Organize Downloads
    locations:
      - ~/Downloads
      - ~/Desktop
    filters:
      - extension: [pdf, doc, docx]
    actions:
      - move: ~/Documents/${ext}

Reference

Hot Reload

The autotidy daemon supports hot-reloading of configuration:

autotidy reload

Rules

Each rule defines directories (locations) to be watched. When the contents of those locations change, the containing files which match the filters will have the actions applied against them sequentially.

By default, rules evaluate both files and directories. Use the file_type filter to limit to one or the other.

# Trashes files (not directories) in ~/Downloads that haven't been modified in 30 days
rules:
  - name: Clean Old Downloads
    locations: ~/Downloads
    filters:
      - file_type: file
      - date_modified:
          before:
            days_ago: 30
    actions:
      - trash

Properties

propertytypedefaultdescription
namestringrequiredRule identifier (shown in logs and status)
enabledbooltrueWhether the rule is active
recursiveboolfalseProcess subdirectories
traversalstringdepth-firstdepth-first or breadth-first
locationsstring/listrequiredDirectories to watch
filterslist-Filter expressions
actionslistrequiredActions to execute

Locations

Locations can be a single path or a list:

# Single location
locations: ~/Downloads

# Multiple locations
locations:
  - ~/Downloads
  - ~/Desktop

Filters

Filters determine which files are processed. Filters are AND’d together by default.

# Matches PDFs that haven't been modified in 30 days
filters:
  - extension: pdf
  - date_modified:
      before:
        days_ago: 30

Use any: for OR logic and not: for negation:

# Matches PDFs or Word documents, excluding any with "_backup" in the name
filters:
  - any:
      - extension: pdf
      - extension: [doc, docx]
  - not:
      - name: "*_backup*"
operatorbehavior
(default)All filters must match (AND)
any:At least one child must match (OR)
not:None of the children must match

See Filters for all available filter types.

Actions

Actions are executed in order for each matching file:

# Logs the file, renames it with a "_backup" suffix, then moves it to ~/Archive
actions:
  - log: "Processing ${name}"
  - rename: "${name}_backup${ext}"
  - move: ~/Archive

See Actions for all available action types.

Recursive

By default, rules only process files directly in the specified locations. Set recursive: true to also process files in subdirectories.

# Moves all PDFs from ~/Downloads and its subdirectories to ~/Documents/PDFs
rules:
  - name: Organize All Downloads
    locations: ~/Downloads
    recursive: true
    filters:
      - extension: pdf
    actions:
      - move: ~/Documents/PDFs

Note: Recursion is depth-first by default. This means children are processed before their parents.

Traversal

When recursive: true, the traversal option controls the order files are processed:

  • depth-first (default) - processes deepest files first, then works upward
  • breadth-first - processes files at each level before going deeper
# Deletes empty directories in ~/Downloads, processing deepest folders first
rules:
  - name: Clean Empty Folders
    locations: ~/Downloads
    recursive: true
    traversal: depth-first
    filters:
      - file_type: directory
    actions:
      - delete

Note: Using breadth-first when moving, renaming, or copying a directory will result in subsequent actions being performed on the moved/renamed/copied contents.

Filters

Filters determine which files or directories are processed by a rule. They are specified in the filters section of a rule.

Available filters

filterdescription
nameMatch by filename (glob or regex)
extensionMatch by file extension
file_sizeMatch by file size
file_typeMatch by type (file, directory, symlink)
date_modifiedMatch by modification time
date_accessedMatch by access time
date_createdMatch by creation time
date_changedMatch by metadata change time
mime_typeMatch by MIME type

Filter logic

Filters are AND’d together by default. Use any: for OR logic and not: for negation.

# All filters must match (AND)
filters:
  - extension: pdf
  - date_modified:
      before:
        days_ago: 30

# At least one must match (OR)
filters:
  - any:
      - file_size: "> 100mb"
      - date_modified:
          before:
            days_ago: 30

# None must match (NOT)
filters:
  - not:
      - name: "*.tmp"
operatorbehavior
(default)All filters must match (AND)
any:At least one child must match (OR)
not:None of the children must match

Both any: and not: can be nested for complex boolean expressions.

Examples

Match all files (not directories)

filters:
  - file_type: file

Match specific file types

filters:
  - extension: [jpg, png, gif]

Match files by name pattern

filters:
  - name: "Screenshot*"

Match large files

filters:
  - file_size: "> 100mb"

Match old files

filters:
  - date_modified:
      before:
        days_ago: 30

Match old or large files (OR)

filters:
  - any:
      - file_size: "> 100mb"
      - date_modified:
          before:
            days_ago: 30

Match old PDFs (AND)

filters:
  - extension: pdf
  - date_modified:
      before:
        days_ago: 30

Exclude temp files (NOT)

filters:
  - not:
      - extension: [tmp, temp, bak]

Complex: (old OR large) AND documents AND NOT backup

filters:
  - any:
      - file_size: "> 100mb"
      - date_modified:
          before:
            days_ago: 90
  - extension: [pdf, doc, docx]
  - not:
      - name: "*_backup*"

name

Matches files by filename using glob patterns or regular expressions.

Syntax

# Glob pattern (shorthand)
- name: "*.txt"

# Glob pattern (explicit)
- name:
    glob: "report_*.pdf"

# Regular expression
- name:
    regex: "^file_\d{4}\.txt$"

Options

optiontypedescription
globstringGlob pattern to match
regexstringRegular expression pattern

Only one of glob or regex can be specified.

Glob patterns

The glob pattern is matched against the base filename only (not the full path).

patternmatches
*Any sequence of characters
?Any single character
[abc]Any character in the set
[a-z]Any character in the range
**Any path (in glob context)

Examples

Match all text files

- name: "*.txt"

Match files starting with “report”

- name: "report*"

Match files with numbers in name

- name:
    regex: ".*\d+.*"

Match screenshot files

- name: "Screenshot*"

Exclude hidden files (macOS)

filters:
  - not:
      - any:
          - name: ".*"
          - name: .DS_Store

extension

Matches files by their file extension.

Syntax

# Single extension
- extension: pdf

# With dot (also works)
- extension: .pdf

# Multiple extensions
- extension: [pdf, doc, docx]

# Explicit form
- extension:
    extensions: [pdf, doc]

Options

optiontypedescription
extensionsstring/listOne or more extensions to match

Glob support

Extensions support glob patterns:

# Match doc and docx
- extension: "doc*"

# Match any single-character extension
- extension: "?"

Examples

Match PDF files

- extension: pdf

Match image files

- extension: [jpg, jpeg, png, gif, webp]

Match document files

- extension: [pdf, doc, docx, xls, xlsx, ppt, pptx]

Match video files

- extension: [mp4, mkv, avi, mov, wmv]

Match all Microsoft Office formats

- extension: ["doc*", "xls*", "ppt*"]

file_size

Matches files by their size. Directories are ignored (filter returns false for directories).

Syntax

Shorthand

- file_size: "> 10mb"
- file_size: "<= 500kb"
- file_size: ">= 1gb"

Explicit

- file_size:
    greater_than:
      mb: 10

- file_size:
    between:
      min:
        mb: 1
      max:
        gb: 1

Operators

shorthandexplicitdescription
>greater_thanStrictly greater than
>=at_leastGreater than or equal
<less_thanStrictly less than
<=at_mostLess than or equal
-betweenWithin a range (inclusive)

Size units

unitbytes
b1
kb1,024
mb1,048,576
gb1,073,741,824
tb1,099,511,627,776

Units are case-insensitive (MB, mb, Mb all work).

Examples

Match large files (> 100MB)

- file_size: "> 100mb"

Match small files (< 1KB)

- file_size: "< 1kb"

Match files in a range

- file_size:
    between:
      min:
        mb: 10
      max:
        mb: 100

Match empty files

- file_size: "< 1b"

Match files at least 1GB

- file_size: ">= 1gb"

file_type

Matches by file type: regular file, directory, or symlink.

Syntax

# Single type
- file_type: file

# Multiple types
- file_type: [file, directory]

# Explicit form
- file_type:
    types: [file, symlink]

Types

typealiasesdescription
file-Regular files
directorydir, folderDirectories
symlink-Symbolic links

Examples

Match only files (not directories)

filters:
  - file_type: file

Match directories only

filters:
  - file_type: directory
filters:
  - file_type: [file, symlink]

Exclude directories

filters:
  - not:
      - file_type: directory

Notes

  • Symlinks are checked without following them (uses lstat)
  • This filter is useful when processing directories recursively to skip subdirectories

date_modified

Matches files by their last modification time.

Syntax

# Files modified before a relative time
- date_modified:
    before:
      days_ago: 30

# Files modified after a relative time
- date_modified:
    after:
      hours_ago: 24

# Files modified before an absolute date
- date_modified:
    before:
      date: "2024-01-01"

Operators

operatordescription
beforeFile was modified before this time
afterFile was modified after this time

Time specifications

Relative time

optiondescription
seconds_agoSeconds in the past
minutes_agoMinutes in the past
hours_agoHours in the past
days_agoDays in the past
weeks_agoWeeks in the past
months_agoMonths in the past (~30.44 days)
years_agoYears in the past (~365.25 days)

Absolute time

optionformatexample
dateYYYY-MM-DD2024-01-15
dateYYYY-MM-DDTHH:MM:SS2024-01-15T14:30:00
unixUnix timestamp1704067200

Examples

Files older than 30 days

- date_modified:
    before:
      days_ago: 30

Files modified in the last hour

- date_modified:
    after:
      hours_ago: 1

Files modified before 2024

- date_modified:
    before:
      date: "2024-01-01"

Files modified in the last week

- date_modified:
    after:
      weeks_ago: 1

Example: clean old downloads

rules:
  - name: Archive Old Downloads
    locations: ~/Downloads
    filters:
      - date_modified:
          before:
            days_ago: 90
    actions:
      - move: ~/Archive/Downloads

date_accessed

Matches files by their last access time.

Syntax

# Files not accessed in 30 days
- date_accessed:
    before:
      days_ago: 30

# Files accessed recently
- date_accessed:
    after:
      hours_ago: 24

Operators

operatordescription
beforeFile was accessed before this time
afterFile was accessed after this time

Time specifications

See date_modified for all available time specification options:

  • Relative: seconds_ago, minutes_ago, hours_ago, days_ago, weeks_ago, months_ago, years_ago
  • Absolute: date (YYYY-MM-DD), unix (timestamp)

Examples

Files not accessed in 90 days

- date_accessed:
    before:
      days_ago: 90

Files accessed today

- date_accessed:
    after:
      hours_ago: 24

Notes

  • Access time tracking may be disabled on some filesystems for performance
  • On Linux, the noatime mount option disables access time updates
  • macOS may not update access times in all cases

date_created

Matches files by their creation time (birth time).

Syntax

# Files created more than 30 days ago
- date_created:
    before:
      days_ago: 30

# Files created recently
- date_created:
    after:
      hours_ago: 24

Operators

operatordescription
beforeFile was created before this time
afterFile was created after this time

Time specifications

See date_modified for all available time specification options:

  • Relative: seconds_ago, minutes_ago, hours_ago, days_ago, weeks_ago, months_ago, years_ago
  • Absolute: date (YYYY-MM-DD), unix (timestamp)

Examples

Files created in the last week

- date_created:
    after:
      weeks_ago: 1

Files created before 2024

- date_created:
    before:
      date: "2024-01-01"

Platform support

platformsupport
macOSFull support
WindowsFull support
LinuxDepends on filesystem (ext4 4.11+, btrfs)

On filesystems that don’t track creation time, this filter may not work as expected.

date_changed

Matches files by their metadata change time (ctime).

Syntax

# Files with metadata changed more than 30 days ago
- date_changed:
    before:
      days_ago: 30

# Files with recent metadata changes
- date_changed:
    after:
      hours_ago: 24

Operators

operatordescription
beforeMetadata was changed before this time
afterMetadata was changed after this time

Time specifications

See date_modified for all available time specification options:

  • Relative: seconds_ago, minutes_ago, hours_ago, days_ago, weeks_ago, months_ago, years_ago
  • Absolute: date (YYYY-MM-DD), unix (timestamp)

What is ctime?

The “change time” (ctime) is updated when file metadata changes, including:

  • Permission changes (chmod)
  • Ownership changes (chown)
  • Link count changes (hard links created/removed)
  • File content modifications (also updates mtime)

This is different from modification time (mtime), which only updates when file content changes.

Examples

Files with old metadata

- date_changed:
    before:
      days_ago: 90

Recently modified files (including metadata)

- date_changed:
    after:
      hours_ago: 1

Notes

  • On Unix systems, ctime cannot be set manually
  • Copying a file typically resets its ctime to the current time
  • On Windows, this typically maps to the file’s change time

mime_type

Matches files by their MIME type, detected from file content (not extension).

Syntax

# Single MIME type
- mime_type: "image/png"

# Wildcard pattern
- mime_type: "image/*"

# Multiple types
- mime_type: ["image/*", "video/*"]

# Explicit form
- mime_type:
    mime_types: ["application/pdf", "application/msword"]

Glob patterns

MIME type patterns support glob matching:

patternmatches
image/*All image types
video/*All video types
text/*All text types
application/*All application types

Common MIME types

Images

  • image/jpeg - JPEG images
  • image/png - PNG images
  • image/gif - GIF images
  • image/webp - WebP images
  • image/svg+xml - SVG images

Documents

  • application/pdf - PDF documents
  • application/msword - Word documents (.doc)
  • application/vnd.openxmlformats-officedocument.wordprocessingml.document - Word (.docx)

Video

  • video/mp4 - MP4 video
  • video/x-matroska - MKV video
  • video/quicktime - QuickTime video

Audio

  • audio/mpeg - MP3 audio
  • audio/wav - WAV audio
  • audio/flac - FLAC audio

Archives

  • application/zip - ZIP archives
  • application/x-tar - TAR archives
  • application/gzip - Gzip compressed

Examples

Match all images

- mime_type: "image/*"

Match videos and images

- mime_type: ["image/*", "video/*"]

Match PDF files

- mime_type: "application/pdf"

Match text files (including code)

- mime_type: "text/*"

Notes

  • MIME type is detected from file content, not the file extension
  • This is more accurate than extension-based filtering, but slower as the file needs to be read
  • Directories always return false (no MIME type)
  • Detection uses the first few bytes of the file (magic numbers)

Actions

Actions define what happens to files that match your filters. Each rule can have one or more actions that execute in order.

Available actions

actiondescription
moveMove files to a new location
copyCopy files with a new name in the same directory
renameRename files in place
deletePermanently delete files
trashMove files to system trash
logLog a message (for debugging/testing)

Action syntax

Actions are defined as a list under the actions key:

rules:
  - name: Example Rule
    locations: ~/Downloads
    actions:
      - move: ~/Documents
      - log: "Moved ${name}"

Multiple actions

Actions execute in order. This allows chaining operations:

actions:
  - copy: "${name}_backup${ext}"   # First, create a backup copy
  - move: ~/Documents              # Then, move the original
  - log: "Processed ${name}"

Template variables

Most actions support template variables in paths and messages:

variabledescription
${name}Filename without extension
${ext}File extension (with dot)
%YCurrent year (4 digits)
%mCurrent month (01-12)
%dCurrent day (01-31)
%HCurrent hour (00-23)
%MCurrent minute (00-59)
%SCurrent second (00-59)

See Templates for full details.

Conflict handling

Actions that create files (move, copy, rename) support conflict handling:

actions:
  - move:
      dest: ~/Documents
      on_conflict: skip  # Don't move if destination exists
modebehavior
rename_with_suffixAdd numeric suffix (file_2.txt, file_3.txt, etc.)
skipDon’t move/copy if destination exists
overwriteReplace existing file

Default is rename_with_suffix.

Dry run mode

Use --dry-run to preview actions without executing them:

autotidy run --dry-run

move

Moves files to a specified destination directory.

Syntax

# Simple form - just the destination
- move: ~/Documents

# Explicit form with options
- move:
    dest: ~/Documents
    on_conflict: skip

Options

optiontyperequireddefaultdescription
deststringYes-Destination directory path
on_conflictstringNorename_with_suffixHow to handle existing files

Conflict handling

modebehavior
rename_with_suffixAdd numeric suffix (file_2.txt, file_3.txt, etc.)
skipDon’t move if destination file exists
overwriteReplace existing destination file

Examples

Move downloads to documents

- move: ~/Documents

Move, skipping files on conflict

- move:
    dest: ~/Documents
    on_conflict: skip

Organize by date

- move: ~/Photos/%Y/%m

Move to categorized folders

rules:
  - name: Organize Images
    locations: ~/Downloads
    filters:
      - extension: [jpg, png, gif]
    actions:
      - move: ~/Pictures/Downloads

  - name: Organize Documents
    locations: ~/Downloads
    filters:
      - extension: [pdf, doc, docx]
    actions:
      - move: ~/Documents/Downloads

Template variables

The destination directory supports template variables:

- move: ~/Archive/%Y/%m

See Templates for all available variables.

Notes

  • The destination must be a directory, not a file path
  • The original filename is preserved (use rename to change filenames)
  • Creates destination directories if they don’t exist
  • Default conflict handling adds a numeric suffix (file_2.txt)

copy

Copies a file to a new name in the same directory.

Syntax

# Simple form - just the new filename
- copy: backup.txt

# With template
- copy: "${name}_backup${ext}"

# With conflict handling
- copy:
    new_name: "${name}_backup${ext}"
    on_conflict: overwrite

Options

optiontyperequireddefaultdescription
new_namestringYes-New filename (supports templates)
on_conflictstringNorename_with_suffixHow to handle existing files

Conflict handling

modebehavior
rename_with_suffixAdd numeric suffix (file_2.txt, file_3.txt, etc.). This is the default
skipDon’t copy if destination file exists
overwriteReplace existing destination file

Examples

Simple copy

- copy: backup.txt

Copy with original name preserved

- copy: "${name}_copy${ext}"

Copy with timestamp

- copy: "${name}_%Y%m%d${ext}"

Backup with overwrite

- copy:
    new_name: "${name}_backup${ext}"
    on_conflict: overwrite

Template variables

The new_name field supports template variables:

- copy: "${name}_%H%M${ext}"

See Templates for all available variables.

Notes

  • Copies to the same directory as the source file
  • The new_name must not contain path separators
  • Original file remains unchanged
  • To copy to a different directory, first copy the file and then use the move action

rename

Renames files in place.

Syntax

# Simple form - new name with template
- rename: "${name}_archived${ext}"

# Explicit form with options
- rename:
    new_name: "${name}_%Y%m%d${ext}"
    on_conflict: rename_with_suffix

Options

optiontyperequireddefaultdescription
new_namestringYes-New filename (supports templates)
on_conflictstringNorename_with_suffixHow to handle existing files

Conflict handling

modebehavior
rename_with_suffixAdd numeric suffix (file_2.txt, file_3.txt, etc.)
skipDon’t rename if a file with the new name exists
overwriteReplace existing file with the new name

Examples

Add date suffix

- rename: "${name}_%Y%m%d${ext}"

Preserve original name

- rename: "${name}${ext}"

Add prefix

- rename: "archived_${name}${ext}"

Rename with skip on conflict

- rename:
    new_name: "processed_${name}${ext}"
    on_conflict: skip

Standardize filenames

rules:
  - name: Rename Screenshots
    locations: ~/Desktop
    filters:
      - name: "Screen Shot*"
    actions:
      - rename: "screenshot_%Y%m%d_%H%M%S${ext}"

Template variables

The new_name field supports template variables:

variabledescriptionexample
${name}Filename without extensiondocument
${ext}File extension (with dot).pdf
%YYear (4 digits)2024
%mMonth (01-12)03
%dDay (01-31)15
%HHour (00-23)14
%MMinute (00-59)30
%SSecond (00-59)45

See Templates for full details.

Notes

  • File stays in the same directory
  • Only the filename changes, not the location
  • Default conflict handling adds a numeric suffix (file_2.txt)
  • Use rename and move in succession to rename a file and move it to another directory
  • Template variables are evaluated at the time of action execution

delete

Permanently deletes files and directories. For safer deletes consider trash instead.

Syntax

- delete

Options

This action has no options.

Examples

Delete old temp files

rules:
  - name: Clean Temp Files
    locations: ~/tmp
    filters:
      - date_modified:
          before:
            days_ago: 7
    actions:
      - delete

Delete by extension

rules:
  - name: Remove Log Files
    locations: ~/Projects
    subfolders: true
    filters:
      - extension: log
      - date_modified:
          before:
            days_ago: 30
    actions:
      - delete

Delete with size filter

rules:
  - name: Remove Large Temp Files
    locations: /tmp
    filters:
      - size:
          gt: 100MB
      - extension: [tmp, temp, cache]
    actions:
      - delete

Safety recommendations

Always use dry run first

autotidy run --dry-run

Combine with specific filters

Don’t use delete without filters:

# DANGEROUS - deletes everything!
rules:
  - name: Bad Rule
    locations: ~/Documents
    actions:
      - delete

# SAFE - specific filters
rules:
  - name: Good Rule
    locations: ~/Documents
    filters:
      - extension: tmp
      - date_modified:
          before:
            days_ago: 30
    actions:
      - delete

Consider using trash instead

For most cases, trash is safer:

# Recoverable
- trash

# Permanent
- delete

Notes

  • Permanent: Files cannot be recovered after deletion
  • No confirmation: Executes immediately when rules match

Trash

Moves files to the system trash/recycle bin. This is a safer alternative to delete since files can be recovered.

Syntax

- trash

Options

This action has no options.

Examples

Clean old downloads

rules:
  - name: Trash Old Downloads
    locations: ~/Downloads
    filters:
      - date_modified:
          before:
            days_ago: 30
    actions:
      - trash

Trash old backups

rules:
  - name: Trash Old Backups
    locations: ~/Backup
    filters:
      - name: "*_backup_*"
      - date_modified:
          before:
            weeks_ago: 4
    actions:
      - trash

Trash temporary files

rules:
  - name: Clean Temp Files
    locations: ~/Projects
    subfolders: true
    filters:
      - extension: [tmp, temp, bak, swp]
    actions:
      - trash

Platform behavior

platformtrash location
macOS~/.Trash
Linux~/.local/share/Trash (freedesktop.org spec)
WindowsRecycle Bin

Comparison with delete

aspecttrashdelete
RecoverableYesNo
Disk spaceStill used until emptiedFreed immediately
SpeedSlightly slowerFaster
SafetySafeDangerous

Notes

  • Safer than delete for automated cleanup rules
  • Uses the system’s native trash mechanism
  • On Linux, follows the freedesktop.org trash specification

log

Logs a message when a file matches. Useful for debugging rules and testing configurations.

Syntax

# Simple form - just the message
- log: "Found file: ${name}${ext}"

# Explicit form with level
- log:
    msg: "Processing ${name}"
    level: info

Options

optiontyperequireddefaultdescription
msgstringYes-Message to log (supports templates)
levelstringNoinfoLog level

Log levels

leveldescription
debugDetailed debugging information
infoGeneral information (default)
warnWarning messages
errorError messages

Examples

Simple logging

- log: "Matched: ${name}${ext}"

Debug logging

- log:
    msg: "File details: ${name}, ext: ${ext}"
    level: debug

Log before action

actions:
  - log: "Moving ${name}${ext} to archive"
  - move: ~/Archive

Testing rules

rules:
  - name: Test Image Filter
    locations: ~/Downloads
    filters:
      - extension: [jpg, png, gif]
    actions:
      - log: "Would process image: ${name}${ext}"
      # Comment out actual action while testing
      # - move: ~/Pictures

Conditional logging

rules:
  - name: Large File Warning
    locations: ~/Downloads
    filters:
      - size:
          gt: 1GB
    actions:
      - log:
          msg: "Large file detected: ${name}${ext}"
          level: warn

Template variables

The msg field supports all template variables:

- log: "File: ${name}${ext}, Year: %Y, Month: %m"

See Templates for all available variables.

Use cases

Audit trail

Log actions for review:

rules:
  - name: Archive with Logging
    locations: ~/Downloads
    filters:
      - extension: pdf
    actions:
      - log:
          msg: "Archiving PDF: ${name}"
          level: info
      - move: ~/Archive/PDFs

Notes

  • Does not modify files in any way
  • Output goes to autotidy’s log output
  • Useful during rule development and debugging
  • Can be combined with other actions in the same rule

Templates

Templates allow you to use dynamic values in action parameters like destination paths and new filenames. Variables are replaced with actual values when the action executes.

Syntax

Template variables use the ${variable} syntax:

- move: ~/Archive/%Y/%m
- rename: "${name}_backup${ext}"

File variables

variabledescriptionexample
${name}Filename without extensiondocument
${ext}File extension (with dot).pdf

Examples

For a file named report.pdf:

templateresult
${name}report
${ext}.pdf
${name}${ext}report.pdf
${name}_copy${ext}report_copy.pdf
backup_${name}${ext}backup_report.pdf

Time variables

Time variables use strftime format tokens:

tokendescriptionexample
%YYear (4 digits)2024
%mMonth (01-12)03
%dDay (01-31)15
%HHour (00-23)14
%MMinute (00-59)30
%SSecond (00-59)45

Common Patterns

patternexample output
%Y-%m-%d2024-03-15
%Y%m%d20240315
%Y/%m/%d2024/03/15
%H:%M:%S14:30:45
%Y%m%d_%H%M%S20240315_143045

Additional Time Tokens

tokendescriptionexample
%yYear (2 digits)24
%BMonth name (full)March
%bMonth name (abbr)Mar
%AWeekday name (full)Friday
%aWeekday name (abbr)Fri
%jDay of year (001-366)074
%UWeek number (00-53)11
%WWeek number (Monday start)10

Examples

Organize by date

rules:
  - name: Organize Downloads
    locations: ~/Downloads
    actions:
      - move: ~/Archive/%Y/%m/%d

Files are organized into folders like ~/Archive/2024/03/15/.

Add timestamp to filename

rules:
  - name: Timestamp Files
    locations: ~/Documents
    filters:
      - extension: pdf
    actions:
      - rename: "${name}_%Y%m%d${ext}"

report.pdf becomes report_20240315.pdf.

Create dated copies

rules:
  - name: Daily Backup
    locations: ~/Documents
    actions:
      - copy: "${name}_%Y%m%d${ext}"

Creates a timestamped copy of each file in the same directory.

Organize photos by date

rules:
  - name: Organize Photos
    locations: ~/Downloads
    filters:
      - extension: [jpg, jpeg, png, heic]
    actions:
      - move: ~/Pictures/%Y/%B

Photos organized into folders like ~/Pictures/2024/March/.

Archive old files

rules:
  - name: Archive Old Downloads
    locations: ~/Downloads
    filters:
      - date_modified:
          before:
            days_ago: 30
    actions:
      - move: ~/Archive/Downloads/%Y-%m

Unique filenames with timestamp

rules:
  - name: Rename Duplicates
    locations: ~/Downloads
    actions:
      - rename: "${name}_%Y%m%d_%H%M%S${ext}"

Combining variables

Mix file and time variables:

- move: ~/Archive/%Y/${name}/%m
- rename: "${name}_%Y%m%d_%H%M%S${ext}"
- copy: "${name}_backup_%Y%m%d${ext}"

Where templates work

Templates are supported in:

actionfields
movedest
copynew_name
renamenew_name
logmsg

Notes

  • Time values are evaluated at action execution time
  • File variables (${name}, ${ext}) come from the matched file
  • Unknown variables are left unchanged in the output
  • Paths are created automatically if they don’t exist

Additional options

Daemon

daemon:
  debounce: 500ms
propertytypedefaultdescription
debounceduration500msWait for filesystem activity to settle before executing rules

The debounce prevents rapid re-execution when files are being written or modified in quick succession. Decreasing it will make rule invocations more responsive, but may reduce performance.

Logging

logging:
  level: warn
propertytypedefaultdescription
levelstringwarnLog level: debug, info, warn, error