dither
A personal index for the agentic era — search your own corpus from the command line.
dither is a local-first personal index. You drop markdown files into collections, run plugins to pull data in from the world, and search across everything from one CLI.
The pieces here all work today: a CLI, a markdown-on-disk library, a qmd-backed hybrid search index, a Deno-sandboxed plugin runtime, and a long-lived daemon for scheduled and watched runs. Things mentioned in the architecture sketch but not yet shipped (an MCP server, sync, browser sidebar) are deliberately omitted from these docs — they'll arrive in later phases.
Install
dither is not on npm yet. Build it from source:
git clone https://github.com/janniks/dither.git
cd dither
npm install
npm run build
npm link # exposes `dither` on your PATHYou can also skip npm link and invoke the binary directly:
node packages/cli/dist/cli.mjs --helpRequirements
- Node 20+ to run the CLI itself.
- Deno — dither downloads and pins its own Deno on first plugin install or run; you don't need it on
PATH. SetDITHER_USE_SYSTEM_DENO=1to opt out and use the systemdenoinstead (CI / dev escape hatch). - On the first hybrid search, qmd downloads its embedding + reranker models (~1–2 GB).
dither initpre-fetches them by default; pass--no-downloadto skip and let them lazy-load instead.
Where dither stores things
dither separates two roots:
- dither home — bookkeeping (config, plugins, grants, runs, history, qmd index, daemon state). Default
~/.dither/. Override with$DITHER_DIR(or$XDG_CONFIG_HOME/dither;$DITHER_HOMEis the deprecated alias). - library — your markdown content. Default
<dither-home>/library/; configurable viadither init --library <path>.
<dither-home>/
config.json schema + library.path
plugins/<name>/ installed plugin code + state
grants/<name>.json plugin manifest + resolved grants
qmd-index.sqlite derived search index
runs/<runId>/ per-run scratch (always cleaned up)
history/<runId>/ persistent run journal
logs/ daemon.log + detached-run logs
env.json global env store
dither.pid, status.json daemon state
<library>/ your canonical markdown
<collection>/**/*.mdSee Storage layout for the full picture.
Quickstart
# Initialize dither (required first step).
dither init
# → ✓ wrote ~/.dither/config.json
# ✓ created library at ~/.dither/library
# ✓ pre-downloaded model weights
# Drop a markdown file into a collection.
mkdir -p ~/.dither/library/notes
cat > ~/.dither/library/notes/hello.md <<'EOF'
---
title: Hello
collection: notes
---
This is my first dither entry.
EOF
# Build the index.
dither index update
# → index updated: 1 collection(s), 1 indexed, 0 updated
# Search.
dither search hello
# → notes/hello.md 0.812 Hello
# Read it back.
dither get notes/hello.mdWant your library somewhere else? Pass --library on the first init (re-init isn't supported — if you've already initialised, remove ~/.dither/config.json first):
dither init --library ~/Documents/dither