‹ go back

A Plaintext Zettelkasten.

Published 15 August 2021 at Yours, Kewbish. 3,210 words. Subscribe via RSS.


With my notetaking workflow, I enjoy working on the meta-flow, building tools, integrations, and new features for myself, just as much as I enjoy actually writing and filling out the content there. I’ve recently been fiddling a bit more with my system, integrating additional principles of the wildly popular Zettelkasten system, and having tonnes of fun messing around with command-line tools and Vimscript. In fact, a couple weeks ago, I sat down and worked through my existing notetaking system wishlist: searching within files, jumping to files from outside of Vim, finally integrating tags and intra-note navigation, and more. I’ve wanted to implement these for a while now, so finally getting them integrated with my Vim setup was a very satisfying weekend accomplishment.

As I finished up my setup, I also learned about Augmented Minds 2021, a short unconference that took place a couple weeks ago. Prominent speakers in the HCI space (well, in layman’s terms, cool people on Twitter) and a morning of discussion about tools for thought? That sounded like a dream come true - so I spontaneously registered for a ticket. While scanning the OpenCollective page, I noted that they were taking proposals for shorter talks throughout the conference: in fact, the entire unconference was built around these smaller breakout sessions. It seemed like a casual, fun way to share on a topic I’m passionate about, and giving lightning talks at other conferences was something I was considering in the future anyways. Long story short, I impulsively signed up to deliver a talk on my Zettelkasten-in-progress, the first topic I could think of off the top of my head. So, among much more qualified speakers and more engaging presentation topics:

Vim + FZF + RipGrep = A Plaintext Zettelkasten*
A demo of my notetaking system, built around Vim, FZF (and FZF.vim), and rg, followed by an open discussion on building your own Zettelkasten systems.

popped up in the schedule of events. I was decently nervous, but the opportunity to give a talk, and especially one in such a welcoming, open space, was something I was definitely excited and grateful for.

This post is a standalone discussion (and a bit about the experience of actually delivering the talk) on my current pseudo-Zettelkasten system adapted directly from my talk, but is the second part of my series on Augment Minds 2021 that I started with this post. If you’re here to nerd out with me about personal knowledge management, this’ll likely be the more attractive post, but feel free to check that one out as well - I go a bit more in depth on some of the amazing talks from the unconference.

Here’s a Video

… well, soon, anyways. I’ll update this section with the talk recording as soon as it comes out.

My Notetaking System

My Zettelkasten (or, really, pseudo-Zettelkasten) is entirely local and entirely Markdown, and my workflow with it involves a combination of Vim, FZF, and rg. If you’re not familiar with the concept of Zettelkasten, most people’ll point you to Zettelkasten.de, and maybe r/Zettelkasten. Look through a couple posts, and you’ll be sure to get the gist of Niklas Luhmann, the creator of the system, and what he proposed, the central concept of atomic notes, and all the hyped-up software that people tend to use with it. My Zettelkasten’s not much of a ‘proper’ Zettelkasten besides in that it borrows some of the concepts of stages of notes, and some of the concepts of interlinking, but I think it’s still interesting in terms of possible ways that it can be modified and expanded, even if you’re striving for a by-the-books Zettelkasten approach.

First, let’s look at the file structure of my system. Zettelkasten purists generally advocate a flat-file approach, with the usual argument being that your links should serve to connect and group files, instead of imposing a decision. As well, what if something belongs in two categories? Extra mental overhead, and even if you manage to subcategorize, you’re increasing the sprawl and unmaintainability of your notes - or so people tend to say. Even with all these apparent cons, in my system, I work with a bunch of folders instead. I opted for this approach mainly because I take notes over several rather disparate categories, and because it makes things easier to navigate visually in a file manager. With just my first term at university, I’ll be taking six classes, all in different topics. I have quite a bit of range with the notes, and to my brain, it makes more sense to group them in a folder. As well, with my linking system, which I’ll touch on in a bit, I can still achieve the same knowledge-connecting ability.

Something else that’s a plus with having an entirely plaintext productivity system is that everything can be backed up through Git or another system. I keep a repository on GitHub, and just run a sync script through cron to commit the changes in the root of my notebook.

Source (Fleeting / Literature) Notes

What the Zettelkasten system calls fleeting, or literature, notes, I group into one big category of source notes. These are generally going to be the notes that I take from something I need to study, be it a paper, a video course on Khan Academy, or a textbook. I tend to jot quick thoughts down as I’m going through the source material, and then return to take more detailed notes in my own words either with a second pass, or pausing between sections. Notes here are almost always linear, or linear-like, where I just go through the material again in the order it was presented in the source. I find that I don’t really have time when I’m taking notes in class to go through and network and piece things together. I’m also a strong believer in the whole ‘have something ready at each stage’ methodology - I don’t want to neglect material just to add a couple linking notes. The format of these notes are also very non-atomic at this stage, since I’m generally trying to collect all the information in one place with a bit more context.

Evergreen Notes

In terms of evergreen notes, I don’t have many of them either - I’ve just gotten the linking working not that long ago, and I haven’t really been ’tending’ this digital garden for too long. However, I think my idea of these evergreen notes is more in line with the main Zettelkasten workflow. They’re drawn either from source notes, though that’s a bit rarer since I don’t really see myself having marvellous interdisciplinary connections between, say, cold fronts and public-key cryptography (yes, those are real examples - you can thank ATSC113 and my vague interest in crypto). Otherwise, they’re just collections of my own thoughts, which is usually more often where the evergreen notes stem from. Anything and everything goes here, from my thoughts on random posts I see on Twitter, to some of my life goals, as long as they have sufficient linkage surface area and context.

Here’s an example: I played with Web Monetization not too long ago, and I found a bunch of posts and talk describing why it was super great and the next big thing, which I do appreciate and support, but I came up with a couple thoughts about why it’s not quite working yet, and then I just wrote about it. Eventually, evergreen notes sometimes get promoted to their own blog post, like this web monetization one, and sometimes I translate blog posts into evergreen notes as well for older content, but let’s finally get into the components that make my Zettelkasten more unique.

My Tools of Choice

My notetaking toolkit currently includes:

  • Vim => I’d been trying Vim out ever since I was on Windows, because I kept hearing my friends rave about how efficient, customizable, and smooth everything was, so I wanted to see what all the fuss was about. Long story short, I took to the idea of modal editing, and stuck to using it as my main code editor ever since. It makes sense that I want my notes to be as easily editable as possible, so I went with what I was familiar with.
    • This also brings up the nice bonus that I can interact with code right beside my notes, and add to my notes when I’m thinking of something even when coding.
  • FZF => FZF is a fuzzy-finder tool, where you can pass in a bunch of sources, and it’ll search through all of them for you. It’s useful outside of vim for searching through files and processes, but I mostly use it in conjunction with FZF.vim, a Vim plugin that wraps a bunch of commands and everything into a very nice interface.
  • RG => Ripgrep is a search tool, written in Rust, and it’s extremely quick when searching through regexes and files. Honestly, I could have just gone with normal find, but as ripgrep integrates so well with FZF and FZF.vim, I thought I may as well integrate it.
  • CTags => CTags, or more specifically, Universal CTags, is a tagging utility that was built to be used to index code files and implement ‘jump to definition’ features and the like. In my system, I abuse its ability to define custom languages and its existing mappings within Vim to make my notes linkable and navigatable.

Everything so far has been pretty vanilla - just modified Zettelkasten workflows. Well, here begins the spicy parts: I’m first going to touch on notebook search, and how I’ve integrated ripgrep and FZF.vim with shortcuts and aliases for editing, and then linking things together in a bit. I think search and linking are two of the big features why people generally turn to things like Notion, Obsidian, or Roam instead for their personal knowledge base, since it comes with those things built in, and you don’t have to spend hours toying with Vim configs - but that’s what makes me happy.

There are a couple different things I search in my workflow: files to open, files containing specific notes, or searching through my links. The first one, files to open, is done through Bash instead of within Vim. I alias evb to1:

cd /home/kewbish/EVB/;vim -o "$(rg --files $evb | fzf)"; ctags -R .

Ignore the ctags, but for now, but what this does is change directory into my notebook, look for all files, and open the FZF fuzzy searching window. I usually know what file I’m going to work on when I’m going to take notes - like, for example, my course notes or lecture notes, so I can just open them with this.

The second mini workflow is integrated within Vim, and is a remap of a FZF command. I use

command! -bang -nargs=* Sevb 
  \ call fzf#vim#grep("rg --column --line-number --no-heading --color=always --smart-case ".shellescape(<q-args>), 1, {'dir': '/home/kewbish/EVB/'}, <bang>0)

this big blob of Vimscript to run ripgrep in my notebook folder. It looks a lot more complicated than it is, but I need to use the custom FZF.vim call because I need to a) search within file contents, as well as b) search all files within my notebook. I’ve remapped this to nnoremap <leader>se :Sevb<CR>, so a quick \se gets me what I’m looking for.


The third searching command involves tags, which was what the earlier ctags -R . was for in my bash alias. Inspired by Edwin Wenink’s plaintext Zettelkasten, I use these tags instead to link between notes. I denote a link with (#: link contents here), mostly because I’d never type (#:) in normal notetaking. It’s a bit clunky, but it also stands out visually, so I’ve stuck with it. I’ve defined this as a custom tag pattern in my ~/.ctags.d/ folder

--mline-regex-markdowntags=/(^|[[:space:]])\(\#: ([^\)]*)/\2/l/{mgroup=1}

Every time I open my notebook with evb, the tags are generated, and I can then use the FZF.vim :Tags mapping, which I have as \st, to search through my links. While on a link, I can also use this mapping:

nnoremap <leader>ln va)y:exe ":Sevb " . substitute(substitute(getreg('"'), "\(#:", "", "/g"), "\)", "", "/g")<CR>

to search through my tags, and insert it somewhere. The first block here yanks my link to a register so I can paste it, then searches my notebook for similar topics as the content of the link. I can always change what I search for, and then quickly jump to the file position and paste the link. I can also use Vim’s inbuilt :ts and g] commands to search through my links and jump to them, but I use that a bit less frequently. I think this linking system’s pretty unique, and one of the biggest features that admittedly, most other software implements out of the box, but that I finally have, in my little plaintext notebook.

The Experience

Admittedly, the decision to give the above talk was completely spontaneous, so I can’t go on about some impressive intrinsic motivation. Yes, I wanted to talk, but I’d like to think that it was more about sharing what my Zettelkasten was like. I also wanted to push myself out of my lurker-by-default existence at bigger events, and force myself to do something slightly outside my comfort zone. People talk about stretching yourself - giving this lightning talk, I think, is a great example of that. I’m not afraid of public speaking per se, but it’s one of those things I’ll have to mentally steel myself for. Being able to share on something I’ve been very into lately meant that I essentially could talk forever without a script anyways, so I didn’t have to worry about not knowing what to say. Preparing for the talk wasn’t an arduous process: mostly just piecing together past thoughts I’d jotted down or thinking through the best order to present my notebook subsections. As well, with the small number of attendees for Augment Minds in general, there’d be a minimal audience to, in the worst-case scenario, mess up in front of. Doing one slightly scary thing, but combining it with a bunch of mostly-familiar topics, is a recipe that I’ll continue to apply in other places - it brings you more positive experiences than if I’d, say, done a talk on a foreign topic with an audience of tonnes of people.

Not many people showed up to the talk, which I’ll be positive about and call a good thing. With just a few people in the room, the little discussion session we had at the end was a lot more close-knit and meaningful. Getting to talk to other people at the end was honestly the best part of the entire Augment Minds 2021 experience - I really enjoyed getting to have these small group chitchats, and talk about alternative Zettelkasten systems, so thanks to everyone who engaged in that! Here’s a brief, slightly abridged, list of the followup points that I took away:

  • I’d like to check out fzf-ripgrep.vim
    • It appears to have more builtin rg bindings, and I wonder if I can pass the directory to search more easily (to avoid the mess of Vimscript everything currently is)
  • Someone asked if I’ve considered NLP, and how can I make fancy AI tools work for my thought
    • One of the projects by the hosting organization, Autocards by Psionica, looks really interesting, especially since I’ve been looking into flashcard and spaced-repetition models recently
    • Integrating notes directly into my calendar, or being able to pull between sources, would be interesting to consider
    • Tools like Elicit for coming up with a general scheme of things and terms to dive into - sort of like mapping a field - are also very appealing
    • A ‘fancy AI’ idea: can I get some NLP tool (i.e. GPT{2, 3}) to distill information while I’m researching? Coming up with plain layman’s explanations of common things to look into would help me know what to look into first, and help me build a personal curriculum
  • Another person asked if I use other old-school Linux utilities (the examples given for ‘old-school Linux’ were sed and awk, so do with that what you will) and if they were powerful enough for me
    • I find my current toolkit powerful enough for me (right now), and I don’t plan to switch anytime soon
    • Why have I stuck to such a minimal set? It’s definitely enough for my use case, but there’s also a config barrier that prevents a lot of people from taking this route, which is 100% valid logic


Part of the reason why I like having my notetaking system in Vim, and stitched together with all these open source tools is because I feel that Vim’s kind of become my Notion, or become my Roam. Or not specifically Vim, after all, but mainly the terminal. It feels like a kind of plaintext home to me, since I spend a lot of time programming and hacking away in the terminal anyways. There’s something about being able to create a workflow that I fully understand, and that fits me perfectly, rather than have to try to slot myself into something that an external tool recommends. And I know, it’s probably a lot easier and a massive waste of time in a lot of people’s opinions for very small optimizations, but hey, it’s my notetaking system, so I don’t really have to explain myself, do I? Open source and plain text as general philosophies are some of the lesser points of my system, but I think they still matter. A lot of general purpose notetaking ecosystems like Roam cover a lot of the same features, but being able to have full control over something so integral to my learning and life is pretty important to me.

Since I gave the talk, I’ve been able to experiment with, and really put, my system to test - I’ve been working on a research project on probablistic primality testing with the Summer Research School (which was an amazing experience and program, by the way - more on it in an upcoming post). It’s a pretty number-theory-heavy field, and the first couple weeks of the program especially involved a lot of reading through the basics of modular math, theorem proofs, and processing jargon-filled papers. I’ve been taking quite a number of notes, and I’ve seen that having these improved searching and linking capabilities has significantly improved my workflow. I’m happy that I took the time to finally get the features I’d been longing for for ages finally into my system, but I think I won’t be touching new Zettelkasten ideas for a while. I try not to mess with my system too often, or else I tend to get more tweaking done than actual work - I also try to limit myself to a couple indulgences of Vimscripting and diving into other people’s systems a year. I’ll see if I need any major changes to happen in my system once September rolls around and school starts, but we’ll see - customizing my workflows is something I enjoy doing anyways.

  1. By the way, all my Vim commands can be found in my .vimrc - take a look there for my reference implementations if you want to replicate anything. ↩︎

‹ go back