🧀 hallouminate 🧀
Persistent, repo-local knowledge for coding agents.
hallouminate gives your coding agent a wiki it writes and searches — plain markdown you review and commit with the code. The markdown files remain the source of truth; hallouminate builds a derived local index so agents can retrieve the right context without rereading the entire repository.

- Human-owned: ordinary markdown in
.hallouminate/wiki/, readable and editable with any text editor. - Agent-native: a focused MCP surface for searching, reading, and safely updating the wiki.
- Local-first: embeddings and search run on your machine; no hosted account or content upload is required.
- Repo-aware: each repository gets its own wiki, with optional union search across repositories.
hallouminate is not a code-intelligence engine: it can index source files as text, but it does not parse symbols, types, or call graphs. Pair it with your code-search tools; use hallouminate for the durable knowledge those tools cannot infer — the architecture, conventions, gotchas, and reasons behind a design.
Install · First run · Full documentation · How it compares
Install
The preferred install is via npm — the package is a thin shim whose
postinstall downloads the matching prebuilt binary from the GitHub release.
No Rust toolchain, no protoc:
npm install -g hallouminate # persistent — puts `hallouminate` on PATH
npx hallouminate --version # or one-off, no global install
Alternatives that fetch the same prebuilts, in cascade order:
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/paulnsorensen/hallouminate/releases/latest/download/hallouminate-installer.sh | sh
cargo binstall hallouminate # same prebuilts, via dist-manifest.json
cargo install hallouminate --locked # source build — needs Rust + protoc
Prebuilts cover Apple-silicon macOS (aarch64-apple-darwin) and x86_64 /
aarch64 Linux (glibc ≥ 2.39). Re-run the install command any time to upgrade.
Source builds need protoc (the lancedb build dependency:
brew install protobuf / apt install protobuf-compiler); from a git
checkout, cargo build --release lands the binary at
target/release/hallouminate.
Intel macOS and older-glibc Linux have no prebuilt (ort/ONNX Runtime ships
no Intel-mac build — pykeio/ort#556); use the source build there. Windows
is unsupported — the daemon is Unix-only (Unix domain socket + flock);
see #48.
Verify with hallouminate --version.
Plugin setup (recommended)
The plugin pack is the preferred integration: one install registers the MCP
server (bundled .mcp.json launching hallouminate serve) and the wiki
skills (/hallouminate:install, wiki authoring workflows). Install it through
the harness-native route:
To curate local Claude Code or Codex memories into the current repo wiki, invoke
/hallouminate:wiki-harvest-memory claude in Claude Code or
$wiki-harvest-memory codex in Codex. The skill cannot run implicitly; Claude
Code also keeps it out of model context until invocation. It presents a redacted
candidate review, then writes only the facts the user approves.
Without the plugin: skills + MCP by hand
The plugin is a convenience wrapper — both halves can be wired manually:
- MCP — register the stdio server directly:
- Claude Code:
claude mcp add hallouminate --scope user -- hallouminate serve - opencode: the
opencode.jsonsnippet from the table above - Any other MCP client: launch
hallouminate serveover stdio — ornpx -y hallouminate serveto skip the PATH install entirely (first run pays the binary download)
- Claude Code:
- Skills — copy
plugins/hallouminate/skills/into your harness's skills directory (Claude Code:~/.claude/skills/; opencode:~/.config/opencode/skills/). Skills are optional — the MCP tools work without them.
First run
hallouminate config init— scaffold the XDG baseline config.hallouminate init-repo <name>in your repo — seed.hallouminate/config.tomlplus the wiki skeleton; the wiki becomes therepo:<name>:wikicorpus. Identical on every harness.hallouminate index— build the index (auto-spawns the daemon and downloads the embedding model on first use).hallouminate ground "<a question your wiki answers>"— prove the loop.
Usage
hallouminate serve starts the stdio MCP server (auto-spawning the daemon if
none is running) — this is what an MCP client launches:
hallouminate serve
From a source checkout, run subcommands through cargo:
cargo run -- serve # stdio MCP server
cargo run -- index # bulk (re)index every configured corpus
cargo run -- ground "how does the daemon work" # CLI semantic search
cargo run -- config show # print the effective merged config
MCP
hallouminate serve starts a stdio MCP server. Every tool call takes a
required cwd argument: the absolute path of the directory the request
applies to. Pass your own active checkout — in a git worktree, the harness's
original working directory is often a different checkout from the one you
are working in, and passing the stale one silently reads and writes the
wrong worktree. Tools:
ground— semantic search.index— bulk (re)build a corpus index.corpus_stats— index health for one corpus: indexed file count, total chunk rows, newest index timestamp, unindexed-file count, and zero-match include/exclude warnings.list_corpora— list every configured corpus.list_files— flat list of relative paths in a corpus.list_tree— the same files grouped into a directory tree, for progressive disclosure without reading everyindex.md.add_markdown— write a markdown file under the corpus' first root, atomic and no-symlink-follow, with auto-reindex of just that file. Returns advisory lintwarnings(empty-destination links, empty mermaid blocks, heading-level jumps) without blocking or rewriting the content.read_markdown— verbatim UTF-8 file contents. Use before overwriting.delete_markdown— unlink the file and prune its rows from the index.backlinks— corpus-relative paths of every page that links to a given page via a[[wikilink]].
Document paths (path on add_markdown, read_markdown, delete_markdown,
backlinks) are corpus-relative. Absolute paths and .. traversal are
rejected.
Markdown content is stored verbatim — hallouminate imposes no schema.
Convention for LLM wiki authors: one topic per file, first line # Title,
file stem matches the slug.
Config
The config lives at $XDG_CONFIG_HOME/hallouminate/config.toml
(~/.config/hallouminate/config.toml by default).
hallouminate config init— scaffold a baseline config.hallouminate config show— print the effective merged config for the current working directory (baseline + repo layer).hallouminate config validate— parse and flag unknown top-level keys.hallouminate config download— pre-fetch the configured embedding model so the firstindexdoesn't pay the download cost.
Corpus globs select which supported documents are indexed. The indexer handles
Markdown, plain text, reStructuredText, CSV, xlsx/xls/ods spreadsheets, and
text-layer PDFs. PDF chunks carry page:N breadcrumbs; image-only pages require
OCR and are skipped with a warning. For example:
[[corpus]]
name = "project-docs"
paths = ["~/Dev/project/docs"]
globs = ["**/*.md", "**/*.pdf"]
Include and exclude patterns match paths relative to each configured corpus
root. For example, docs/**/*.md selects root-level docs/, not libs/docs/.
Use **/docs/**/*.md to select both. The most-specific root owns files when
roots overlap. A single-file root matches patterns against its file name.
Absolute patterns are errors; no legacy matching or automatic rewrite exists.
config validate and corpus_stats report patterns with zero matches as
advisory warnings. Each warning names the corpus, root, rule kind, and pattern.
A valid empty corpus still succeeds. These warnings do not certify index freshness.
Cross-repo union search
ground (and the read/list tools) resolve corpora relative to the directory
passed as cwd:
- Inside a repo — a
groundcall with no explicitcorpussearches the union of that repo's ownrepo:<name>:wikiwith every other config-declared corpus — baseline-registered[[repository]]wikis, user-declared[[corpus]]entries, and each repository'srepo:<name>:corpussource corpus when configured — fused as one ranking. The repo's own pages win score ties and keep reservedtop_filesslots. - Above all repos (e.g.
cwd: ~/Dev) — agroundcall with no explicitcorpussearches the union of every effective corpus: discovered sub-repo wikis + baseline-registered[[repository]]wikis, plus user-declared[[corpus]]entries and each repository'srepo:<name>:corpussource corpus when configured. The results are merged and re-ranked into one response, and each hit is attributed to its source corpus (file-levelcorpusplus per-chunkprovenance.corpus).
The downward walk is bounded: it honours .gitignore, skips hidden
directories (except .hallouminate itself), caps its depth, and never scans
above the cwd directory. Walk-discovered wikis are deduped against the
baseline by resolved path; a discovered local config that collides with a
baseline repository of the same name wins, with a cross-repo-union warning
on the response rather than a silent shadow.
Passing an explicit corpus always pins the search to that one corpus,
unchanged. Writes (add_markdown / delete_markdown) still require an
explicit single-root corpus — the multi-root union is read- and search-only.
How the daemon works
A long-lived local daemon owns the LanceDB ground directory, the repository registry, and per-corpus mutation locks. The CLI and the stdio MCP server are thin clients that talk to it over a Unix domain socket.
- Auto-spawn —
hallouminate serve,index, andgroundstart a detached daemon automatically when none is listening; there is nothing to start by hand. - Socket resolution order —
HALLOUMINATE_SOCKET(explicit full-path override; setting it also disables auto-spawn — the caller owns the daemon lifecycle), else$XDG_RUNTIME_DIR/hallouminate/daemon.sock, else~/.cache/hallouminate/daemon.sock. - Lifecycle —
hallouminate daemon status/stop/restart; barehallouminate daemonruns it in the foreground. Only one instance per socket can run (flock-guarded). - Version-skew respawn — after a binary upgrade, the next client pings the running daemon and compares versions; a mismatch stops the stale daemon and spawns a fresh one. No manual restart needed after upgrades.
- Diagnostics — anything the auto-spawned daemon emits before its logger
is up (panics, early config errors) lands in
~/.local/state/hallouminate/daemon-bootstrap.log($XDG_STATE_HOME). - Process logs —
$XDG_STATE_HOME/hallouminate/hallouminate.log(default~/.local/state/hallouminate/hallouminate.log) rotates exactly at 10 MiB into numbered archives and retains at most 100 MiB. Configure[logging].max_file_bytes/max_total_bytes, or override them withHALLOUMINATE_LOG_MAX_FILE_BYTES/HALLOUMINATE_LOG_MAX_TOTAL_BYTES.[watch].failure_reminder_secsdefaults to 60 seconds; override it withHALLOUMINATE_WATCH_FAILURE_REMINDER_SECSor set0to disable suppression. - Windows — the daemon model is Unix-only; see #48.
FAQ
How do I turn embeddings off?
Dense embeddings are on by default, using the
snowflake/snowflake-arctic-embed-s model. On first index hallouminate
downloads that model and fuses its vector signal with lexical search.
To run lexically only — full-text search + ripgrep + rerank, no embedding
model downloaded (just the tokenizer used for chunking) — set enabled = false
in ~/.config/hallouminate/config.toml:
[embeddings]
enabled = false
Changing the embedding mode (or model) for a ground directory that was already
indexed under a different mode trips the store's mismatch guard on the next
run. Delete the ground directory and re-run hallouminate index to rebuild:
rm -rf ~/.local/share/hallouminate/ground
hallouminate index
Which embedding models are supported?
Set embeddings.model in your config to one of these (all embed to 384-dim
vectors). Omitting embeddings.model selects the default.
Skill pack
A cross-harness plugin pack ships in this repo under
plugins/hallouminate: skills for installing
hallouminate and authoring wikis, plus MCP registration for each supported
plugin format. Claude Code and OMP use .claude-plugin/marketplace.json,
Codex uses .agents/plugins/marketplace.json, Copilot CLI uses the payload's
root plugin.json, Cursor uses .cursor-plugin/, and Gemini CLI uses
gemini-extension.json — see the install matrix.
tests/plugin_manifests.rs pins every manifest to the crate version, and the
release-skills workflow publishes versioned plugin-pack archives on every
v* release tag.
License
MIT — see LICENSE.