Lesson from Orgmode: Embracing UUID's in Markdown

Published on:2024/12/04
Banner for Lesson from Orgmode: Embracing UUID's in Markdown

Introduction

I recently escaped Emacs/Orgmode's clutches, understanding there's only so much you can do with a - although open source - non-standard, single implementation document system running on software almost twice my age relying on the world's worst lisp where debugging is an interactive adventure in a often irreproducible environment.

Despite the time spent moving to and then away from Emacs, this was not wasted time and many concepts from Orgmode (or more accurately its ecosystem) were worth keeping and reimplementing somewhere else. One such concept is the idea of relying on UUIDs in documents rather than file names.

So moving from Orgmode to Markdown, let's also move away from Elisp and embrace JavaScript's safety and coherence – because nothing says 'upgrade' like trading dynamic scoping for prototypal inheritance and other proxies. (After all, unexpected runtime behavior is much easier to rationalize when it comes from a familiar source).

We have a (loose) document format, a language, we just need a runtime. This is where Obsidian comes in, let's use that.

Advantages of UUID in Document Management

Let's briefly go over the advantages of using UUIDs in documents:

  • Reliable reference point: moving or renaming documents has not adverse effects
  • Avoiding filename collisions: or the end of "Do I already Have a 2024 - Staging deployment documentation"

Orgmode vs markdown implementation

In Org-mode, UUIDs are typically implemented using the org-id property. This property can be automatically generated and added to the properties drawer of an Org file. For example:

:PROPERTIES:
:ID:       5458d193-87ec-4457-8c22-5181b4bd90e7
:END:

This can be implemented at the document level but also at the header level which is reccuring advantage of orgmode over emacs.

Although limits can be a good thing, this can be abstracted away with various markdown implementations allowing block-level properties.

For instance, in Obsidan, the task plugin would allow us to retrieve something like: - [ ] My block [ID:: abxyz]

In markdown, UUIDs would be implemented at the document level through the frontmatter

ID: 5458d193-87ec-4457-8c22-5181b4bd90e7

UUID in Obsidian

Obsidian natively works with UUIDs to some extent by loosely enforcing unique filenames.

Filename collision in a vault is handled gracefully but at the potential loss of functionality of certain API calls that expect unique filenames or even right in the editor. For instance links like this may not work: [[MyFileNameWithoutExtensions|The Pretty Name of This Link]].

Properly, random UUIDs

Ok, so documents names are technically UUID's, how can we automatically generate them and still have the oppurtunity to enter a human-readable title?

Let's use the QuickAdd plugin, a templating and macro running extension for Obsidian.

  • Note(1): that the only part of that snippet that relies on the QuickAdd API is the inputPrompt, the general logic applies anywhere in Obsidian.
  • Note(2): crypto might not be available on mobile, I haven't tested but it probably relies on Node.js implementation.
const uuid = crypto.randomUUID(); // generate a new random UUID
const title = await quickAddApi.inputPrompt("Enter a title for the note:"); // Get title value from 
const newFilePath = `notes/${uuid}.md`; // if wanting to drop the new document in a specific folder
await app.vault.create(newFilePath, "Insert some default content here if needed"); // create the file
const file = app.vault.getAbstractFileByPath(newFilePath); // ask obsidian for the file back as a TFile object
await app.fileManager.processFrontMatter(file, (frontmatter) => { // Modify the property of the frontmatter using the title and UUID 
  frontmatter.title = title;
  frontmatter.ID = uuid;
  frontmatter.tags = "inbox";
});

This script generates a new UUID, creates a new note with the UUID as the filename, ask the user for a title and then includes the UUID and title in the frontmatter.

Displaying the title

Great, we have randomly generated unique filenames but 9ea87889-e14b-4869-9e83-299bbccf11cc.md is not such a great title to remember or to look at while editing.

This is where The FrontMatter Title Plugin comes in.

This can be easily set up to show as a title the value from a field in the frontmatter.

By default, it expects title and can be enabled to work in

  • the filetree
  • the search results
  • the effective title while editing a document
  • in tab names
  • and maybe most importantly in the suggestion candidates when auto-completing for creating a new link.

Note that in this context, files are never renamed, but we only chnge the value of the title field and whether or not links are updated does not matter (although the frontmatter title plugin will do it automatically)

Conclusion

Transitioning from Org-mode to a Markdown-based system using Obsidian (and Neovim) has been a breaze so far, taking the concepts from Orgmode/Emacs and implementing them better and faster. Giving up very little while gaining a lot, both in the quality of the editor/API but also in features (for instance Orgmode does not support lists as properties, which is absolutely not a problem in a frontmatter's yaml)

While Emacs is a decent Elisp IDE, one has to realize that Elisp has terrible Orgmode bindings (ironic, since it's the only implementations of it). Using dataview and vanilla Obsidian API, one can get a universal document object returned from a single UUID/filename argument with something like:

let myDocument = dv.page("abc-123")

I will not embarrass myself by trying to write the 5-10 lines of Lispy nightmare in order to compare it to Emacs' implementation.