zkc - My Second Attempt at Zettelkasten

This post is about my Zettelkasten cli tool that I made. I find zkc to be helpful and use it daily now. The reason why this post is subtitled "My Second Attempt at Zettelkasten", is that I made a different cli Zettelkasten tool before. And even blogged about it! However, it was not effective. My first go at it was a big hack and wasn't faithful to the original text. I wouldn't say I liked using it and thereby didn't write any notes down. So I sought to build a different one.

One of the goals was to be more faithful to the text of Zettelkasten. Despite all the different writings of Zettelkasten, the original version will always be the best reference point. You can find an English translation here.

My summary of that text is that your note system has to be a completely flat hierarchy. Forget about a million nested folders. This system needs to be easily searchable and focus on communication. I'll go into more depth about that later.

One of zkc's most significant deviations from the original Zettelakasten text is about 100 years of modern technology. The original paper described using note cards and a filing cabinet. zkc contains them all in a single sqlite3 file. I find this better than a bunch of text files scattered everywhere. This setup reminds me of a notebook, journal, or diary. The database is the modern form of the filing cabinet. By using it, I am extending the power of Zettelkasten, not betraying it.

In a few weeks, I did the bulk of the coding. I've been using it more than I've been working on it, which is much better than I can say about my other projects. Besides a few bug fixes, the most significant addition was adding the 'tail' keyword. I'm still surprised at how simple the code turned out. The whole thing clocks in at less than 1500 lines of C code.

Communication - The Inbox

With zkc, my main goal was to make it easy to add notes. My last approach required doing all the linking and organizing upfront. However, this is not productive when you are in the heat of the moment, focused on something else. To remedy this, I added the concept of the inbox. This concept should bring to mind email. However, with zkc, you are writing to yourself. Well, your future self. The note gets stored in the inbox, then, in a similar process as cleaning out your email, you go through the inbox later to tag, link, and organize. Eventually, the notes get archived. Archiving a note removes it from the inbox. The note still exists in the Zettelkasten graph and can be referenced by its UUID. Going through zkc's inbox is like cleaning out your email inbox. Great for passing the time and adding some organization to your life.

Heads and Tails

Since copying pasting UUID's is a delicate process that isn't always friendly to humans. I implemented two keywords: head and tail. If you think about zkc's inbox like a list, the head is the first note in the inbox. In other words, the most recent. The tail is the last note in the inbox. In other words, the least recent. Head refers to the note at the top of your inbox. While tail refers to the note at the bottom of your inbox. Having both of these helps when navigating or linking different things.

Often I'll want to edit the last note to add things. To do that:

zkc edit head

You can use these keywords for any command and in any combination.

zkc link head tail

The above is a sound set of commands for zkc.


A nice feature of sqlite3 is it comes with multiple search capabilities. First, we can query a note by UUID, look up a note's list, or even search a list of notes with a tag. Another feature is search by text. A feature I use all the time. I can't remember UUID's or if I even tagged something. Sometimes I only remember the vague idea of something. With search by text, I can search notes by a keyword, and it will bring up matches. Powerful searching features are where a SQL database shines over a physical filing cabinet.

Future Work - Data Replication

I knew that something missing would reveal itself after using zkc for some time. The missing feature I've found is syncing databases across multiple machines. This implementation would be trivial, using dropbox and text files. Currently, I'm using rsync and pushing and pulling from a central server. The problem is that notes might be overwritten if the databases are not in sync. I've come up with a solution conceptually and will be working on it in the future.

Project Link

You can get a copy of the code and try it out here. Detailed instructions on building and using zkc are in the README. zkc help will also display instructions.

Content for this site is CC-BY-SA.

More Posts