dodder-onboarding

star 2

Introduces dodder, a distributed zettelkasten and content-addressable blob store. Covers core concepts (zettels, object IDs, tags, types, blobs, the store), installation via Nix, a first-steps walkthrough including repository initialization and zettel creation, and the mental model for working with dodder. Activated when a user is new to dodder, asks what dodder is, wants to get started, install, set up, or learn how dodder works.

amarbel-llc By amarbel-llc schedule Updated 5/20/2026

name: Dodder Onboarding description: > Introduces dodder, a distributed zettelkasten and content-addressable blob store. Covers core concepts (zettels, object IDs, tags, types, blobs, the store), installation via Nix, a first-steps walkthrough including repository initialization and zettel creation, and the mental model for working with dodder. Activated when a user is new to dodder, asks what dodder is, wants to get started, install, set up, or learn how dodder works. triggers: - get started with dodder - set up dodder - install dodder - new to dodder - what is dodder - dodder tutorial - learn dodder - how does dodder work

Dodder Onboarding

What Is Dodder

Dodder is a distributed zettelkasten written in Go. It functions as a content-addressable blob store with automatic two-part IDs, flat organization, and full version tracking. Think of it as Git for knowledge: every piece of content is stored by its hash, every change is recorded in an append-only inventory list, and the working copy on disk is just a checkout of what lives in the store.

Unlike traditional note-taking tools that impose folder hierarchies, dodder keeps everything flat. Organization comes from tags and types rather than directory structure. Each note (called a "zettel") receives an automatically assigned human-friendly identifier composed of two parts drawn from user-supplied word lists, producing IDs like one/uno or red/apple.

Two user-facing binaries exist: dodder and der (same tool, shorter name). A third binary, madder, is low-level and intended for internal or advanced repository operations. All three share the same Go module and source tree.

The .dodder/ directory is the store, analogous to .git/ in a Git repository. It holds all blob content (by SHA hash), inventory lists (the authoritative version history), configuration, and derived indexes.

Core Concepts at a Glance

Concept Description
Zettel A note or blob with an automatically assigned ID. The primary content type.
Object ID Two-part human-friendly identifier (e.g., one/uno) drawn from user-supplied yin and yang word lists.
Tag Organizational label attached to zettels. Plain (project), dependent (-dependency), or virtual (%computed).
Type Content format definition prefixed with ! (e.g., !md, !txt, !toml-config-v2). Types are versioned.
Blob Raw content stored by its SHA hash (blake2b-256). Same content always produces the same hash.
Store The .dodder/ directory. Holds blobs, inventory lists, configuration, and indexes. Like .git/.

Installation

Dodder is built and distributed through Nix.

Build from source

Clone the repository and build with Nix:

nix build

This produces debug and release binaries. Alternatively, enter the development shell to get dodder (and the der alias) on the PATH:

nix develop

Build with Just

From within the development shell or a configured environment:

just build

This compiles debug binaries to go/build/debug/ and release binaries to go/build/release/.

Verify installation

dodder --help

Or equivalently:

der --help

Both names invoke the same binary.

First Steps

Initialize a repository

Every dodder repository requires two word lists -- called "yin" and "yang" -- that dodder combines to generate unique zettel IDs. Supply them during init:

dodder init -yin <(echo -e "one\ntwo\nthree") \
  -yang <(echo -e "uno\ndos\ntres") my-repo

This creates a my-repo/ directory containing a .dodder/ store. The yin list (one, two, three) and the yang list (uno, dos, tres) define the ID space. Dodder assigns IDs by combining entries from these lists: the first zettel gets one/uno, the second gets one/dos, and so on. The cross-product of the two lists determines how many unique IDs are available before the lists need to be extended.

Change into the new repository before continuing:

cd my-repo

Create a zettel

Create a new empty zettel without opening an editor:

dodder new -edit=false

Dodder assigns the next available ID from the yin/yang cross-product, stores the empty blob, and records the new object in its inventory list. Output shows the assigned ID and metadata.

To preview which IDs dodder will assign next, use:

dodder peek-zettel-ids

This displays the upcoming IDs from the yin/yang combination without creating anything.

View a zettel

Display all zettels in the repository:

dodder show :z

The :z query selects the zettel genre. Output shows each zettel's ID, type, tags, and blob hash in a log-style format. For a single zettel, pass its ID directly:

dodder show one/uno

Edit a zettel

Open a zettel in the configured editor:

dodder edit one/uno

This checks out the zettel to a temporary file, opens the editor, and checks the modified content back in when the editor closes.

Add tags and set types

Create a zettel with tags and a specific type:

dodder new -edit=false -tags project,important -type md

Tags and types can also be modified after creation through the edit and organize commands.

Import content from files

Import an existing file as a new zettel:

dodder new -edit=false document.txt

Each file argument becomes a separate zettel. The file content becomes the blob, and dodder assigns a new two-part ID. Combine with -tags and -type to set metadata at import time:

dodder new -edit=false -tags reading-list -type md notes.md

Check repository status

After creating or editing zettels, inspect the state of checked-out objects:

dodder status

This displays each object's checkout state -- whether it exists only in the store (internal), is synced to the filesystem (checked out), has been modified locally (changed), or has no store counterpart (untracked). The status output mirrors the mental model of store versus working copy described below.

Checkout and checkin

Materialize a zettel as a file on the filesystem for external editing:

dodder checkout one/uno

After editing the file, commit changes back to the store:

dodder checkin one/uno

The store records the new blob content and updates the inventory list. The original blob remains in the store (content is immutable); a new blob is created for the modified content.

Mental Model

Understanding dodder requires internalizing a few principles that differ from traditional file managers and note-taking applications.

Flat, not hierarchical

There are no folders or directories for organizing content. Every zettel exists at the same level. Organization comes from tags (labels) and types (format definitions), not from filesystem paths. This eliminates the problem of deciding where a note "belongs" and makes cross-referencing straightforward.

Everything is versioned

Every change to a zettel -- content, tags, type -- is recorded. Inventory lists (text-format append-only logs stored in .dodder/local/share/inventory_lists_log) serve as the authoritative version history. The stream index (binary pages in .dodder/local/share/objects_index/) provides fast access but is derived from the inventory lists and can be rebuilt.

Working copy vs. store

Like Git, dodder distinguishes between the store (.dodder/) and the working copy (files on the filesystem). The store is the source of truth. The working copy is a convenience for editing.

  • checkout syncs objects from the store to the filesystem.
  • checkin syncs changes from the filesystem back into the store.
  • Zettels can exist only in the store (internal), only on the filesystem (untracked), or in both (checked out). Conflicts arise when both sides diverge independently.

Content-addressable storage

All blob content is stored by its blake2b-256 hash. Identical content always produces the same hash, providing automatic deduplication. Blobs are immutable once stored. The hash serves as both the storage key and a content integrity check.

Tags organize, types define format

Tags are flexible labels: plain tags (project), dependent tags (-blocked), and virtual tags (%computed). They can be nested hierarchically. Types define the content format and are prefixed with ! (e.g., !md for markdown, !txt for plain text). Types are versioned -- the v1, v2 suffixes track format evolution.

Next Steps

For day-to-day workflows -- querying, organizing, checking in and out, remote synchronization -- refer to the dodder-usage skill.

For deeper understanding of the object ID system, genres, the type system, tags, content-addressable storage internals, and the working copy lifecycle, see references/concepts.md.

Install via CLI
npx skills add https://github.com/amarbel-llc/dodder --skill dodder-onboarding
Repository Details
star Stars 2
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator