org-wiki is an Emacs Lisp implementation of the read side of an
Org-native LLM Wiki: a curated, interlinked knowledge layer inside an
existing Org-roam corpus that LLMs can search, read, and cite through
structured tools.
The larger LLM Wiki idea is simple: do not make the model rediscover the same structure from raw documents on every query. Ingest sources once, synthesize them into stable wiki nodes, connect those nodes with links and metadata, and answer later questions from the accumulated wiki. The wiki becomes a durable memory of prior synthesis rather than another transient retrieval result.
This repository is the first working slice of that design. It is intentionally read-only: it exposes search, read, metadata, and backlink operations over wiki nodes, and it provides those operations to three callers:
- MCP clients, through
mcp-server-lib - Emacs users, through minibuffer commands
- gptel conversations, through direct gptel tools and an
org-wikipreset
The full architecture, including planned ingest and mutation workflows,
lives in ../docs/org-llm-wiki.md. This
package is the implementation-backed core that validates the read model
and is already useful against a real Org-roam corpus.
A conventional RAG system searches raw source material at query time and asks the model to synthesize an answer on the spot. That works, but the synthesis is ephemeral. The next question pays the same cost again, and the system has no durable place to record concepts, disagreements, cross-source links, or open questions.
An LLM Wiki moves synthesis into the knowledge base itself:
- Sources are read and integrated into wiki nodes.
- Nodes are organized by kind, linked by stable IDs, and cited back to sources.
- Query-time answers are composed from wiki nodes, not from raw source documents.
- Coverage gaps become explicit: if the wiki does not know enough, the answer should say what is missing and suggest a source to ingest.
In Org-wiki, the storage layer is plain Org. A wiki node is an Org
heading with an :ID: and a :WIKI_KIND: property. Org-roam supplies
stable IDs, backlinks, and graph structure; org-ql supplies fast
property-based selection; optional org-ql-semantic supplies semantic
search. LLM access is mediated through tools rather than arbitrary file
edits.
This repository implements the read-only surface of the wiki. It does not yet implement source ingest, node creation, node mutation, lint repair, transaction logging, raw artifact registration, embedding sync, or recovery. Those are mutation-side concerns described in the architecture document.
What is implemented here:
- wiki-node identity and discovery
- semantic-first search with literal fallback
- node body reads by ID
- metadata reads with tool-maintained hash properties stripped
- backlink reads through org-roam
- deterministic structural health diagnostics
- MCP tool registration
- interactive Emacs commands
- gptel tools, preset, one-shot ask command, and persistent chat command
- tests, fuzzing, coverage gates, benchmarks, formatting, linting, and Nix/CI integration
The read-only boundary is deliberate. It makes the package safe to use against a personal corpus while proving the assumptions the write side will depend on.
Wiki identity is property-based. Any Org heading with :WIKI_KIND: is a
wiki node, regardless of its file path:
* Content-Addressed Storage
:PROPERTIES:
:ID: 4f1c3b8e-9ad2-4b7e-9d04-1a5e6f7c8b91
:WIKI_KIND: Concept
:CONFIDENCE: high
:END:
** Summary
Content-addressed storage names data by the hash of its content.
org-wiki-root defaults to ~/org/wiki/. That directory is the
canonical home for new wiki files, but it is not the read identity
predicate. Reads can find any Org-roam node whose properties mark it as
part of the wiki. Path boundaries matter later for writes: a future
mutation tool can refuse to edit a drifted node outside org-wiki-root
while read tools continue to see it.
Supported :WIKI_KIND: values are:
ConceptEntityTopicComparisonQuestionSource-RecordFrozenIndex
Org-wiki also handles the two-ID convention common in this corpus: files may have a top-level file ID while the real wiki node has a heading ID. Read tools accept the file-level ID as an alias and return the canonical heading ID so callers learn what to cite next time.
The package is split into five modules.
| File | Role |
|---|---|
org-wiki.el |
Data core: node predicates, candidate discovery, search, reads, metadata, backlinks, ID normalization, and structured errors. |
org-wiki-health.el |
Deterministic, read-only structural health diagnostics. |
org-wiki-mcp.el |
Read-only MCP tool registration around the data core. |
org-wiki-commands.el |
Interactive Emacs commands with optional consult previews and embark actions. |
org-wiki-gptel.el |
Direct gptel tools, the org-wiki preset, org-wiki-ask, and org-wiki-chat. |
org-wiki--search returns node summaries with :id, :title,
:kind, :file, and :summary.
When org-ql-semantic is available, search is semantic-first and ranks
matches by score. If the semantic backend is absent, misconfigured,
errors, or returns no results, Org-wiki falls back to literal text
search over headings and body text. This keeps the tools useful when an
embedding service is down and keeps literal hits from disappearing
behind a failed semantic path.
Candidate discovery unions files under org-wiki-root with org-roam DB
entries whose properties include WIKI_KIND, so property-based identity
is honored across the corpus.
org-wiki-read-node returns the full Org subtree for a node ID.
org-wiki-node-metadata returns a plist of property values and removes
hash-maintenance properties such as HASH_*.
org-wiki--backlinks returns backlink plists with source ID, title, and
file, using org-roam when available.
Errors use the org-wiki-error condition with stable payloads such as
:unknown_id, :id_not_in_file, and :not_a_wiki_node. The MCP and
gptel layers convert these into JSON-shaped tool results.
org-wiki--health performs deterministic, read-only checks over every wiki
node: missing or duplicate IDs, invalid kinds, missing summaries, broken or
non-canonical wiki ID links, source provenance, SOURCE_IDS citation parity,
and type-aware orphan/source connectivity. It makes no LLM calls. Results
include stable issue codes and are exposed through Emacs, MCP, and gptel.
org-wiki-mcp-enable registers five read-only tools:
| Tool | Arguments | Result |
|---|---|---|
wiki_search |
query, k |
Matching node summaries. |
wiki_read_node |
id |
Full Org body plus canonical ID. |
wiki_node_metadata |
id |
Property drawer as JSON, hash properties omitted. |
wiki_backlinks |
id |
Nodes that link to the target node. |
wiki_health |
none | Deterministic structural health report. |
The default MCP server-id is "default" and can be customized with
org-wiki-mcp-server-id. Tool names are prefixed with wiki_ to avoid
generic names on a shared endpoint. Registration is guarded so
double-enable fails clearly instead of silently keeping stale handlers.
The MCP wrapper preserves structured tool errors. This matters because
mcp-server-lib-tool-error is a subtype of error; a generic
condition-case clause placed first would accidentally catch and
rewrite it.
org-wiki-commands.el adds user-facing commands for the same read-only
operations:
| Command | Behavior |
|---|---|
org-wiki-search |
Search wiki nodes and visit a selected result. With a prefix argument, force literal search. |
org-wiki-find |
Pick a wiki node by title and visit it. |
org-wiki-backlinks |
Show nodes linking to the node at point or a chosen node. |
org-wiki-show-metadata |
Display node metadata in a transient buffer. |
org-wiki-health |
Display deterministic structural health diagnostics. |
The commands work with plain completing-read. If consult is loaded,
candidates get live previews. If embark is loaded, wiki candidates and
id: links at point get actions for visiting, copying/inserting links,
showing backlinks, and showing metadata.
The package provides an unbound prefix keymap:
(keymap-set global-map "C-c w" 'org-wiki-command-map)This gives C-c w s, C-c w f, C-c w b, C-c w m, and C-c w h for
search, find, backlinks, metadata, and health.
org-wiki-gptel.el exposes the same five operations as direct gptel
tools. This avoids an MCP hop when the LLM conversation is already
inside Emacs.
User-facing entry points:
M-x org-wiki-askasks one question and streams an Org-formatted answer into*org-wiki-ask*.M-x org-wiki-chatopens a persistent gptel chat buffer with theorg-wikipreset applied.@org-wiki <question>can be used in gptel prompt transforms once the preset is registered.ob-gptelblocks can use:preset org-wiki.
The preset does not set a backend or model; it inherits the active gptel
backend. org-wiki-ask and org-wiki-chat still resolve and pin a
concrete model buffer-locally so a nil global gptel-model is not sent
to a provider.
The system prompt enforces the query discipline: search first, read
every relied-upon node, cite claims with Org [[id:...][title]] links,
and report coverage gaps instead of answering from general knowledge.
The package is developed inside the dot-emacs tree, but it can be loaded directly from this directory:
(use-package org-wiki
:load-path "~/src/dot-emacs/lisp/org-wiki"
:commands (org-wiki-read-node
org-wiki-node-metadata
org-wiki-canonical-id))
(use-package org-wiki-commands
:load-path "~/src/dot-emacs/lisp/org-wiki"
:after org-wiki
:commands (org-wiki-search
org-wiki-find
org-wiki-backlinks
org-wiki-show-metadata
org-wiki-health)
:config
(keymap-set global-map "C-c w" 'org-wiki-command-map))To expose the read tools to MCP clients:
(use-package org-wiki-mcp
:load-path "~/src/dot-emacs/lisp/org-wiki"
:after (org-wiki mcp-server-lib)
:config
(org-wiki-mcp-enable))To use the gptel integration:
(use-package org-wiki-gptel
:load-path "~/src/dot-emacs/lisp/org-wiki"
:after org-wiki
:commands (org-wiki-ask org-wiki-chat org-wiki-gptel-register))Create ~/org/wiki/, add Org nodes with :ID: and :WIKI_KIND:, and
ensure org-roam has indexed them. The read tools will then operate over
the wiki subset of the corpus.
The test suite is not just regression coverage; it records empirical answers to design questions from the architecture document:
(property "WIKI_KIND")is a sound org-ql identity predicate.- Read identity can be property-only while future write permission can remain path-bounded.
- Semantic search can degrade cleanly to literal search.
- Hits on child headings can surface the enclosing wiki node.
- File-level IDs can be accepted as aliases while canonical heading IDs remain the citation target.
mcp-server-libparsesMCP Parameters:docstrings into schemas for positional handlers.- Structured MCP tool errors must be caught before generic
errorclauses. - The gptel preset must store category-qualified tool objects so
duplicate
wiki_*names from another category cannot shadow the direct Org-wiki tools.
The following are intentionally outside this repository's current surface:
- source ingest and raw artifact management
- creation, patching, merging, or deletion of wiki nodes
- semantic lint and lint-repair tools
- write-ahead logging, crash recovery, file locks, and transaction replay
- hash refresh and tamper-evidence on mutation
- embedding queue maintenance and sync repair
- privacy/read filtering beyond the
:WIKI_KIND:read predicate - publication workflows
Those features require a mutation discipline. The current package keeps the useful, safe read path small and well tested before that complexity is added.
The Nix dev shell provides Emacs and the package dependencies:
nix develop
make checkCommon targets:
| Target | Purpose |
|---|---|
make build |
Byte-compile package and tests with warnings as errors. |
make test |
Run the ERT suite. |
make lint |
Run checkdoc, package-lint, relint, and check-declare. |
make format |
Format Elisp, shell scripts, and Nix files. |
make format-check |
Verify formatting without modifying files. |
make coverage-check |
Run coverage and compare against the baseline. |
make bench-check |
Run benchmarks and compare against the baseline. |
make fuzz |
Run the seeded random-input harness. |
make check |
Run the aggregate local gate. |
Pre-commit hooks run the same gates in parallel through lefthook:
nix develop --command lefthook installGitHub Actions runs nix flake check, nix build, and report
generation for coverage and benchmarks.
BSD 3-clause; see LICENSE.md.