{ Code Thrasher }

What I cannot create, I do not understand

Evolving my note-taking processes

It took me a while to understand that I need/needed to write everything down or there was a greater-than-fifty-percent chance that, whatever it was, I'd forget about it. Initially I was scribbling on random bits of paper, then moleskins, then markdown files scattered around my hard drive, then I started messing with Standard Notes; which I used happily for nearly a year. But then I started predominantly using Emacs for my development work (after moving from Vim "just cuz") and got tired of moving out of Emacs to write notes.

I knew of Org-mode, but it seemed odd to me. I was still married to the syntax of standard Markdown, so the org syntax grated on me.

No longer. Down the org rabbit hole...

Simple usage

Like most new-to-org/emacs users, I relied (and still do, to some extent) heavily on external packages. Many of them are wonderful pieces of software and I tip my hat to the creators of those packages (namely, @jethrokuan and @alphapapa; both of whom have been personally helpful when I've asked questions). Whether it was initiated by my need to tweak my editor to my specifications or simply to satisfy my curiosity, I started writing tiny functions in Elisp to aid in getting my notes written-out as quickly--and painlessly--as possible.

Generally, my note-taking process in Emacs is as such:

  1. key command to open my daily note ("dailies" in org-roam parlance)
  2. pre-defined template inserted (see image below)

My initial template

  1. Begin writing! I use an org-headline (*) for each "thing" I'm thinking about/working on throughout the day, e.g.:

example heading

I've purposely hidden my org-tags via their face configuration. I don't find them useful (with the exception of one, which I'll discuss later), but I do tag my headings heavily.

In #3's image I've linked to the last time I worked on "Project X" via the "see yesterday" org-link, which references...you guessed it, my note from yesterday.

A deeper approach

The above has worked well for me for a while, but I continually found myself either losing context in the sprawl of daily notes in my org directory, people mentioned in my notes, or how to quickly lookup a conversation I had with such-and-such person. So, as any good hacker is wont to do, I stayed up later and started losing myself in the parenthetical ~hell~ heaven. Some of the pain points I hit were tagging people and building references (backlinks) to notes. It was easy enough to store a link and insert it where I needed it, but there was a bi-directionality that I was missing.

Homegrown backlinks

Let's say I want to insert a link like the "see yesterday" link in the image above. Simple, right? org-store-link...move to necessary file/region...org-insert-link. Done.

But then I hit the problem of knowing if the note I'm reading has been referenced anywhere else. It's not a thing I do a lot, but I do occasionally need to do it. Grep/ag/ripgrep work, but that's a lot of work. So I wrote this elisp function:

(defun my/org-insert-link-and-ref ()
  "effectively duplicates the org-insert-link function and adds a ref (a link to the file the
   linked-entry is pasted into) in the linked-entries property drawer."
  (let* ((buf (current-buffer))
         (current-heading-id (org-id-get-create))
         (current-heading (format "%s" (org-get-heading t t t t)))
         (heading-of-inserted-link (format "%s" (cadr (car org-stored-links))))
         (id-of-inserted-link (substring-no-properties (car (car org-stored-links))))
         (file-of-inserted-link (car (org-id-find (cadr (split-string id-of-inserted-link "id:")))))
         (buffer-of-inserted-link (org-find-base-buffer-visiting file-of-inserted-link))
         (marker-to-inserted-link (org-find-exact-headline-in-buffer heading-of-inserted-link buffer-of-inserted-link))
         (marker-to-current-link (org-find-exact-headline-in-buffer current-heading buf)))
    (with-current-buffer (get-buffer-create buffer-of-inserted-link)
      ;; check the REFS for existence/enries
      (if (org-entry-get marker-to-inserted-link "REFS")
          ;; check if the id has already been inserted (avoid placing the same ref)
          (if (not (string-match-p current-heading-id (format "%s" (org-entry-get marker-to-inserted-link "REFS"))))
              ;; if there's no ref already in the property, append it
              (org-entry-put marker-to-inserted-link "REFS"
                             (format "%s //// [[id:%s][%s]]"
                                     (org-entry-get marker-to-inserted-link "REFS") current-heading-id current-heading)))
             ;; else, place the ref
            (org-entry-put marker-to-inserted-link "REFS"
                           (format "[[id:%s][%s]]" current-heading-id current-heading)))
      (insert (format "[[id:%s][%s]]" id-of-inserted-link heading-of-inserted-link))))

There's a lot going on here and I'm completely aware that org-roam solves this with its backlinks paradigm, but I like to make life harder and learn on my own, so here's a recreated wheel!

What my/org-insert-link-and-ref does is insert the "last stored" org link, visits the headline that was just inserted, adds a property REFS to the PROPERTY drawer of said headline, and adds (or appends) a link to the headline that I just inserted into. This might be better visualized with another image:

example of a

Now, when I read that note, I can easily see that I referenced it somewhere else (namely, in a headline dubbed "More Hume"). Excellent.

But what about people? I would like to be able to consolidate my conversations with people so that I can "at" a person (@someperson) in a note and look that up easily. For example, one day I might think,

I know I had a convo with so-and-so about unit tests, but I don't know when that was...

I could search my tags for various terms (unit_tests, convo, so-and-so, etc.), but that's pretty inefficient. What if I had a file I called contacts.org that held headlines of each person I've ever mentioned in my note taking? That could work. There might also be a package for it, but why not just re-invent another wheel? Let's do it...


When I press CTRL-@ I get an ivy popup which let's me select a name that is queried from a contacts file:

contacts popup

If a name doesn't exist, I get prompted to add the name to the file as well as an alias (which is stored in the person's PROPERTY drawer), that will be placed in the tag (link) like so:

linked person

When I @ a person in my notes I have a custom function which links the heading I'm pasting into into the person's heading in the contacts file. It's really helpful for answering the question of "I know I talked to...but I can't remember...":

Referenced heading for person

Current tasks

When I begin a new note I like to have a running list of things I'm working on. I define these by tagging a given heading with an in_progress tag. When my file is generated I get a list of things marked as "in progress". Yeah, I could probably use TODOs and look at my agenda, but in all honesty, I haven't leaned too much on org-agenda yet. I like to keep as much context in my daily notes as possible.

(defun my/get-current-tasks ()
(insert "Current tasks:\n")
  (dolist (item (org-ql-select (org-agenda-files) '(tags "in_progress")))
    (insert (format "- [[id:%s][%s]] (last worked-on: %s)\n"
(org-element-property :ID item)
(org-element-property :raw-value item)
(org-element-property :DATE_MODIFIED item)))))

Still evolving...

Those are, roughly, the wheels I've recreated. I still have some pain-points I'm working through, but I really like my flow so far. If you have any questions or suggestions feel free to reach out to me: dev (AT) mttyng (dot) com