Zettelkasten Tool in C
Change search notes by tag to be exact match
3b772ecb — Harley Swick 9 months ago
Minor changes and formatting
98d4fba9 — Lorenzo Beretta 9 months ago
Make main.c table driven



You can also use your local clone with git send-email.



cd zkc
meson build
ninja -C build


sudo ninja -C build install


doas apk add sqlite-dev openssl-dev


sudo apt install libsqlite3-dev libssl-dev


doas pkg install sqlite3 openssl




Zettelkasten Tool in C. A featured CLI note taking tool that tries to strictly adhere to Zettelkasten method.

Recommended reading - link

The key idea is that the Zettelkasten method is more than a note taking system. It is a communication system.


zkc stores notes, tags, and links in a sqlite database stored at ~HOME/.local/zkc/zkc.db.


The recommended workflow is to create a note. All new notes are added to the inbox. The most recent note in the inbox can be referenced as "head". The oldest note in the inbox can be referenced as "tail".


zkc view head

The point is to be able to save notes as inspiration strikes. Then you can later go through the inbox to either tag, link, or delete a note. Once you are happy, you can archive the note and move it out of the inbox. While order isn't necessary, working on the head or tail note is the most convenient. Using the keywords prevents you from having to copy and paste uuid's constantly.

#Example Workflow

zkc init
zkc new
zkc inbox
zkc view head
zkc tag head foobar
zkc tags head
zkc archive head


Once notes are moved out of the inbox and into the archive you'll still be able to search for it.

zkc search foobar

This will return all the notes that have the word "foobar".

There are two types of searches: text matching and tag matching. The default is text as seen above. Which is equivalent to:

zkc search text foobar

To search for all notes that are tagged with foobar.

zkc search tag foobar


When opening an editor zkc follows the same process as git. This means it will try to see if EDITOR or VISUAL are set. If not, then it will fall back to vi. This is similar to how git works.

If ZKC_EDITOR is set it will take precedence over all other options.


The downside of using sqlite as the storage layer for zkc is that merging notes from one computer to the other doesn't work. You would overwrite data with the new copy of the database. Note systems that use a file per note don't suffer from this problem in the same way. One can store the notes in a dropbox or nextcloud and the system would sync the different files together.

In order to work around this problem, I implemented a very basic merging and diff strategy. All notes have an associated hash of the note body. The merging algorithm will check if a uuid exists in both databases. If it doesn't exist in both, it will add it to the database that is being merged into. Merges are not bidirectional. If the uuid exists in both databases, it will check the hash. If the hash is different, it will then check if the timestamp is greater. If the timestamp is greater in the other database it will update the note in the database that is being merged into. If the timestamp is less, it will keep the existing note unchanged.

The workflow when merging looks like this:

zkc diff other_zkc.db

The diff command will display any mergeable differences with other_zkc.db. If there are mergeable differences you can then run the merge command:

zkc merge other_zkc.db

After this if you run the diff command again you should see no differences.

One thing to keep in mind with this strategy is that deletes won't persist after a merge, if the database that the merge is coming from still has that note, tag, or link. The recommended workaround is after a delete, one should overwrite all copies of the database with that version. This is a downside of the simple merging strategy. The tradeoff being made to prioritize not accidentally deleting data.

#Remote Backups

Remote backups can be acheived easily with a few shell scripts and ssh.

Here is a script to push the local copy of the database:

#! /bin/sh

scp ~/.local/zkc/zkc.db foo@example.com:~

Here is a script to pull a remote copy locally:

#! /bin/sh

scp foo@example.com:~/zkc.db zkc.db

The idea is that you pull a remote copy locally, but don't overwrite your local copy. To get updates from remote, run the merge command.


Discussions and patches should be sent to:


If you are new to email based git workflows please refer to this tutorial.