dither

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 PATH

You can also skip npm link and invoke the binary directly:

node packages/cli/dist/cli.mjs --help

Requirements

  • 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. Set DITHER_USE_SYSTEM_DENO=1 to opt out and use the system deno instead (CI / dev escape hatch).
  • On the first hybrid search, qmd downloads its embedding + reranker models (~1–2 GB). dither init pre-fetches them by default; pass --no-download to 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_HOME is the deprecated alias).
  • library — your markdown content. Default <dither-home>/library/; configurable via dither 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>/**/*.md

See 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.md

Want 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

Where to go next