Architecture
Bezial’s architecture is one idea applied consistently: the files are the truth, and everything else is derived from them.
Files write, the graph reacts
Section titled “Files write, the graph reacts”People and agents write Markdown. The graph is downstream, regenerated automatically the way a reactive backend recomputes a query when its inputs change.
documents/ ──▶ commit ──▶ section re-extract ──▶ one temporal graph write .md versioned, only changed patched, not rebuilt audited heading sections │ ▼ two views + recallThe flow is one-directional: files flow into the graph; the graph never writes your files. With no bi-directional sync to maintain, the graph stays a pure function of your documents. A passage-to-fact provenance link is what lets a single edit regenerate only its slice.
The load-bearing invariant
Section titled “The load-bearing invariant”The only write path is a file, and it is enforced structurally, not by convention.
add()appends to a Markdown note;write()replaces a document.- Every mutation runs one ordered path: permission-check → serialize → version → audit → project.
- The graph projector is notified after the commit with an immutable event. It is a pure sink: it receives data, never a store handle, so it cannot become a graph-write path.
- A failing projection is isolated and never corrupts the file truth - the graph is always rebuildable from
documents/.
There is no graph-write API anywhere, and none can be added. The substrate that makes this durable - object versioning and an append-only audit log - is described in Storage & audit.
One graph, two views
Section titled “One graph, two views”Do not build two graphs. Build one temporal graph and a thin projector that emits the file map from it.
- View 1 - the file map (for humans). Nodes are documents; edges connect documents that share entities. Coarse, intuitive, great for browsing and inspection.
- View 2 - the fact graph (for agents). Nodes are entities; edges are bi-temporal facts. Fine-grained and exact, powering precise and as-of recall.
Both views are projections of the same substrate, both are permission-filtered per fact, and both accept an asOf instant.
The file map is mostly free, since you already know which entities each document produced.
Explore both, live, in the interactive viewer.
Bi-temporal by design
Section titled “Bi-temporal by design”Every fact carries two time axes:
- Valid time - when the fact is true in the world.
- Recorded time - when Bezial came to know it.
A contradiction on a single-valued (subject, predicate) archives the superseded fact (it sets a recorded-to bound) rather than deleting it, so an as-of query still sees the earlier belief.
Contradiction is scoped to the same author: one principal’s write can only supersede that principal’s own earlier belief - it can never archive, or side-channel-leak, another author’s fact.
Two authors holding contradictory beliefs both remain, each returned only to whoever may read it.
Reactive, section-level re-extraction
Section titled “Reactive, section-level re-extraction”A commit is split into heading sections, each with a stable anchor and a content hash. Only sections whose hash changed are re-extracted; a removed section has its facts archived; an ACL-only change re-stamps facts with no re-extraction. That is what keeps a single edit cheap - you never rebuild the whole graph to fix one note.
The reference engine and the production backend
Section titled “The reference engine and the production backend”The TypeScript engine is the reference: it implements the whole projection and recall path natively and deterministically - an in-memory graph store and a rule-based extractor - so recall runs with no database and no LLM and is exhaustively tested, including the zero cross-space / cross-author leak guarantee.
The production temporal graph is a Python adapter behind two ports: an extractor seam (Graphiti’s LLM extraction) and a graph-store seam (Graphiti over an embedded Kuzu database, one file per space). Neither changes the bi-temporal model, the ACL stamping, the recall filtering, or the two views - those are backend- and extractor-agnostic. The heavy adapter is an optional install, so the core stays a clean, deterministic, zero-network dependency tree.
Communities, the optional overlay
Section titled “Communities, the optional overlay”For a “big picture” view, run community detection over the one graph as a separate, cheap pass, then let an LLM name each cluster. Communities are a labelled overlay, not another database - add them only once the memory is large enough that “what is this person working on lately” beats a list of individual facts.
Risks to watch
Section titled “Risks to watch”- The view has a scale ceiling. A folder is delightful at 1,000 facts and a wall at a million. Lean on the file map and community summaries before then.
- Extraction quality caps everything. The viewer faithfully shows mis-extracted facts - good for trust, but the extractor must be solid. The upside: visible errors are editable at the source note.
- The file map can hairball. Threshold “shared entity” edges by count or by community, the way Obsidian and similar tools prune.
- Multiplayer merges need care. Rebuild only the touched sections, and surface contradictory facts rather than silently resolving them. See Multiplayer.