Skip to main content
warden export converts the knowledge base for a given version into one of six deliverable formats. All six are deterministic: given the same KB state, the output is byte-identical on every run. That means they diff cleanly in git and compose naturally with CI pipelines.

The six formats

headers

A C header of recovered function prototypes. Use this to feed names into a downstream C/C++ toolchain or as a human-readable symbol sheet.

pseudo

Per-function listings: the recovered name, type signature, agent summary, provenance, and lifted pseudo-C (requires the original .wasm to be present; falls back to a mnemonic count otherwise). Use this for manual review.

kb-text

A columnar, stable text dump of every symbol (index, stable id, lock flag, provenance, confidence, and name), sorted by function index. The primary format for committing alongside source and reading diffs across versions.

ghidra

A Python script that pushes recovered names back into a Ghidra project. Run it from Ghidra’s Python console after loading the same module.

csv

A neutral CSV file of every defined function: index, stable id, name, type, provenance, and confidence. Edit it in any spreadsheet or script and import it back with warden import.

json

The same content as csv but in JSON array form, one object per function. Useful when automating annotation workflows or feeding into IDA scripts.

Basic usage

By default, output goes to stdout. Pass --out <file> to write to a file instead.
--db selects the project database when it is not the default warden.db:

Format details

headers

Emits a C header wrapped in an include guard. Each defined function gets a comment line with its function index, Wasm type signature, provenance, and confidence score, followed by a skeleton declaration. Only defined (non-imported) functions are emitted; imports are excluded.
The prototypes are stubs. Parameter types are not yet recovered from the Wasm type signature. The comment carries the full signature string so you can fill it in. This is a known limitation; proper C prototype reconstruction is on the roadmap.
When to use it: feeding into a C toolchain, generating a symbol cheat-sheet, or as a starting point for writing a real header by hand.

pseudo

Emits a readable listing of every defined function with its recovered name, type signature, agent-generated summary, and provenance/confidence. When the original .wasm path is still accessible in the KB, instruction mnemonics are included inline; otherwise the listing notes the instruction count without disassembly.
When to use it: manual review of agent and Oracle output, writing a report, or orienting a second analyst. The stable ID truncated to 12 hex characters appears in every function header so cross-referencing the KB is easy.

kb-text

A columnar dump of every function in index order (including imports) with a fixed-width layout designed for git diff. The format is:
Columns: index (Wasm function index), stable_id (first 16 hex chars of the full stable identity hash), lk (L when the symbol is locked; space otherwise), provenance, confidence, name (dash when unnamed).
Commit kb-text output alongside your source code. When the vendor ships a new .wasm, warden ingest + warden diff + warden export v2 --format kb-text gives you a git diff that shows exactly which functions changed, were added, or were dropped, and which annotations carried over automatically.
When to use it: source-controlled annotation snapshots, CI regression detection, sharing the current KB state without giving someone access to the database.

ghidra

Emits a Python script for Ghidra’s built-in scripting console. The script iterates over every defined function that has a recovered name and calls fn.setName(name, SourceType.USER_DEFINED) to apply it.
The Ghidra round-trip is a round-trip bridge that targets the nneonneo/ghidra-wasm-plugin and calls its getFunctionByWasmIndex helper. If that helper is not present in your Ghidra environment, the rename loop silently skips every function. Verify the plugin is loaded before running the script.
When to use it: you already have a Ghidra project open for the same module and want WARDEN’s recovered names applied without re-doing the work interactively. The index-based mapping is stable as long as the loaded .wasm is the same binary that WARDEN ingested for that version.

Built-in decompiler

The warden.lift module contains a pure-Python stack-machine lifter that re-folds Wasm stack operations back into readable pseudo-C. It handles the integer subset comprehensively including infix arithmetic, memory loads and stores, local and global variables, and function calls. It also renders f32 and f64 arithmetic, comparisons, and constants as readable expressions, so floating-point code reads the same way the integer subset does. Float min, max, and copysign render as named calls (fminf, fmax, copysign); unary ops render as name(x) (and neg as -(x)); f32.const and f64.const decode their raw IEEE-754 bytes to clean literals like 0.5; and conversions render as a C cast ((float)x) or a named call. It degrades gracefully for anything unmodeled by emitting a /* mnemonic */ comment and an opaque temporary instead of crashing.
Load it with samples.float_demo() to lift the float sample interactively.

Structured control flow

The lifter now reconstructs structured control flow, not just straight-line code. WebAssembly’s block, loop, and if constructs are already well-nested, so the lifter builds a control-flow tree and emits proper C constructs from it:
  • if/else. Result-typed ifs assign each branch into a fresh temp so the value is available after the closing brace.
  • while loops with break/continue. The common block + loop idiom renders as a clean while (1) { ... if (cond) break; ... } with no goto. A labeled goto is the fallback for control flow that does not fit the innermost-loop/break pattern, so output is always correct.
  • switch for br_table. Multi-way branches become a switch statement with a case per target and a default.
An unmodeled opcode still degrades to a /* mnemonic */ comment and pushes an opaque temp. The lifter never crashes; every function produces valid pseudo-C. Two samples ship with WARDEN and illustrate both constructs:
Load the samples with samples.control_flow() to lift them interactively.

How --format pseudo uses it

When you run warden export --format pseudo and the original .wasm is available, the exporter now calls the lifter instead of dumping raw instruction mnemonics. Each function block contains a proper pseudo-C body:
Functions whose .wasm is not on disk fall back to the previous mnemonic-count note; the switch is automatic.

Targeting a single function

Use warden lift to decompile one function by name without running a full export:
The --index N flag is useful when multiple functions share a recovered name across an ambiguous KB state.

Python API

lift_module skips imports (they have no body) and concatenates in function-index order so the result diffs cleanly across builds.
The lifter covers the integer, floating-point, and control-flow subset that Emscripten-compiled C/C++ produces in practice. f32 and f64 arithmetic, comparisons, and constants render as readable expressions, the same as the integer subset. SIMD (v128) opcodes are not modeled and degrade to a single /* v128 op 0xNN */ comment with an opaque temp, so a SIMD-using function still lifts without a crash or a stack desync. The output is always valid pseudo-C, never a crash or a partial file.

Round-trip bridge

warden export --format csv|json and the new warden import command deliver annotations that round-trip. Export a version’s names to a neutral file, edit them in Ghidra, IDA, or a text editor, and import the result back into the knowledge base.

Exporting to CSV or JSON

Two new format values are accepted by warden export:
Each row contains: index, stable_id, name, type, provenance, confidence. The stable_id column is the key used on import. The type column carries the Wasm type signature and is round-tripped as-is. The Python API:

Importing back

After editing the file, import it with the new warden import command:
The command prints a summary: matched, written, skipped (no name), rejected by the economy, and unmatched (row did not resolve to a known function). The Python API:

How identity and the economy interact

The bridge resolves each row to a function by stable_id first. This means a name recovered against one build lands on the same logical function in a later build, even when the function index shifts. If the stable_id is absent or unrecognized, the bridge falls back to the index column. Writes go through the same provenance/confidence economy as every other annotation source. An import never clobbers a higher-authority annotation. For example, a human 1.00 name already in the KB is not overwritten by an oracle 0.94 row from the file. Pass --provenance human to assert human authority for all rows in the file.
The existing warden export --format ghidra script is the push side of the Ghidra round-trip. The CSV/JSON formats are the neutral pull side: they work with any tool that can read a spreadsheet or JSON file, including IDA’s name-import scripts and manual annotation sessions.

Format details

HTML report

warden report writes a self-contained HTML file: no server, no CDN, no build step. Everything is inlined so the file opens from any clone with a double-click, and the output is deterministic (same KB state in, byte-identical HTML out) so it diffs cleanly in git.

What the report contains

The heatmap color key:

Python API

Pass module=<Module> to either function if you have the parsed .wasm on hand; it is optional and reserved for future inline disassembly views. The report is fully driven by the KB without it.
Commit the HTML report alongside kb-text snapshots. The report is byte-identical for the same KB state, so git diff --stat will tell you at a glance whether anything actually changed between runs. This is useful in CI to detect spurious annotation drift.

Comparing across versions

Because all formats are deterministic, you can snapshot them at each version and use standard diff tooling to review what changed:
Functions with unchanged stable_id and annotations appear as unchanged lines. New functions, dropped functions, and any confidence or provenance changes are visible immediately.
For a richer semantic changelog (which functions are new, removed, carried over, or only partially matched), use warden diff before exporting. The diff engine runs the same fingerprinting that export relies on, so the two views are consistent.

Reference

warden export flags

warden import flags

Last modified on June 10, 2026