Factum

Native knowledge language for LLMs — structured, traceable, verifiable
v0.1.0-alpha.1 MIT License Rust MCP 2025-06-18

Three Knowledge Bottlenecks for LLMs

Factum is not another database format — it is a native knowledge medium designed for LLMs.

Read Bottleneck

LLMs receive knowledge context primarily as natural language, lacking provenance, confidence, and temporal validity. They cannot distinguish "verbatim Wikipedia text" from "some LLM's inference."

Factum's solution: Each fact carries 7-tuple metadata, injected into context via MCP. Canonical form saves 62% tokens vs JSON.

Write Bottleneck

LLM-generated structured output lacks syntactic constraints. Ambiguous parsing introduces uncertainty. Errors are uncategorized, preventing self-correction.

Factum's solution: Fully parenthesized S-expressions guarantee unique parse trees. 7 error classes enable LLM self-correction.

Reasoning Bottleneck

LLM "thinking" lives in implicit weights. There is no structured knowledge representation for auditable reasoning.

Factum's solution: factum-l encodes knowledge as continuous thought vectors (M3 research), targeting semantic round-trip ≥ 0.95.

Node 7-Tuple Data Model

Each fact is a Node with 7 core fields + 2 runtime metadata fields. Click any field to expand.

7-tuple: (id, predicate, validity, provenance, confidence, authority, permissions) + deps + status

1 / 7
id
NodeId
Unique node identifier — human-readable string or ULID
2 / 7
predicate
Predicate
Content predicate — what is being asserted. Composed of morpheme head + positional args + named args
3 / 7
validity
Validity
Temporal validity: forever / bounded window / open-ended window
4 / 7
provenance
Provenance
Provenance chain: Verbatim / Summary / Extracted / Derived / Asserted
5 / 7
confidence
f32 [0,1]
Confidence — subjective measure, not in precise arithmetic. Used for query filtering threshold
6 / 7
authority
f32 [0,1]
Source authority — tiebreaker in conflict arbitration
7 / 7
permissions
u32 bitmask
Permission labels: PUBLIC / INTERNAL / CONFIDENTIAL / RESTRICTED
meta
deps
Vec<NodeId>
Dependency chain — propagates invalidation during cascade retraction
meta
status
NodeStatus
Lifecycle: Active / Retracted (soft delete) / Pending
9
Total fields (7 core + 2 meta)
5
Provenance levels
4
Permission tiers
3
Validity types

Factum-F Syntax

Fully parenthesized S-expressions — every valid input has exactly one parse tree.
Click play: source code to AST parsing
( node n001 :pred ( instance-of @ACME-CORP organization ) :conf 0.99 :auth 0.95 :perm public :src ( asserted "wikidata" ) )

Full Syntax Example

; Acme Corp knowledge graph ; Basic assertion — Acme is an organization (node n001 :pred (instance-of @ACME-CORP organization) :conf 0.99 :auth 0.95 :perm public :src (asserted "wikidata")) ; LLM extraction — majority shareholder info (must carry model ref) (node n004 :pred (shareholder-major @ACME-CORP @FOUNDER-1 0.73) :conf 0.85 :auth 0.8 :perm confidential :src (extracted "doc002" [100 200] (model "gpt-4" "2024-06"))) ; Derived knowledge — subsidiary relationship (depends on n001, cascade retractable) (node n006 :pred (subsidiary-of @ACME-SUB @ACME-CORP) :src (derived n001 "rule-subsidiary-merge") :deps [n001])

Parse Uniqueness — Two Guarantees

1. Full Parenthesization

Eliminates operator precedence ambiguity. All nesting is expressed through explicit parentheses — no infix expressions.

2. Named-Arg Ordering Constraint

Named arguments must follow positional arguments. Eliminates ambiguity between :keyword prefixes and symbols.

Error Taxonomy — Foundation for LLM Self-Correction

MissingPredField — missing :pred
UnknownNodeField — unknown field
NamedArgBeforePositional — arg order
DepthLimitExceeded — exceeds 128 levels
UnbalancedParen — mismatched parens
UnterminatedString — unclosed string
MissingModelRef — Extracted lacks model ref

Five-Level Provenance System

Every fact must declare its source. Different sources carry different trust implications.
Level 1
Verbatim
Verbatim quote from source document — original text reconstructable via (doc, span)
Highest trust
Level 2
Summary
Human-authored summary — human judgment
High trust
Level 3
Extracted (must carry model ref)
LLM-extracted knowledge — may hallucinate. Mandated to carry model name + version
Medium trust
Level 4
Derived
Formally derived from other nodes — trust depends on rule correctness
Depends on rule
Level 5
Asserted
Directly asserted by a human or external system — trust depends on the asserter
Depends on asserter

MissingModelRef — Non-Negotiable Constraint

Extracted provenance must carry a model reference (name + version). This is enforced in the parser, not a documentation convention. The same text extracted by GPT-4 vs a small model has vastly different reliability — extracted knowledge without a model reference is a broken audit chain.

Conflict Arbitration — Refuse to Guess

When multiple nodes match the same query, return Ambiguous if uncertain. Never guess.
LatestWins
Highest authority wins, timestamp as tiebreaker
Default policy
HighestAuthority
Strict authority ranking
Multiple max → Ambiguous
Unanimous
Return only if all sources agree
Disagreement → Ambiguous

Query Engine 6-Step Pipeline

Candidate Generation
Retrieve candidate nodes via entity index or predicate-head index, avoiding full-table scan
; Query: Who is the majority shareholder of ACME-CORP? (shareholder-major @ACME-CORP ?holder ?stake) ; → uses by_entity["ACME-CORP"] index

Index-Level Permission Filtering

Permission filtering happens at candidate generation — unauthorized nodes are never materialized.

Why Post-Query Filtering Is a Vulnerability

If the system retrieves all matches first and filters afterward, aggregate queries themselves leak information: "returned 10 but filtered 3" → the caller now knows 3 confidential nodes exist.

Permission Tiers (Bitmask)

PUBLIC 0b0001
Accessible to anonymous users
INTERNAL 0b0010
Accessible to internal staff
CONFIDENTIAL 0b0100
Accessible to analysts
RESTRICTED 0b1000
Admin only

Cascade Retraction

When a source node is retracted, all Derived dependents are automatically cascade-retracted. Soft delete preserves audit history.

n001 (asserted) → cascade → n006 (derived from n001) → cascade → n007 (derived from n006)

Token Efficiency — LLM-Native Metric

Canonical S-expressions save 62% tokens vs JSON. Counterintuitively, the form designed for correctness is also the most token-efficient.
Token efficiency comparison: Factum canonical vs compact vs JSON

Why Canonical Beats Compact in Token Count

BPE tokenizers split JSON delimiters ({ } " :) into separate tokens, while S-expression parens and spaces frequently merge with adjacent tokens.

JSON token sequence
{ | " | confidence | " | : | 0.85 | , | " | authority | " | : | 0.8 | }
Each delimiter = 1 token
S-expr token sequence
(node | n001 | :pred | (instance-of | @ACME-CORP | organization) | :conf | 0.85)
Parens often merge with adjacent words
-62%
Canonical tokens saved (vs JSON)
-53%
Compact tokens saved (vs JSON)
-68%
Compact bytes saved (vs JSON)
100%
Parse round-trip consistency

✓ All token counts measured with real o200k_base tokenizer via tiktoken-rs (issue #9 resolved)

MCP Integration

Communicates with LLM clients via Model Context Protocol, JSON-RPC 2.0, compatible with MCP 2025-06-18. stdio transport verified with Claude Code and Cursor — see Getting Started guide.
LLM
LLM Client (Claude Code / Cursor)
Calls factum_query / factum_insert / factum_retract via MCP
↕ JSON-RPC 2.0
MCP
factum-mcp (Protocol Layer + Handler)
Morpheme negotiation · capabilities.factum capability declaration · graceful degradation
↕ Rust API
RT
factum-rt (Runtime)
Storage (InMemory + RocksDB) · 6 indices · query engine · arbitration · permissions · cascade retraction · verifier
↕
F
factum-core (Core)
Node 7-tuple · S-expression lexer/parser · dual serialization · 24 morphemes

Three MCP Tools

ToolPurposeRequired params
factum_queryQuery the knowledge graphquery (S-expr)
factum_insertInsert a new nodenode (S-expr)
factum_retractRetract a node (cascade)node_id

Morpheme Negotiation

Client declares capabilities.factum → server returns 24-morpheme ID/name/kind table → compact form uses u32 indices instead of string names. Clients that don't declare it gracefully fall back to string names.

{ "method": "initialize", "params": { "capabilities": { "factum": {} } } } // → Server returns factum_morphemes table

Relationship to Other Formats

Factum does not replace any existing format — it occupies a specific ecological niche.
FormatPositioningHow Factum Differs
RDF / JSON-LDW3C triples7-tuple; provenance/confidence/permissions are first-class. RDF requires reification.
CUEConfig validationDifferent domain. Factum validates knowledge claims with temporal validity and conflict arbitration.
DatalogDeductive queriesFactum supports pattern matching but adds temporal validity, confidence arbitration, and provenance.
MarkdownHuman-readable textHuman-oriented vs LLM-oriented. Factum trades readability for verifiability.
JSONGeneral data interchangeJSON has no schema/provenance/validity. Factum compact form uses JSON as transport encoding.

Roadmap

M1 Open-source Alpha in progress. M2 Adoption-readiness is a hard blocker.
M0: Core ImplementationDone
factum-core / factum-rt / factum-mcp / factum-bench fully implemented, 112 tests passing
M1: Open-Source AlphaIn Progress
README / CI / conformance vectors / authoring guide / Good first issues / RocksDB persistence / stdio transport verified / preferred_form negotiation — exit criteria: fuzzing stable 1 week + 3 external reviewers
M2: Adoption-ReadyPlanned
HTTP transport · Claude Code/Cursor integration tests · Wikidata converter · 200+ morphemes · Z3/Lean verifier · MVCC concurrency
M3+: ResearchResearch
factum-l latent space projection · encoder/decoder · semantic round-trip ≥ 0.95 · Qwen2.5-7B + LoRA
24
Seed morphemes
5
RocksDB column families
3
MCP tools
112
Tests passing