🧀 hallouminate 🧀
Stop hallucinating. Start hallouminating.
"The wiki must flow."
A markdown corpus indexer for LLMs to build and query their own per-repo
wikis. Hallouminate stores markdown verbatim on disk, embeds it with
fastembed, indexes the embeddings in LanceDB, and exposes a small MCP
surface (add_markdown / read_markdown / delete_markdown / ground)
so an LLM can author and search a per-repo knowledge base without
leaving its agent loop.
The filesystem is the source of truth; LanceDB rows are derived and
refreshed automatically when an LLM writes via add_markdown, or in
bulk via hallouminate index. Code files (.rs, .toml, …) can also
be indexed as text for semantic search, but hallouminate does no
structural analysis — it's a wiki indexer that happens to tolerate
code, not a code intelligence tool.
A long-lived local daemon owns the LanceDB ground directory, per-corpus mutation locks, and config resolution. The CLI and the stdio MCP server both talk to it over a Unix domain socket — one owner, no cross-process LanceDB races.
📖 Full documentation: https://cheeselord.dev/hallouminate/
Install
The default install is a prebuilt binary — no Rust toolchain, no protoc:
|
Prebuilts cover Apple-silicon macOS (aarch64-apple-darwin) and x86_64 /
aarch64 Linux (glibc ≥ 2.39). Re-run the one-liner any time to upgrade.
Alternatives, in cascade order:
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.
Per-harness setup
The MCP server is always the same command: hallouminate serve (stdio).
What differs per harness is how it gets registered:
| Harness | Plugin / skills | MCP registration |
|---|---|---|
| Claude Code | /plugin marketplace add paulnsorensen/hallouminate → /plugin install hallouminate@hallouminate → run /hallouminate:install |
Declarative — the plugin bundles .mcp.json (project scope). User scope fallback: claude mcp add hallouminate --scope user -- hallouminate serve |
| Codex | codex plugin marketplace add paulnsorensen/hallouminate, restart, then codex plugin add hallouminate@hallouminate (or install from /plugins) |
Bundled .mcp.json in the plugin payload |
| opencode | Copy skills from plugins/hallouminate/skills/ to ~/.config/opencode/skills/ — opencode loads the MCP server and skills directly (no plugin manifest) |
Add to opencode.json: { "mcp": { "hallouminate": { "type": "local", "command": ["hallouminate", "serve"] } } } |
| Copilot CLI | — (binary + MCP only) | Add to ~/.copilot/mcp-config.json: { "mcpServers": { "hallouminate": { "command": "hallouminate", "args": ["serve"] } } } |
| Cursor | — (binary + MCP only) | Add to ~/.cursor/mcp.json: { "mcpServers": { "hallouminate": { "command": "hallouminate", "args": ["serve"] } } } |
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:
From a source checkout, run subcommands through cargo:
MCP
hallouminate serve starts a stdio MCP server. Tools:
ground— semantic search.index— bulk (re)build a corpus index.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.get_footnote— resolve a single citation: the footnote target for a page's#footnote_number.
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.
Cross-repo union search
ground (and the read/list tools) resolve corpora relative to the caller's
working directory:
- Inside a repo — the request defaults to that repo's
repo:<name>:wiki. - Above all repos (e.g.
cd ~/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 working 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). - 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:
[]
= 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:
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.
| Model | Notes |
|---|---|
snowflake/snowflake-arctic-embed-s |
Default. English, symmetric retrieval. |
BAAI/bge-small-en-v1.5 |
English, symmetric retrieval. |
intfloat/multilingual-e5-small |
Multilingual, asymmetric retrieval; no quantized variant. |
Skill pack
A cross-harness plugin pack ships in this repo under
plugins/hallouminate: skills for installing
hallouminate and authoring wikis, plus a bundled .mcp.json that registers
the MCP server declaratively. Claude Code installs it from
.claude-plugin/marketplace.json, Codex from .agents/plugins/marketplace.json
— see the install matrix. tests/plugin_manifests.rs
pins the pack's manifests to the crate version, and the release-skills
workflow publishes versioned skill-pack archives to GitHub Releases on every
v* release tag.
License
MIT — see LICENSE.