Fabricius: Roam to Anki Bidirectional Sync

In May, I re-wrote my Anki to Roam sync app to use Roam’s client-side Javascript API and released it as Fabricius. After four months of personal use, it has evolved into something that I trust and enjoy using.

Fabricius provides a way to create flashcards inline with your Roam pages, and exports them to Anki on the click of a button. The synchronization is two-way, meaning that any changes to cards in Anki are synced back to Roam as well. One feature I added that has been super useful is the ability to pull in context from parent blocks. Roam Research is quite different than traditional note-taking apps because the block is the atomic unit of reference. Because of this, notes in Roam are often quite nested, and pulling in content from a single block is often insufficient to create a good flashcard See https://andymatuschak.org/prompts/: context-laden prompts help the leap from theory to practice . By providing a limited facility to pull in context from surrounding blocks, we can leverage Roam’s block structure and turn this note:

into this card:

In practice, I found that being able to pull in 2 levels of blocks was both extremely useful and sufficiently powerful. Typically, the highest level block situates the card in a broad context See https://controlaltbackspace.org/memory/designing-precise-cards/#questions-should-be-context-free: The topic or context should be stated at the beginning or near the beginning of the question, to prime your memory to retrieve the right kind of information and to facilitate reviewing cards from different subjects intermixed . This is typically a subject area, book or paper. The mid-level block provides context that is more specific to the prompt and typically contains information that makes the prompt more focused, precise, consistent and tractable. Going back to the example above, if we left out the mid-level block (tagged with #srs/cloze-g), we might get confused as to what relations are in the context of a database. With the extra context, we now know that our prompt is about relations as used in the relational model.

The card itself looks a bit cluttered and could probably be fixed with better CSS. In terms of the algorithm, if we think of individual note pages as containing forests, what the sync engine is doing is picking 3 nodes on the root to leaf path and serializing it as a single card. One thing I noticed about this is that I sometimes have to re-think how I write notes in order to accommodate the algorithm. Take for example this hypothetical note:

- This is your mind on plants - Michael Pollan #srs/cloze-t
    - Caffeine #srs/cloze-g
      - is primarily used as a stimulant
        - because it is {c1:an adenosine antagonist}.

There is no way for me to quiz myself on the fact that caffeine acts as a stimulant because it is an adenosine antagonist. I would need to refactor it like so:

- This is your mind on plants - Michael Pollan #srs/cloze-t
    - Caffeine
        - Caffeine is primarily used as a stimulant #srs/cloze-g
            - because it is {c1:an adenosine antagonist}.

Notice this isn’t entirely ideal either because the text stutters on “Caffeine”. It is better than nothing though, and allows for slightly more fine-grained control over the resulting card at the expense of having to spend some time tweaking the note structure. I’ll need to continue using this more to tell if it strikes a happy medium between hand-crafted cards and unstructured inline clozes.