Denote's file naming scheme and org-roam


There is nice Emacs package - Denote for taking notes which lacks graphing capabilities, but it has interesting file naming scheme where filenames e.g. contains tags used in notes’ meta.

It looks that it is is not so simple to adapt org-roam’s naming scheme to Denote to take advantage of org-roam-ui, but wonder about the other way: adapting Denote’s naming to org-roam or this is even more complex considering org-roam’s usage of sqlite3 database?

I think that’s feasible either direction. Denote generates file names based on some rules (programmed). For Org-roam, that’s just part of the capture template. Filenames should not be relevant with use of database. A challenge may be adaptation of “tags”. I’d start without tags and see how far I would get.

You can use Denote to take notes in Org mode, instead of capture, and add IDs so that Org-roam can save the files as nodes.

I was looking into Denote but never tried it due to the lack of graphing capabilities. However, the idea of programmed rules for file naming is appealing. Author of Denote Prot argues that "different field separators, “namely -- and __ introduce an efficient way to anchor searches”.

That is interesting and therefore I wonder how exactly could this workflow work?

You can use Denote take notes in Org mode, instead of capture, and add IDs so that Org-roam can save the files as nodes.

Sure. There are a couple of approaches, but the easiest would be to personalize the front matter.

You can read the relevant part of the manual where Prot talks about changing the front matter.

As a proof of concept, put the snippet below in your init.el before you load/require denote – there is a quirk with Denote at the moment, and you need to set this variable before it is loaded. I have sent a patch to make it easy for users to personalize the front matter. Let’s see how it goes.

(setq denote-org-front-matter
:ID: %4$s
#+title:      %1$s
#+date:       %2$s
#+filetags:   %3$s

If you don’t want to remove the default #+identifier, you can add it with the value %4$s to repeat the same ID inserted – as far as I can see, it’s there only for informational purposes. Prot also shows an example of removing it in the user manual (in the same section above).

The resultant Org note will look like this. The rest should be easy: set the denote-directory to your org–roam-directory, and turn on org-roam-db-autosync-mode before creating the note. Org-roam should use the ID to save it to the database as a normal Org-roam file-node – I have not tested it myself but that should just work. If I recall correctly, even when the ID is not generated with an org-id function, Org-roam adds it to the org-id-locations-file. Any issue, you can come back here; I’m pretty sure we can work out a way.

Great! Thank you.

I’ve added that snippet to my config.el, but the newly created (De)notes have IDs like :ID: 20221023T192650 which is not the same as the original org-roam ones.

Any hint?

What’s the problem with this ID? That’s the format Denote uses and the only format it recognizes without changing many of its built-in regexp’s.

I thought it can be recognized by org-roam-ui since my point was to, somehow, be able to use the same (Denote) notes with org-roam/org-roam-ui.

Have I misunderstood something?

Org-roam and Org-roam-ui have no problem with Denote’s ID format. Did you try it?

When I tried to add keyword to such (De)note I got: “denote-keywords-add: Buffer not visiting a Denote file” ?

Yes, created few notes with Denote, but org-roam-ui does show empty graph, although org-roam does recognize those Denote-created notes…:confused:

Edit: And there is no org-roam.db created.

I’m also using Denote and playing with it. It identifies Denote notes with the file name (the frontmatter is currently just a convenience for the human user). Did you change the file name? Also, you need to set the correct directory to denote-directory customizing variable.

This is weird. If the node is not in the database or the db file is not present, Org-roam is not working for the file. Org-roam-ui relies on the db file. No db, no Org-roam and its friends.

But the format of the ID should not matter (I’m using a date format). Try running org-roam-update-id (or something like this). it’s a command to sync Org-ID and Org-roam when IDs are not in sync. I don’t have to do this, but it might help.

I’m glad you do. :smile:

Here is my complete setup:

;; org-roam
(use-package org-roam
  ;;(org-roam-directory (file-truename "/home/gour/emacs/roam"))
  (org-roam-directory (file-truename "/home/gour/emacs/denote"))
  :bind (("C-c n l" . org-roam-buffer-toggle)
         ("C-c n f" . org-roam-node-find)
         ("C-c n g" . org-roam-graph)
         ("C-c n i" . org-roam-node-insert)
         ("C-c n c" . org-roam-capture)
         ;; Dailies
         ("C-c n j" . org-roam-dailies-capture-today))
  (setq org-roam-node-display-template "${tags:30} ${title:70} ")
  ;; If using org-roam-protocol
  (require 'org-roam-protocol)

;; org-roam-ui
(use-package org-roam-ui
  :after org-roam
  (setq org-roam-ui-sync-theme t
        org-roam-ui-follow t
        org-roam-ui-update-on-save t
        org-roam-ui-open-on-start t)

;; front-matter
(setq denote-org-front-matter
:ID: %4$s
#+title:      %1$s
#+date:       %2$s
#+filetags:   %3$s

;; Denote
;; Remember to check the doc strings of those variables.
(use-package denote
  (setq denote-directory (expand-file-name "~/emacs/denote/"))
  (setq denote-infer-keywords t)
  (setq denote-sort-keywords t)
  (setq denote-file-type 'org) ; Org is the default, set others here
  (setq denote-prompts '(title keywords))

  ;; Pick dates, where relevant, with Org's advanced interface:
  (setq denote-date-prompt-use-org-read-date t)

  ;; Read this manual for how to specify `denote-templates'.  We do not
  ;; include an example here to avoid potential confusion.

  ;; We allow multi-word keywords by default.  The author's personal
  ;; preference is for single-word keywords for a more rigid workflow.
  (setq denote-allow-multi-word-keywords t)

  (setq denote-date-format nil) ; read doc string

  ;; By default, we fontify backlinks in their bespoke buffer.
  (setq denote-link-fontify-backlinks t)

  ;; Also see `denote-link-backlinks-display-buffer-action' which is a bit
  ;; advanced.

  ;; If you use Markdown or plain text files (Org renders links as buttons
  ;; right away)
  (add-hook 'find-file-hook #'denote-link-buttonize-buffer)

  ;; Generic (great if you rename files Denote-style in lots of places):
  ;; (add-hook 'dired-mode-hook #'denote-dired-mode)

  ;; Here is a custom, user-level command from one of the examples we
  ;; showed in this manual.  We define it here and add it to a key binding
  ;; below.
  (defun my-denote-journal ()
    "Create an entry tagged 'journal', while prompting for a title."

  ;; Denote DOES NOT define any key bindings.  This is for the user to
  ;; decide.  For example:
  (let ((map global-map))
    (define-key map (kbd "C-c n j") #'my-denote-journal) ; our custom command
    (define-key map (kbd "C-c n n") #'denote)
    (define-key map (kbd "C-c n N") #'denote-type)
    (define-key map (kbd "C-c n d") #'denote-date)
    (define-key map (kbd "C-c n s") #'denote-subdirectory)
    (define-key map (kbd "C-c n t") #'denote-template)
    ;; If you intend to use Denote with a variety of file types, it is
    ;; easier to bind the link-related commands to the `global-map', as
    ;; shown here.  Otherwise follow the same pattern for `org-mode-map',
    ;; `markdown-mode-map', and/or `text-mode-map'.
    (define-key map (kbd "C-c n i") #'denote-link) ; "insert" mnemonic
    (define-key map (kbd "C-c n I") #'denote-link-add-links)
    (define-key map (kbd "C-c n l") #'denote-link-find-file) ; "list" links
    (define-key map (kbd "C-c n b") #'denote-link-backlinks)
    ;; Note that `denote-rename-file' can work from any context, not just
    ;; Dired bufffers.  That is why we bind it here to the `global-map'.
    (define-key map (kbd "C-c n r") #'denote-rename-file)
    (define-key map (kbd "C-c n R") #'denote-rename-file-using-front-matter))

  ;; Key bindings specifically for Dired.
  (let ((map dired-mode-map))
    (define-key map (kbd "C-c C-d C-i") #'denote-link-dired-marked-notes)
    (define-key map (kbd "C-c C-d C-r") #'denote-dired-rename-marked-files)
    (define-key map (kbd "C-c C-d C-R") #'denote-dired-rename-marked-files-using-front-matter))

  (with-eval-after-load 'org-capture
    (setq denote-org-capture-specifiers "%l\n%i\n%?")
    (add-to-list 'org-capture-templates
                 '("n" "New note (with denote.el)" plain
                   (file denote-last-path)
                   :no-save t
                   :immediate-finish nil
                   :kill-buffer t
                   :jump-to-captured t)))

What do I miss?

Does the second evaluate to the same directory as the first? expand-file-name seems unnecessary (or causes it to be set to the wrong dir name ).

That was a hint in the right direction…trying to update IDs, I discovered that org-roam-db-location is pointing out at /$HOME/.config/emacs/var/org//org-roam.db - it must be some of those Emacs-28.x features…

Then I found out that sqlite3 package was not installed by default and had to re-in stall emacs-sql in order to build binary - I just restored my data from backup, but migrated from Debian/Sid to Fedora (fc37).

Finally, sqlite db was looking OK, but still no graph in the browser which led me to try with Chromium and, at last, clear the Firefox’ cache. :smiley_cat:

Now I can see all the nodes, but Denote links like:

This is Denote link: [[denote:20221024T100301][link]]

are not rendered, while the ones created with org-roam like:

the org-roam link: [[id:20221024T100301][another link]]

are rendered, so I do wonder if it is possible to achieve complete interoperability between org-roam and Denote in order to see in Denote links in org-roam-ui?

You just need to use ID link with Org-roam. Denote will see this as a backlink too. No need for denote: link type.

As far as I have seen, the custom link type denote: is only used to create the link between Denote notes as a button at the moment; you click on it with a mouse. The keyboard operation seems to come from Org-mode itself.

Denote does not rely on this button to recognize links between notes; just the ID as a string (try typing an ID and a backlink should appear). It’s all based on regex and file name convention.

In the backlink buffer, only one link will appear for a file, so multiple occurrences within a file does not do anything extra for Denote’s backlinks.

So far my conclusion is that there is no additional finctionality from using Denote with Org-roam at the moment — functionally, Org-roam is a complete superset of Denote.

It’s easy to learn and provides great documentation. It is built with a completely different set of built-in functions, so it’s useful in learning Emacs and Elisp. But not really necessary as a user for note-taking if you are happy with Org-roam.

Ahh, that is great!

What about Denote’s naming scheme and renaming capabilities?

For me, at the moment, the most important thing is that I completely abandoned the idea to use apps like Logseq/Obsidian and to focus on Emacs instead…

This is a good point.

The capture template can have the naming scheme and it’s more flexible in that it can have different ID format easily. So to me, Denote enforces a good convention and Org(-roam) capture provides more flexibility.

With capture, tags might be a challenge if you like the multiple tags in the file name AND in the frontmatter.

The file name change function is also useful with integration with Dired — multiple file names can be changed in one operation. This is nice.

So… I agree that tags and file name operations are good additional functions if you find them useful.

I use only a single tag per file and don’t change it. I don’t change file names, either. So I am in the user group who does not benefit much from these Denote features.

Denote is fun to play with and reading its documentation is fun too, so it gives me a lot of more toys :slight_smile: