This is the second part of a 3 part series:

  1. Introduction, Logseq and Termux on mobile
  2. Improving Logseq and Org-roam interoperability (this part)
  3. Automating synchronisation

This part covers my Emacs configuration and package to enable Org-roam and Logseq interoperability.

I personally use Emacs on my desktop and Logseq on the go, but if you plan to use both on the same machine, this post should apply as well.

Org-roam configuration

I’ve introduced some of it in my previous post, to detail Logseq’s configuration. This is the gist of it:

:preferred-format :org             ;; required!
:pages-directory "pages"           ;; default
:journals-directory "journals"     ;; default, must match `org-roam-dailies-directory`
:journal/page-title-format "yyyy-MM-dd"   ;; match with `org-roam-dailies-capture-templates`
:journal/file-name-format "yyyy-MM-dd"    ;; match with `org-roam-dailies-capture-templates`
:preferred-workflow :todo          ;; recommended
:property-pages/enabled? false     ;; recommended, disable property pages

Here we’ll focus on Emacs & Org-roam configuration. You can also refer to my current setup, if you need to see the full configuration.

Directory layout

This is how my directory organisation currently looks like:

~/
└── Notes/
    ├── ...              # Org stuff in here
    └── roam/            # Org-roam stuff in here
        ├── .git/        # Use Git for synchronisation
        ├── assets/      # Use for attachments too
        ├── journals/    # All dailies go here
        ├── logseq/      # Logseq's own space, Org-roam must ignore it
        └── pages/       # All notes go here

I nested my Org-roam directory under my Org directory for historical reason. If you are starting fresh with Org-roam & Logseq directly, this distinction is not necessary.

Here is how you can configure Emacs to achieve the above:

(setq org-directory "~/Notes/"
      org-roam-directory (file-truename (file-name-concat org-directory "roam/"))
      org-attach-id-dir (expand-file-name "assets" org-roam-directory)
      org-roam-dailies-directory "journals/"
      org-roam-file-exclude-regexp "\\.git/.*\\|logseq/.*$")

The last line is essential to ensure that Org-roam ignores the logseq directory.

Org-roam capture

Capture is responsible for determining notes location when you create them. Therefore you should update your capture template(s) to match Logseq’s directories. Your Emacs configuration should minimally look like:

(setq org-roam-capture-templates
   '(("d" "default" plain
      "%?"
      ;; Accomodates for the fact that Logseq uses the "pages" directory
      :target (file+head "pages/${slug}.org" "#+title: ${title}\n")
      :unnarrowed t))
   org-roam-dailies-capture-templates
   '(("d" "default" entry
      "* %?"
      :target (file+head "%<%Y-%m-%d>.org"
                         "#+title: %<%Y-%m-%d>\n"))))

Pay attention to page/${slug}.org in particular. If you have configured Logseq differently for some reason, adjust accordingly.

Task management

Logseq task management is pretty basic, but Org is very flexible and can be easily extended beyond what Logseq does. If you want complete interoperability, your Emacs configuration should contain:

(setq org-todo-keywords '((sequence "TODO(t)" "DOING(s)" "|" "DONE(d!)")
                          (sequence "[ ](T)" "[-](S)" "[?](W)" "|" "[X](D)")))

Logseq’s equivalent is:

:preferred-workflow :todo

You can keep the :now style and configure Org accordingly, TODO simply felt more natural when using Emacs.

Logseq provides the user with 2 choices of link format when using the Org format. Neither choice is perfect, so it depends on your use case:

  • Fuzzy links (or internal links):
    • Style: This is a link to a [[Note]]
    • Pro: Easy to capture, edit, especially with the limited mobile screen estate.
    • Cons: Ambiguous (hence the name) in certain cases, e.g. when the title of a heading matches with the link (Org internal link).
    • When to use: You create many small notes (Zettelkasten style) and notes are shorter.
  • File links:
    • Style: This is a link to a [[file://../pages/note.org][Note]]
    • Pro: Unambiguous
    • Cons: Because of a bug in Logseq, when the target note does not yet exists, the path is rendered incorrectly. It must be fixed manually every time, or it will remain incorrect even when the notes is eventually created.
    • When to use: you create fewer notes and you already use internal links in your notes.

Logseq defaults to fuzzy links and that’s the one I recommend if you can’t choose. If you prefer to go with file links, update your config.edn in Logseq with:

:org-mode/insert-file-link? true

Converting Logseq captures to Org-roam

In the last post, I’ve detailed some of the problems with using Logseq out-of-the-box with Org-roam. As a recap, the biggest issue is how Logseq and Org-roam differ on links: Logseq uses internal links or file links as external links, while Org-roam relies on ID links.

I’ve created an Emacs package named logseq-org-roam (Github) to address this problem and some others. Assuming you have straight.el & use-package.el, you can install it with:

(use-package logseq-org-roam
 :straight (:host github
            :repo "sbougerel/logseq-org-roam"
            :files ("*.el")))

Invoking logseq-org-roam crawls your entire Org-roam directory, to migrate Org files edited with Logseq as Org-roam files:

  • Adds missing ID for each notes, so that Org-roam can index them
  • Adds missing titles for each notes
  • Converts all links to ID links, when they match an existing note; works with both fuzzy and file links
  • Converts Logseq aliases to Org-roam aliases

These 4 actions fix much of the friction between Org-roam and Logseq, and make both application interoperable. logseq-org-roam is capable of more: it can use cache information from Org-roam in order to speed up its operations, it can even capture new notes.

logseq-org-roam will however break some things for Logseq as I mentioned in Part I (backlinks and graph). Here, I assume that Org-roam is your main note-taking tool, and Logseq is used to take Org-roam on the go.

When installed and used for the first time, I recommend to invoke it with C-u M-x logseq-org-roam: it will parse all Org-roam files and update the ones created or modified with Logseq. Afterwards, you can use M-x logseq-org-roam which works incrementally by skipping cached Org-roam files.

I recommend that you use git or another source version control before using logseg-org-roam in case you are not happy with the changes. When you invoke logseq-org-roam, it creates the buffer *Logseq-org-roam <org-roam-directory>* which you can consult to see the modifications made.

logseq-org-roam comes with a hook which you can customize to automatically sync the Org-roam cache after files are updated:

(add-hook 'logseq-org-roam-updated-hook #'org-roam-db-sync)

Workflow and remaining frictions

If you’ve followed the guide so far, you’ve installed Logseq on your phone, you’ve setup your version control and you’ve tested the interoperability of Logseq with Org-roam, you should have a good idea if you want to use this regularly.

Your workflow at this point, looks as such:

  • When editing notes on your phone:
    1. git pull on Termux
    2. Edit notes
    3. git commit -a -m "Update from phone"; git push
  • When editing notes on your desktop
    1. git pull
    2. Invoke logseq-org-roam in Emacs
    3. Edit notes
    4. git commit -a -m "Update from desktop"; git push

This is works but it’s pretty tideous: I’m sure you prefer to focus on editing notes. I do too. In my next post I’ll cover automating synchronisation between your mobile and your desktop, on top of git. With automated synchronisation, Org-roam note taking on the go with Logseq feels natural, almost magical.