Intake
Knowledge base & vault
Everything eli.ai knows starts as plain markdown in a per-workspace vault. The vault is the source of truth for content; the database is a derived index that makes it searchable, linkable, and graph-traversable. This page explains how a document travels from disk to a citable, retrievable chunk.
Files-first, not database-first
Each workspace owns a directory of .md files plus attachments under DATA_DIR/vaults/<workspace>/. The files are Obsidian-compatible and git-able — you can edit them in eli.ai, in your editor, or sync them with Dropbox, and the app reconciles. The database stores what has no natural file form (chunks, embeddings, entities, relations, runs, evals) and a metadata index over the files (path, title, content hash, version).
Web edits write through to disk atomically (temp-file + rename) and never corrupt your vault. In local mode a filesystem watcher picks up external edits; on a remote host the server owns all writes and you trigger a manual rescan instead. Deleting a file is a soft-delete with a grace window keyed on the document's frontmatter id, so a folder rename never destroys provenance.
Document identity
Every document gets a stable ULID. On first save eli.ai injects it into frontmatter by textual splice — it never parses and re-serializes your YAML, because round-tripping mangles dates, comments, and key order across thousands of files. The splice is gated by a one-time consent prompt; if you decline, identity falls back to the content hash.
A handful of frontmatter keys are meaningful: title, tags, client, and type. A bu (business-unit) mapping feeds the coverage matrix. Everything else is preserved verbatim.
Wikilinks
[[Wikilink]] syntax connects documents and seeds the entity graph. When you save, eli.ai resolves each link against known entity names and aliases: a match produces a mention and a references edge; an unresolved target becomes a stub entity, flagged and excluded from client-facing views until it earns real content. Because your explicit links are the highest-precision signal available, they build a connected graph with zero LLM cost — the graph exists even fully offline. See Entity graph.
Chunking
Retrieval and extraction operate on chunks, not whole documents. One deterministic module (remark mdast, heading-aware) splits each document into heading-scoped sections:
- Target ~1,000 tokens per chunk, with a 200-token minimum and a 1,600-token hard cap.
- Zero overlap — overlap would duplicate mentions and double extraction cost. The heading path (e.g.
CFO interview › Capital allocation) is prepended as context to prompts and embeddings but is not stored inside the chunk text. - Offsets are absolutecharacter offsets into the original file, so a chunk's content is always exactly
original.slice(startOffset, endOffset). - Chunk identity is
(doc_id, sha256(normalized_text)). Renaming a heading is cheap; identity only changes when the text itself changes.
The dual index: FTS + vector
Each chunk is indexed two ways so retrieval can fuse lexical precision with semantic recall:
- Full-text search (FTS) — a Postgres
tsvectorper chunk, queried withwebsearch_to_tsquery('english', …)and ranked byts_rank_cd. Built synchronously on save. - Vector search — chunk embeddings stored in
chunk_embeddingsunder anembedding_spacesrow (provider + model + dimension), with a pgvector index. Embedding is the async half of the save path, dispatched to the worker.
Switching embedding models creates a new space and re-embeds in the background, so search never goes dark mid-migration. If no embedding provider is configured, retrieval simply runs FTS-only.
The save-path invariant
Deletion is synchronous
Soft-deleting a document synchronously hard-deletes its derived rows (chunks, FTS, vectors) so retrieval can never surface deleted content. A later hard purge cascades through every verbatim-text copy — version snapshots, mention surface text, relation-evidence quotes — and emits a dated destruction record. This is what lets a consultant delete an off-the-record interview and be sure chat will not cite it an hour later. See Export & offboarding.
Next
- Documents & editing — create, edit, preview, and upload files in the app.
- Retrieval & grounded chat — how chunks become cited answers.
- Entity graph — how mentions become a traversable graph.