I split my brain
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.
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 aliasorg-roam-capture
- launches an Org-roam capture
I extended them to allow me to select a context (folder):
- I extended
org-roam-node-find
andorg-roam-node-capture
to allow me to select a directory first:
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:
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.
Comments