Automatic filing with Hazel and Mavericks tags

[Tweet : nvALT]

I’ve finished a tag-based filing system I started working on before Mavericks. I personally think it’s flexible enough to be shared, but others may balk at the apparent complexity. It does take some planning and setup, but it’s an effective way for me to manage files.

The basic idea is that you save new files and incoming attachments that you don’t immediately have a place for to your Desktop. I sometimes fill up about half my Desktop (with 64px icons) with new project files over a day. Then, when you have time to review, you apply special tags that Hazel recognizes, triggering a script that handles filing based on the tags applied. Speed up the tagging process with a keyboard shortcut. The files move to their locations in a shallow folder hierarchy, and the additional tags you put on them during the review make them searchable.

The path tags are redundant after filing, because the folder path already roughly represents that metadata, in most cases. You can tag a target folder with a tag name completely different from its folder name, and you can have multiple target tags on one folder. Thus, it can be handy to have the path string in the tag to know why it originally ended up in that folder.

There’s a primary set of “context” folders that define major divisions in tag groups. Mine include “Projects,” “Work,” “Writing,” and “Archive,” among a few others. In my system these are the root folders of what I consider multiple organization paths. These are tagged with an equal sign prefix and start with a capital letter: =Archive. When tagging a file to find them, a hash is used instead: #Archive.

The path strings are colon delimited “paths.” Each section of the string is parsed in order from left to right. Based on the primary context tag (#Tag) that must exist for it to be picked up for filing, the first segment of the string is searched for in the root folder. The first search is for a folder tagged (@string) in the full depth of the folder system. If one is found matching the current segment, it becomes the root for any further searches. If the string continues, it does the same search for the next part within the last located folder. If at any time a tagged folder is not found, it generates new nested folders the remainder of the path string. For example:

  1. I have a folder hierarchy two levels deep off the main context folder:

     Writing (=Writing)
         Notes (@note)
             General Brainstorming (@brainstorm)
  2. I tag a file with the following:

     (#Writing) (:brainstorm:maverickstagging)
  3. The file is picked up by Hazel when it sees a #Tag on it and passed to the filing script.
  4. The script starts with “brainstorm” and searches for a tagged folder in “Writing.”
  5. It will locate “General Brainstorming” based on the @tag and skip ahead to that level of the folder hierarchy.
  6. It will look for a tagged folder with @maverickstagging, but it won’t find one.
  7. It will check for an existing directory named “maverickstagging.” It won’t find one.
  8. It will create a new folder inside of “General Brainstorming” called “maverickstagging.”1
  9. If you use the same path string on another file, the new folder will be recognized by name and the file added to it.

Note that files with colon-delimited-string tags are searchable by any section of the path as tags. If you give your target folders semantic tags (or names), the path tags are perfectly usable for search. They just don’t show up as individual tags in tag lists, you have to manually create “tag:tagname” searches.

I don’t file very deep, so my path tags are rarely longer than three sections. This makes them easily reusable through autocomplete, and common folders are a couple of keystrokes away once you’ve filed to them a couple of times.

Only one #Context and one :path:tag should exist in a single file’s tags.


Finding a file is simple, now. I can choose to search system-wide, within a context folder or just use a top-level #Context tag to filter out any ambiguously-tagged files and folders from other contexts. Then I search with a string like:

tag:brainstorm tag:mav filename:.scriv

That will instantly bring up the rough draft for the book I’m working on. Note that “mav” matches “maverickstagging,” as you only need the first few letters of a tag to pick it up. In cases like this where there are fairly specific tags in place, I can skip the extra folder tag and just search for tag:mav filename:.scriv or tag:mav kind:Scrivener. In my mind, this is simple and works with the way I search for files.

Speaking of searching for files, this system nests as deeply as you want to. I keep it shallow, but if you prefer to find files by clicking, it will let you. The benefit you still get is that you can assign and search for common tags throughout your filesystem, grouping files and folders from different projects and contexts in a single search or Smart Folder.


Tag target folders

  • Tag primary “context” directories with =Tagname (e.g, =Archive, =Project)
  • Tag target subfolders with @tagname (@contract, @pearson)

Tag files

  • Tag files with a target context #Tagname
    • # matches = in the search
  • Add subfolder matches in sequence, starting with and separated by colons :contract:pearson
    • These are matched in order
    • If it matches an @tagged folder first, it searches for the next string within that folder
    • If there’s no @tag folder to match, it checks for a matching folder name
    • If there isn’t one, it creates a folder hierarchy from that word on and nests folders for any following sections of the path string
    • The file is moved to the last located or created folder in the path chain


Here is the script that Hazel will need. Save it to tagfiler.rb in a folder somewhere. Make it executable by running chmod a+x path/to/tagfiler.rb in Terminal.

Set up a single rule on the Desktop (or wherever you want your “Inbox” folder) to match any file with “Tags contains #” and add a Run Shell Script action. Choose “Other” from the dropdown and point it to tagfiler.rb.

The “#” condition makes it possible to tag files on your desktop without filing them. Only files containing a primary context are picked up for filing.

It should give you a notification with success or error message. If you have any trouble, you can try saving the script to a file and running ruby tagfiler.rb path/filename on the command line and seeing what you get for errors.

  1. Tags often don’t make good folder names. If you’re creating folders from tags and want a better-looking name, just rename it and add the original name as an @tag on it. You can also use Planter to pre-create repetitive hierarchies with tags assigned.