Md-roam: Use Markdown with Org-roam V2

Hi all,

Just want to quickly show my humble Org-roam plug-in I named “Md-roam”. With it, you can use Org-roam with Markdown together with Org files (yes, you can mix them in a single Org-roam directory). I finally got it to work with V2.

I don’t intend to make it to MELPA or any other public package repositories at this stage; it is meant to be my personal enhancement to Org-roam. If this is OK with you folks, you are welcome to try it.

I use it everyday now, so it works as much as I want it to be. I use iPhone and iPad when I’m not at the desk with my laptop. I want to take notes on my mobile devices and sync them with my laptop. As Markdown offers more options for note-taking on iOS, I want the bridge between Markdown and Org-roam. Md-roam is the bridge :slight_smile:

One remark for those interested: I don’t export/publish my notes, so Md-roam does not really do anything for the process. The [[title/alias]] wiki links work only within Org-roam (I use its database to resolve IDs). If you want to export md files with these links that work outside Org-roam, you will need to resolve the links yourselves somehow.


From Md-roam’s GitHub README:

  1. Title and other meta data in the YAML front matter
  2. #tag support to categorize notes
  3. Note as a reference material (literature notes or notes on website) with roam_refs:
  4. Aliases of a note with roam_aliases: in the YAML array syntax with ["alias1", "alias two"]
  5. Link with [[wiki-link]] syntax that appears as a backlink and “in-line search” with Company or Corfu ; you can use the title or an alias of a note
  6. Citations with Pandoc style [@citekey] , @citekey -@citekey , etc. for Markdown files; for Org, Org-ref or Org-cite styles as Org-roam support them
  7. Markdown and Org citations for reference materials; they appear in the reflink section
  8. Backlinks between Org and Markdown files both ways; you can mix both formats in a single Org-roam database
  9. Org-roam standard backlink buffer with no modification to the database schema and backlink buffer
  10. Partial support by Org-roam-ui (ORUI)

ORUI with Markdown files is already functional and useful for most cases. The links work. As of 2021-11-10, it’s “partial support” because the preview of note on the right panel is not entirely compatible with the Markdown format yet – it is designed for the Org format. The headings with # are interpreted as Org’s comment, so not displayed. The YAML front matter is not correctly rendered. All text information appears to be present but the underscore _ is interpreted as an indicator for subscript.

Animated GIF for “in-line completion” (completion-at-point function, or capf) for wiki links:

6 Likes

Hi nobiot,

Thank you for such great plugin! I believe that it is the base for extending the usability of org-roam in an area where Emacs (and Linux in general) falters: mobile devices.

Let me explain my experience and workflow because I think it may help others with similar predicaments: After reading Ahrens’ How to take smart notes, the first thing that came to my mind as an Emacs user was: “The Zettelkasten workflow he describes sounds like something org-mode would do pretty well”. I was pleasantly surprised to find out that Jethro had already invented org-roam, and I’ve been a user ever since. However, as I began my Ph.D in the middle of the COVID19 pandemic, the occasions where I had the possibility to work comfortably with my own Emacs set up were becoming more and more limited: I saw myself working most of the time at cafés with small tables where working with several books and a big laptop was difficult. I ended up buying a Bluetooth keyboard to work from my phone. Furthermore, since I began capturing a lot of information with my smartphone such as scans, voice notes (not audio files, but text from speech recognition), screen captures, etc., I had to find a way to put all that into my Zettelkasten because there’s no Emacs client on iOS.

First, I would use Evernote, but notes kept accumulating there, which defeats the purpose of the Zettelkasten (i.e., to produce a communication partner and not a collection of notes). Then, I switched to Bear, but the same problem occurred because I use Emacs from a Linux computer. In the end, as Obsidian.md had recently released an iOS app, I jumped ship. After a couple of months of using Obsidian, I have settled for the fact that neither Emacs nor Obsidian offer all the features that I need in one place, so I use both on a daily basis for different things: I write 99% of my notes (research, dailies, task management, etc.) in Obsidian, but I use Emacs (bibtex-mode, bibtex-completion, markdown-mode) for managing my BibLaTeX files, exporting my markdown notes to pdf (using custom elisp functions and pandoc) and doing bulk edits to my notes (with dired).

I am very excited to hear that md-roam is now compatible with org-roam v2 because of the prospect that it offers to work on my Obsidian vault from within Emacs. For compatibility between Emacs’ markdown-mode and Obsidian, though, I had to give up on wiki-style links, so I made a minor change to the insert part of the function md-roam-note-insert to produce markdown-links:

(cl-defun md-roam-node-insert (&optional filter-fn &key templates info)
  "Find an Org-roam node and insert (where the point is) an \"id:\" link to it.
FILTER-FN is a function to filter out nodes: it takes an `org-roam-node',
and when nil is returned the node will be filtered out.
The TEMPLATES, if provided, override the list of capture templates (see
`org-roam-capture-'.)
The INFO, if provided, is passed to the underlying `org-roam-capture-'."
  (when (md-roam--markdown-file-p (buffer-file-name (buffer-base-buffer)))
    (unwind-protect
        ;; Group functions together to avoid inconsistent state on quit
        (atomic-change-group
          (let* (region-text
                 beg end
                 (_ (when (region-active-p)
                      (setq beg (set-marker (make-marker) (region-beginning)))
                      (setq end (set-marker (make-marker) (region-end)))
                      (setq region-text (org-link-display-format (buffer-substring-no-properties beg end)))))
                 (node (org-roam-node-read region-text filter-fn))
                 (description (or region-text
                                  (org-roam-node-formatted node))))
            (if (org-roam-node-id node)
                (progn
                  (when region-text
                    (delete-region beg end)
                    (set-marker beg nil)
                    (set-marker end nil))
                  (insert (concat "["
                                  (cond
                                   ((eq md-roam-node-insert-type 'id)
                                    (concat description "](" (org-roam-node-id node) ".md)" ))
                                   ((eq md-roam-node-insert-type 'title-or-alias)
                                    (concat  (org-roam-node-title node) "](" (org-roam-node-id node) ".md)")))))
                  ;; for advice
                  t)
              (org-roam-capture-
               :node node
               :info info
               :templates templates
               :props (append
                       (when (and beg end)
                         (list :region (cons beg end)))
                       (list :insert-at (point-marker)
                             :link-description description
                             :finalize 'insert-link)))
              ;; for advice
              t)))
      (deactivate-mark)
      ;; for advice
      t)))

This works for my workflow because I keep all my Obsidian notes in one folder and I name all my notes as “YYYYMMDDHHmmss.md”. Likewise, for the “id” property in the YAML front matter, I stick to the convention “id = note title” (kinda the way it was in org-roam v1) because Obsidian does not yet have the equivalent of org-id to identify nodes, so linking to headlines within a note, although supported in Obsidian, is not as robust as org-roam’s way of dealing with the problem. For now, sticking to the principle of “1 note = 1 node” as in org-roam v1 hasn’t affected my workflow, but it may to other people’s. (As a side note, since we historians work with so many references (several editions of the same work in different languages, different translations, etc.), I decided to use the “YYYYMMDDHHmmss” format for my BibLaTeX entries because I was wasting too much time maintaining my bibliography files and synchronizing that information with my literature notes. I did the change to this key format earlier this year, and I haven’t looked back).

The only thing I haven’t figured out yet is how to have the completion system produce markdown links instead of wiki links when typing [[ in a markdown file.

1 Like

Which wiki-style link feature did you have to give up? Obsidian’s or Md-roam’s?

If I remember correctly, Obsidian’s is a file name without the .md extension. It shouldn’t be too hard to do — it’s the feature of Md-roam V1 and the stock Markdown-mode. You might like to take a look at the V1 source in the repo.

I don’t think I would re-implement it myself any time soon, though.

For this… I think you’d just need to convert the double brackets to the markdown link here, or the exit function right after it.

Also… Thank for the detailed portrait of the real situation. And for the code.

I was thinking of supporting the normal markdown link somehow. Perhaps as a configurable switch, and per-call switch by C-I. I might be able plug in your mod. Let me see how I might go with this idea.

I would not have the capacity to specifically support the Obsidian format, but if it can be done as a by-product, I’ll be happy. Let me see what I can do.

Is this in fact this?
id = filename (without .md)

If so… my early version in fact had a customizing option to support it. I removed it for simplicity. I might put it back on??

EDIT: I was mistaken… Thought removed it but I didn’t.

This is not relevant for your case anyway because it’s in the node-insert function you override. Let me think it through. I just came back to my desk to have a better look.

Apologies for a series of quick responses – I was on iPhone… Not the best to read on it.

Does this format enable compatibility with logseq and/or Obsidian?

I can’t tell. I tried to keep V1 compatible with Obsidian, but I stopped this for V2. I believe the wiki link in Obsidian is [[file name]], and md-roam now uses either [[title]] or [[id]]. I have no idea about logseq.

I see. That’s an interesting option, thanks for putting out all these cool tools in the org ecosystem! I share your concerns, but from my view, an org-mode based bridge between org-roam and logseq would seem like a more promising approach.

I love org-mode and Emacs and don’t want to stop living inside Emacs. However, it’s a shame that org-mode is locked inside Emacs. The Markdown ecosystem has a bunch of advantages over org, mainly integration with other non-Emacs tools and – most importantly – non-Emacs users. It’s very hard to share and collaborate using org with non-Emacs users. Moreover, org-roam is great and it’s evolving, but there are still many important features missing. Queries come to mind, which I think will get better over time, but then also more generally support for multimedia and mobile.

logseq has org-mode support and it’s all plain text files and they can be edited just fine with Emacs and org-mode. We can still use Emacs and all our lovely org things. But logseq has more features and can be used by anyone without any prior knowledge and setup of Emacs. So I think logseq could work as the “app” for org-roam that nobody in the org ecosystem will build. From my (limited) understanding, not much would be needed to create a bridge between org-roam and logseq. I think it’s mainly the difference in IDs vs. wiki-like links. There might be some other smaller syntax deviations, but I haven’t seen anything major. From my perspective, having such a bridge this would be a huge win for org -mode (and logseq)!

The problem is I can’t implement anything, so these are just empty words compared to actually putting out a tool like yours, but I wanted to share my thoughts at least :slight_smile:

Sure. You have your own needs, and logseq and org-roam may be the best combination for you.

I don’t think I have expressed my “concern”, in the sense of “worry”. I just have my own needs of connecting the markdown editing app (iA Writer) on iPad / iPhone with my note-taking app on my Windows and Linux laptops. I wrote md-roam to fill this needs for me. It is a good-enough solution for my needs as I don’t need features for export, share, or collaboration. I don’t know if Obsidian or logseq provide them, though.

Thanks, I didn’t want to put words in your mouth, sorry.

I just got excited when I saw that logseq supports org-mode, and I do believe that it has huge potential for people who love Emacs and org-mode, but want to also access, edit, and share stuff outside of Emacs. Like on mobile, as with your example. Just tried it again with the new version of logseq and most things work out of the box. So I just wanted to point to that option, but it’s good to hear your Markdown setup works well, too :slight_smile:

1 Like

No no, no worries. I keep coming back to pen an paper for “mobile” note taking… :sweat_smile:

1 Like

Like many others, being able to create and edit markdown files from my mobile device within my org-mode dominated notes database is an important use case.

I just wanted to note here that @nobiot 's latest md-roam package works with the latest org-roam 20220804.437 from melpa. See below for the configuration.

With this, I get seamless org-roam-node-find across org and markdown files. Thank you @nobiot !

;; thanks to nobiot we can include md files with our org-roam database!
;; as per the docs https://github.com/nobiot/md-roam#basic-configuration
;; md-roam-mode should be active before org-roam-db-autosync-mode
(use-package md-roam
  :quelpa (md-roam :fetcher github :repo "nobiot/md-roam")
  :config
  (setq org-roam-file-extensions '("org" "md"))
  (md-roam-mode 1))

;; this line should already be somewhere in your org-roam config
;; activate org-roam-db-autosync-mode
(org-roam-db-autosync-enable)
2 Likes