KnowledgeBase("project.db"). The schema is applied (idempotently via CREATE TABLE IF NOT EXISTS) on every open from src/warden/kb/schema.sql, loaded at runtime through
importlib.resources. No migration runner is required.
Two SQLite PRAGMAs are set at open time: PRAGMA journal_mode = WAL (concurrent readers
alongside the single writer, which matters when warden mcp and a local agent run
simultaneously) and PRAGMA foreign_keys = ON (version-scoped tables cascade-delete when a
module_versions row is removed).
Status: alpha. The schema is functional and exercised end-to-end by
warden demo. Additional
columns (DWARF source info, wasm2c harness references) are tracked in the
roadmap.The linchpin design choice
Annotations are keyed on a function’s stable content identity, not on a per-version row-ID.The
functions table is the per-version appearance log: it records that function index 42
appeared in version v1 with a given stable_id. The symbols table is the durable
annotation layer: it holds names, types, summaries, and evidence keyed on that same
stable_id.
When a vendor ships v2.wasm and every table index shifts, WARDEN re-ingests and
re-fingerprints. A function that was index 42 in v1 might become index 51 in v2, but its
stable_id (a composite content hash) stays the same. The annotation in symbols is still
there, automatically. That is the carry-over mechanism that makes RE incremental.
See core concepts for how stable_id is computed from structural, semantic, fuzzy,
and exact fingerprints.
Table reference
meta
Lightweight key/value store for project-level metadata. Accessed via KnowledgeBase.get_meta()
and set_meta().
module_versions
One row per ingested .wasm file, representing a point in the target’s version history. The id here is
the foreign key anchor for functions, thread_model, and diffs.
functions
The per-version appearance log. Each row records one function as it appeared in one version,
with all fingerprinting data needed for identity matching and Oracle lookup. This table does
not hold human annotations. Those live in symbols.
Unique constraint:
(version_id, func_index). One row per function per version.
Indices: idx_functions_stable on stable_id; idx_functions_version on version_id;
idx_functions_struct on structural_hash.
symbols
The durable annotation layer. Keyed on stable_id so that an annotation created against
v1 is automatically present when the same function appears in v2, v3, and beyond. All
writes go through KnowledgeBase.upsert_symbol(), which enforces the provenance/confidence
economy (see below).
Unique constraint:
(stable_id, kind). One annotation record per identity per kind.
structs
Recovered memory-region and struct layouts, stored as first-class structured data rather than
free-text comments.
Written via
KnowledgeBase.upsert_struct(), which uses ON CONFLICT(name) DO UPDATE.
thread_model
The concurrency spine: lock-to-guarded-data relationships, atomic sites, TLS references, and
worker entry points. Version-scoped because the threading model may change between releases.
Written via
KnowledgeBase.add_thread_fact(); retrieved via thread_facts(version_id).
oracle_matches
Records of individual Oracle identifications: a function fingerprint matched to a known upstream
runtime or libc function. References functions.id (not stable_id), so each match is
version-specific: the same logical function may match at a different func_index in each
version, generating a separate row.
Unique constraint:
(function_id, matched_name).
An Oracle match is a separate record from the symbols annotation it triggers. warden oracle identify writes both: the match record here, and a symbols row (provenance "oracle") via
upsert_symbol.
diffs
Stored cross-version diff reports (the semantic changelogs produced by warden diff). One row
per ordered pair of versions. The report column holds the full JSON classification (unchanged,
structurally-equivalent, fuzzy-matched, added, removed) and carry-over counts.
Unique constraint:
(from_version_id, to_version_id).
audit_log
Append-only trail of every symbol write attempt, whether accepted or rejected. Rows are never
modified, only inserted. Used to answer “who changed this name and when?” and “why was this
agent proposal rejected?”.
Retrieve recent entries with
KnowledgeBase.audit_log(limit=100).
Deep analysis tables: per-function analysis, renames, and live events
Schema version 2 adds three tables for the per-function deep agent engine. They are created withCREATE TABLE IF NOT EXISTS, so an existing project upgrades in place on the next open.
function_analysis
One row per function (keyed on stable_id, like symbols) holding the distilled per-function
understanding that flows up to a parent agent. Raw WASM is re-derived from the module on demand and
is never stored here.
Read with
KnowledgeBase.get_analysis(stable_id) or analyses_for_version(version_id); write with
upsert_analysis(...), which is partial (a None field keeps the existing value).
rename_history
Append-only log of every name, variable, and summary change, so the whole session is reversible.
add_rename(...) records a change; revert_rename(rename_id) applies the inverse;
rename_history_for(stable_id) lists the trail.
agent_events
The live activity feed the UI polls so you can watch the per-function agents work in real time.
record_event(...) appends an event; events_since(after_id) returns newer events for polling.
Provenance ranking
Every symbol write carries aprovenance label. PROVENANCE_RANK in src/warden/kb/models.py
assigns an integer priority that the may_overwrite() gate uses to decide whether a new write
may displace an existing annotation.
10. Human is sovereign at the
top; raw agent proposals sit at the bottom. The ranking is also shown in the core
concepts table.
The may_overwrite() economy
may_overwrite() in src/warden/kb/models.py is the gatekeeper called by every
KnowledgeBase.upsert_symbol() invocation. It receives the new write’s provenance and
confidence alongside the existing annotation’s provenance, confidence, and lock state, and
returns (allowed: bool, reason: str).
The rules, exactly as implemented:
1
Empty slot: always allow
If
existing_provenance is None the slot is empty and any write succeeds. Reason:
"new symbol".2
Human write: always allow
If
new_provenance == "human" the write wins unconditionally, regardless of what already
exists. Reason: "human override". A subsequent lock_symbol() call then sets
locked = 1 to protect it.3
Locked symbol: reject any non-human write
If
existing_locked is true and the writer is not "human", the write is rejected.
Reason: "existing symbol is locked (human-verified)". The locked flag is set by
warden set-name (which locks by default) and by KnowledgeBase.lock_symbol().4
Agent write: narrow overwrite rights
An agent may only write if one of two conditions holds:
- The existing annotation is also
"agent"andnew_confidence > existing_confidence(strictly higher). Reason:"higher-confidence agent write". - The existing provenance has a rank strictly below 30 (the agent rank), i.e. an unknown
source. Reason:
"outranks existing automated source".
oracle, export, import, string-xref, diff-carry, or
human annotations. The rejection reason names the existing provenance and its confidence.5
Other automated sources: rank then confidence
For all other provenances (oracle, export, import, string-xref, diff-carry):
- Higher rank wins outright.
- At equal rank,
new_confidence >= existing_confidenceis required. - Otherwise the existing annotation takes precedence.
(False, reason) and are appended to audit_log
with action='rejected'. This lets you re-run the entire agent crew on every update without
clobbering any verified human work or high-confidence Oracle annotations.
Example economy decisions
KnowledgeBase API
KnowledgeBase (in src/warden/kb/database.py) is a pure-stdlib sqlite3-backed class that
supports the context-manager protocol. Schema is applied idempotently on every open.
Representative calls
Module versions
Module versions
Write and read a symbol
Write and read a symbol
Bulk-fetch symbols for a version
Bulk-fetch symbols for a version
Coverage statistics
Coverage statistics
coverage_pct is computed over defined functions only (imports excluded from the
denominator).Oracle matches
Oracle matches
Lock a symbol
Lock a symbol
warden set-name <label> <index> <name> (which locks by default).Diff storage
Diff storage
Audit log
Audit log
The kb-text export format
warden export <label> --format kb-text emits a stable, deterministic text dump of every
symbol in a version, sorted by func_index. Because the output uses fixed-width fields and a
consistent sort, it diffs cleanly in git alongside version-controlled .wasm artifacts.
lk column is L for locked (human-verified) symbols and a space otherwise. The
provenance and conf columns are - for functions that have no symbol record yet.
Storage notes
Pure stdlib
KnowledgeBase imports only sqlite3 and json. No C extensions or native dependencies on
the core path.WAL mode
PRAGMA journal_mode = WAL allows concurrent readers alongside the single writer, so
warden mcp and a local agent can run simultaneously without blocking each other.Foreign-key cascade
ON DELETE CASCADE is set on all version-scoped tables. Deleting a module_versions row
automatically cleans up functions, oracle_matches, thread_model, and diffs.JSON columns
Columns such as
minhash, histogram, call_targets, inferred_flags, glue_info,
evidence, layout, and report store structured data as JSON strings.
KnowledgeBase handles serialization transparently; callers work with Python list and
dict objects.Related pages
Core concepts
How stable_id is computed and why the provenance economy exists.
CLI reference
Commands that read and write the KB: ingest, oracle, agent, diff, export.
MCP reference
Serve KB data to external tools over the Model Context Protocol.