Simple Zettelkasten in C

In this post I want to go over a new CLI tool that I've written and go over my thinking for why I made it. The tool szc is a simple cli interface for organizing and create zettelkasten notes.

Now before I continue I should take the time to go over what zettelkasten is. I am no expert, and this is my disclaimer that szc may not be a proper zettelkasten tool. However, I think the basic ideas are there.


zettelkasten is a knowledge management and note taking system that came from Germany. Hence the German name. For a better background check out the Wikipedia. Originally it was used with index cards, and each card has an ID. Think a random number or cryptographic ID like a hex value. Which is what I use with szc. Each card contains a short note about a single idea. Then these cards are meant to be linked together in a great big directed graph. Think mind map meets wiki. Some software tools work to actually visualize this graph. The idea is that you can start with one note and then work your way through to other notes. It is supposed to work like one's mind works. A network of ideas linked together. A proper zettelkasten tool is supposed to follow these simple basic principles.

How do you keep any of it organized? How do you know which note refers to which note? With index cards I think there would've been a natural organization. Whereas with software what is one to do? Well I decided to defy the zettelkasten Gods and add one shallow level of hierarchy that I call a hub. Which is essentially a directory or folder that contains the notes. This is inspired by the 'Structured Zettelkasten' approach that was developed in response to organizing a large number of notes. More info on structured zettelkasten can be found here.


So my experience with zettelkasten was when I tried out neuron. I found this to be really cool, it worked out of the box, and had an emacs mode. What was cool about the emacs mode was that it added 'virtual titles' to the links. The links being the hex value id's which aren't exactly human readable. This was noted to be a transgression, but certainly more user friendly.

What I didn't like about neuron was that it was quite complicated. I felt this was a mismatch for what was supposed to be a simple process. Also the installation process required the nix package manager. This to me was overkill. neuron is complicated because it has a lot of features. However, upon looking at the source code it seemed most of the code was related to rendering markdown on the web and visualizing the directed graph. While cool, I didn't use any of these features. I wanted something simple and portable. So I chose to write it in C instead of Haskell. I chose C because it fit my desired needs. To be simple and portable. Also, I like coding in C because it provides the creative constraints for me to ensure I follow that original vision.

Using szc

The first time that the szc binary is run it will automatically create a directory called zettelkasten in the root directory if it doesn't already exist. This is where all of the hubs and zettels will be stored.

The way szc works is that when the binary is run it will prompt the user with a question.

Do you want to create a new zettel, query for a zettel, or link two zettels?

To be honest, I have no idea if zettel is the correct name, but I thought it was fitting. When creating a new zettel the user inputs 'new'.

This prompts the user with a next question.

Do you want to create a new hub or zettel?

If you recall earlier, I was discussing what a hub is. Which is simply a folder that will hold the zettels. If you want to create a hub then the user inputs 'hub' and 'zettel' for to create a zettel. The name of a hub should be the name of the high level category that the zettel might belong in. It doesn't matter too much, because zettels can always be linked regardless of hub. If a user chooses hub then the user will be prompted to input the hub name. If zettel is chosen then the user will first choose a hub, and then create a zettel with a title. This will then open up the new markdown file with the user's default $EDITOR. Which can be set in .bashrc

The other options with szc are query and link. When a user is looking for a particular zettel they wrote before they can use the query option. It will first ask for the hub, and then list the zettels in that hub. The user selects the specific zettel by inputting its 4 digit id value which is displayed next to the title. This will then open the zettel with $EDITOR to be viewed.

To link two zettels one essentially goes through a similar process like query to select the two zettels to link. This then adds a tag to the bottom of the markdown file that looks like this:

LINK: foo/

That is all of the functionality for szc. Simple, right?!


Overall, I have been quite happy with this setup even though it is quite simplistic. It is easy to setup on my machines, and I find it to be a great way to keep track of notes. It is very much my extended mind. I don't have to constantly search for things I've already learned but might have forgotten about. Which overall saves me a lot of time and makes me more confident to try out new ideas that build on things I already have done. I currently use it so save small scripts or random command line instructions. There are some quality of life features that I have thought about adding in the future, but for now I am quite happy with it. Usually when I make a random tool I almost never use it after a few weeks. However, with this tool I find that I use it quite frequently!

More Posts