I split my brain

3 minute read

cover

This year I started taking my notes exclusively using org-roam. It’s a wonderful knowledge management and note-taking system based on org-mode and inspired by roam-research. You can take a look at my intro post for org-roam I wrote a couple of months ago.

Over time I found one thing that makes my usage of org-roam less enjoyable and comfortable. It’s a lack of contexts. Let me explain with an example. For example, you use org-roam to manage your notes both for work-related projects and for your personal projects and free time. The problem for me is that org-roam stores all notes in the same DB so it searches all your notes even when you want only your work-related or personal notes.

mess

In the image above you can see the note about Red Rising book series ( you should check it out :) ) with my emacs related notes. To me, it looks like a mess.

Org-roam in its manual has a section about maintaining multiple org-roam directories. But it seems it’s broken because I couldn’t make it work. I created an issue in the org-roam repo, but it didn’t receive any comments. A couple of months ago org-roam v2 was released, it introduced a couple of bugs so maybe it’s one of these bugs.

As a workaround, I wrote a couple of functions that help me to search my org-roam notes both globally and separated by contexts.

Overview

Contexts

I have several subdirectories in the main org roam directory (defined by org-roam-directory variable). Each of these directories is a separate project or separate context. For example here are several of my contexts:

  • work - my notes related to work and work-related projects
  • fun - notes on pop culture stuff (fiction books, tv series, movies)
  • daily - default org-roam directory for daily notes / journal
  • braindump - my public notes for my braindump
  • todos - notes for my agenda view

Also, I have a couple of directories dedicated to software projects I’m working on.

Extension of default functions

The main function of org-roam are:

  • org-roam-node-find - find and open an Org-roam node by its title or alias
  • org-roam-capture - launches an Org-roam capture

I extended them to allow me to select a context (folder):

  • I extended org-roam-node-find and org-roam-node-capture to allow me to select a directory first:

tags

In the image above, it asks to select a tag. But it just lists all directories in the main org-roam directory.

  • After selecting a directory, only notes in the selected directory are searched. It’s achieved by using tags.

When you create a new note in the selected context, my custom functions add a tag to this note. Its value is the same as the name of the selected directory:

capture

Implementation

Filter nodes by tag

This function filters org-roam nodes by the given tag. I found this function in the awesome video by System Crafters youtube channel.

(defun ayrat555/org-roam-filter-by-tag (tag-name)
  (lambda (node)
    (member tag-name (org-roam-node-tags node))))

Custom capture templates

The following two functions are used to set a tag in the org-roam capture templates. ayrat555/org-roam-current-tag variable is set when selecting a directory.

(defun ayrat555/org-roam-get-current-tag ()
  ayrat555/org-roam-current-tag)

(defcustom ayrat555/org-roam-capture-templates
  '(("d" "default" plain "%?"
     :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org"
                        "#+title: ${title}\n#+filetags: :%(ayrat555/org-roam-get-current-tag):")
     :unnarrowed t))
    "Templates for the creation of new entries within Org-roam.")

Listing directories

ayrat555/org-roam-directories function just lists all subdirectories in the org-roam directory

(defun ayrat555/org-roam-directories ()
  (let ((files (directory-files org-roam-directory)))
    (seq-filter (lambda (name)
                  (and (file-directory-p (concat org-roam-directory name))
                       (not (string-prefix-p "." name))))
                files)))

Custom capture function

This function allows a user to select a directory before running org-roam-capture-

(defun ayrat555/org-roam-capture ()
  (interactive)
  (let* ((directory (completing-read "org-roam directory: " (ayrat555/org-roam-directories)))
         (org-roam-directory (expand-file-name directory org-roam-directory)))
    (setq ayrat555/org-roam-current-tag directory)
    (org-roam-capture- :node (org-roam-node-read
                              nil
                              (ayrat555/org-roam-filter-by-tag directory))
                       :templates ayrat555/org-roam-capture-templates)))

Custom find function

Again, this function asks for a directory from the user

(defun ayrat555/org-roam-node-find ()
  (interactive)
  (let* ((tags (ayrat555/org-roam-directories))
         (tag (completing-read "tag: " tags))
         (org-roam-directory (expand-file-name tag org-roam-directory)))
    (setq ayrat555/org-roam-current-tag tag)
    (org-roam-node-find
     nil
     nil
     (ayrat555/org-roam-filter-by-tag tag)
     :templates ayrat555/org-roam-capture-templates)))

Conclusion

I hope my custom functions will be useful for org-roam users feeling the same way about context separation. You can find my complete org-mode and org-roam files in my emacs configuration.

Categories:

Updated:

Comments