Skip to content
Zettels is a command line tool implementing Niklas Luhmann's system of a "Zettelkasten".
Python Makefile
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
zettels 0.6.0 Jul 28, 2017
.gitignore v0.1.0 May 19, 2017 0.6.0 Jul 28, 2017
LICENSE Initial commit May 19, 2017 0.6.0 Jul 28, 2017
Makefile added Makefile May 31, 2017 0.6.0 Jul 28, 2017 0.6.0 Jul 28, 2017


Zettels is a command line tool implementing Niklas Luhmann's system of a "Zettelkasten".

It's still in alpha stage and probably very buggy.

What does Zettels do?

Zettels is a command line tool to index markdown files (your zettels). It reads YAML-metadata blocks as defined by pandoc and also parses the markdown hyperlinks in each file.

The resulting index contains the metadata and the targets of the hyperlinks.

Have a look at the files in examples/Zettelkasten and examples/index.yaml to get a better idea.

Zettels can also be used to query the index. The output can then be piped to other tools (like grep or as arguments for the text editor of your choice).

It's intended to be used for a "Zettelkasten" like Niklas Luhmann used it.

What the heck is a Zettelkasten?

"Zettel" is German for "note" or "slip of paper". "Kasten" is German for "box". Think of old style library catalogues.

Obviously, this piece of software is not a box of paper sheets. However, Niklas Luhmann used such a box in a very specific way for his academic work.

A wonderful introduction in Luhmann's system of a Zettelkasten are the slides of a talk by Daniel Lüdecke: Introduction to Luhmann's Zettelkasten-Thinking

In Luhmann's own words: Communicating with Slip Boxes (translation of "Kommunikation mit Zettelkästen").

If you speak German, there's more:

What, no GUI?

True. A GUI for querying the index would be nice. However, as such, Zettels doesn't provide one. It is intended to be used in a toolchain of UNIX-tools.

I myself edit my Zettelkasten in my favourite text editor and have created a little module that allows me to query its index from there. So, if you use Textadept or don't care which text editor you use, have a look at ta-zettels.


If you're looking for a GUI, all-in-one approach to implementing Luhmann's idea into software, I can recommend Daniel Lüdecke's Zettelkasten (sjPlot/Zettelkasten).

Installation and setup

  1. Install using pip (or pip3, depending on your OS): pip install zettels
  2. Run zettels --setup – follow the interactive setup process
  3. Run zettels -su once to initially build the index.


Run zettels -h for a complete list of options. Some examples:

Build or update the index:

zettels -su

Shorthand for --silentupdate

Querying the index

Show a list of all zettels:


Show a list of all zettels, but update the index first:

zettels -u

Show info about a specific zettel, e.g.


Show info about two zettels, e.g. and


Show a list of followups of a specific zettel, e.g.

zettels -f

Show a list of zettels a specific zettel links to, e.g.

zettels -l

Show a list of zettels linking to a specific zettel, e.g.

zettels -i

And finally, a bit of fun with pipes: Let's say you want to see which zettels apart from itself link to the followups of

zettels -f | zettels -i | grep -v

Try it with example data

Run e.g.

zettels -s examples/zettels.cfg.yaml examples/Zettelkasten/

Zettel format

Zettels doesn't require your markdown files to have a metadata block. But to be really effective parts of your Zettelkasten, a YAML metadata block containing an entry for title, tags and followups is necessary.

title:  'Example Zettel'
tags: [example, question]
followups: [, subdir/, ../]

If no such metadata is present, Zettels will replace it with appropriate "empty" values in the index:

  • title: "untitled"
  • tags: "[]"
  • followups: "[]"

Instead of finishing the metadata block with ... you can also use ---.

title:  'Example Zettel'
tags: [example, question]
followups: [, subdir/, ../]

In fact, a zettel file may contain several YAML-blocks. However, Zettels will only parse the first one. The metadata block may contain a variety of other entries (e.g. author, date) – maybe for other tools, like pandoc – but those other entries are ignored by Zettels and do not become part of Zettels' index.

To manually link between zettels, use the "inline syntax" for markdown hyperlinks:

[link text](url)

Links between zettel files should be relative links. The same is true for entries in followups.

Output format

The output can be tweaked to your needs. In the settings file (default: ~/.config/zettels.cfg.yaml), you'll find two settings:

  • outputformat - standard format
  • prettyformat - used when Zettels is called with the --pretty flag

These output formats are given as Python Format Strings. Query output consists of two fields that these format strings can process:

1. title - accessible by `'{0[0]}'`
2. path (relative to the Zettelkasten directory) - accessible by `'{0[1]}'`

By default the formats are:

outputformat: '{0[1]}'
prettyformat: '{0[0]:<40}| {0[1]}'

Standard outputformat just outputs the path(s) of the query results, prettyformat is a pseudo-table with the title(s) of the query result in the first column (which is at least 40 characters wide), and the path(s) in the second column.

The output format can also be tweaked on a per call basis with the -o flag, that takes a custom output format.

See the Python Format String Syntax for details.


  • Python 3.x
  • grep & find– Your Python runtime must be able to find and execute the UNIX tools grep and find. Zettels is tested against GNU grep and GNU find, but other implementations should be fine, too.
  • PyYaml
  • pathspec>=0.5.0
You can’t perform that action at this time.