id = "maid" name = "Maid" homepage = "https://github.com/maid/maid" description = "Be lazy! Let Maid clean up after you, based on rules you define. Think of it as \"Hazel for hackers\"." # The project's own mark, from its GitHub organisation avatar. icon = "https://github.com/maid.png?size=200" executables = ["maid"] [dotfiles] # lib/maid/maid.rb — the DEFAULTS hash: # rules_path: File.expand_path('~/.maid/rules.rb') # log_device: File.expand_path('~/.maid/maid.log') # and the constructor does FileUtils.mkdir_p(File.expand_path('~/.maid')), so # the directory is always there once maid has run. rules.rb is the file the user # writes: "Your rules are defined in Ruby" (README). paths = ["~/.maid/rules.rb"] # ~/.maid/maid.log is the run log — "actions are logged so you can tell what # happened" (README) — and it is not below a path above, so there is nothing to # carve out. Named here anyway so a consumer widening this entry to the whole # ~/.maid directory does not pick the log up. exclude = ["~/.maid/maid.log"] # A Ruby rule file: globs, directory names and the actions to take. No # credentials. secret = [] # No machine_lines. Rules do name directories — `dir('~/Downloads/*')` — but # they are written home-relative, which is the point of carrying them to another # machine. A rule that hard-codes a volume would be machine-local, but there is # no keyword to match it on: the whole file is Ruby, not a key-value format. # maid loads rules.rb at the start of each run and exits; nothing holds the file # open between runs. side_effect = false [commands] format = 1 label = "Maid" description = "Run or rehearse your Maid cleanup rules. Daemon mode and rule generation are left out." quality = "ai-draft" parser = { end_of_options = "--", interleave = "permute", long_equals = true, short_attached = true, short_bundles = true } [[commands.subcommand]] path = ["clean"] label = "Clean up" description = "Run the rules in ~/.maid/rules.rb (or another rules file). Use Dry run first to see what would happen; Force actually performs the actions." [[commands.subcommand.source]] id = "readme" kind = "manual" url = "https://github.com/maid/maid#readme" revision = "HEAD 2026-10-27" evidence = """ maid clean --dry-run # Synonyms: -n, --noop maid clean -f # Run the rules at ~/.maid/rules.rb, logging to ~/.maid/maid.log maid clean -fr some_rules.rb # Run the rules in the file 'some_rules.rb', logging to ~/.maid/maid.log $ maid clean -nr some_rules.rb maid clean --force --silent --rules ~/.maid/rules.rb """ [[commands.subcommand.field]] id = "dry_run" label = "Dry run" description = "Show what would happen without taking any action." type = "boolean" option = ["--dry-run", "-n"] sources = ["readme"] [[commands.subcommand.field]] id = "force" label = "Force (perform actions)" type = "boolean" option = ["--force", "-f"] effect = "exec" sources = ["readme"] [[commands.subcommand.field]] id = "rules" label = "Rules file" description = "Defaults to ~/.maid/rules.rb." type = "path" option = ["--rules", "-r"] path = { kind = "file", role = "input", must_exist = true } sources = ["readme"] [[commands.subcommand.field]] id = "silent" label = "Silent" description = "Suppress output, e.g. when run from cron." type = "boolean" option = ["--silent"] sources = ["readme"] [[commands.subcommand.task]] id = "preview" label = "Preview rules" fields = ["dry_run", "rules"] required = ["dry_run"] set = { dry_run = [true] } [[commands.subcommand.task]] id = "run" label = "Run rules" fields = ["force", "rules", "silent"] required = ["force"] set = { force = [true] } [[commands.subcommand.group]] id = "basic" label = "Basic" fields = ["dry_run", "force", "rules", "silent"]