> ## Documentation Index
> Fetch the complete documentation index at: https://warden-re.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Interactive UX

> Two read-only surfaces for browsing a WARDEN knowledge base: a rich terminal diff view and a local single-page HTTP dashboard with a confidence heatmap.

WARDEN ships two ways to look at a knowledge base without writing Python. Both are read-only.
Neither changes a single row. They share the same data the CLI and the library see, so anything
the Oracle, the agent crew, or your own `set-name` calls produced shows up the moment you open
them.

* The **terminal diff view** renders a cross-version diff as a colored table in your shell.
* The **HTTP dashboard** serves a single page on localhost with a confidence heatmap and a small
  JSON API behind it.

<Note>
  Both surfaces are strictly read-only. They open a fresh `KnowledgeBase`, answer the question,
  and close it. The HTTP server puts the connection into `query_only` mode for the whole request,
  so no route can write. The diff endpoint serves the stored diff, or computes one as a pure read
  that writes nothing.
  The terminal view renders diffs with `carry=False`, so it never ports an annotation forward
  either. To change annotations, use the CLI (`warden set-name`, `warden agent`) or the
  [MCP server](/reference/mcp).
</Note>

## The terminal diff view

The terminal view lives in `warden.ui.terminal`. It turns a diff into a compact, colored table
you can scan in a shell, the same data that backs the [semantic changelog](/pipeline/diff) but
laid out for the eye instead of for a file.

It imports `rich` lazily, inside the functions that render. Importing `warden.ui` never pulls
`rich` into the import path, so the standard-library HTTP server stays dependency-free.

### Functions

<AccordionGroup>
  <Accordion title="diff_table(kb, from_version_id, to_version_id)" icon="table">
    Build a `rich` table comparing two versions function by function. One row per change. Each row
    shows the classification (`unchanged`, `moved`, `modified`, `new`, `deleted`), the from and to
    indices, the function name, the provenance, the confidence, and whether the change is runtime
    or toolchain churn.

    Rows are styled by classification, so genuine application deltas stand out from carried-over
    and unchanged rows. The provenance cell is colored by source, matching the heatmap. Driven by
    `diff_versions(kb, a, b, carry=False)`, so it is a pure read.

    **Returns:** a `rich.table.Table`. Pass it to a console, or render it yourself.
  </Accordion>

  <Accordion title="render_diff(kb, from_version_id, to_version_id, *, console=None)" icon="terminal">
    Print the diff to the terminal. Builds the table with `diff_table`, prints it, then prints the
    semantic changelog underneath.

    Pass your own `rich.console.Console` to control width or capture the output; omit it and a
    default console is created.
  </Accordion>

  <Accordion title="coverage_panel(kb, version_id)" icon="gauge">
    Render a coverage summary for one version as a `rich` renderable: total defined functions, how
    many are named, the coverage percentage, and the split by source (oracle, human, agent). This
    is the same data `warden coverage` prints, formatted to read at a glance next to a diff.

    **Returns:** a `rich` renderable (a `Table`).
  </Accordion>
</AccordionGroup>

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from warden.kb import KnowledgeBase
from warden.ui import render_diff

kb = KnowledgeBase("project.db")
render_diff(kb, from_version_id=1, to_version_id=2)
kb.close()
```

These functions back a `warden ui diff` CLI command that is being wired in. The command is
read-only: it renders a diff as the terminal table instead of the plain-text changelog. It never
carries annotations forward; use `warden diff` for that.

## The HTTP dashboard

The dashboard lives in `warden.ui.server`. It is a small, standard-library-only HTTP server: it
uses `http.server`, `json`, `urllib`, and `html`, with no third-party dependencies. It serves one
self-contained page plus a handful of JSON endpoints.

### Starting it

In Python, call `serve` directly:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from warden.ui import serve

serve("project.db")  # blocks; serves on 127.0.0.1:8787
```

`serve(db_path, *, host="127.0.0.1", port=8787)` starts a `ThreadingHTTPServer`, prints the URL
once, and serves forever. Use `make_handler(db_path)` to wire the handler into your own server.

<Warning>
  The dashboard is read-only and meant for local use. It binds to `127.0.0.1` by default and has
  no authentication. Do not bind it to a public interface. If you change the host, you are exposing
  your knowledge base to that network with no access control.
</Warning>

### The single-page dashboard

The page is one self-contained HTML document with inline CSS and vanilla JavaScript, no external
assets and no build step. It lists every ingested version, shows coverage for the selected
version, and renders the **confidence heatmap**: every function as a cell tinted by who claimed
its name and how sure that claim is. This is the same heatmap the static `warden report` produces,
served live from the database so it always reflects the current state. It also has a from/to diff
view that calls the diff endpoint.

On top of the heatmap, three panels let you go from a name to a single function and then walk its
whole life across versions:

* The **symbol search box** takes a name and queries `GET /api/search?q=`. It runs a
  case-insensitive substring match over named functions across all versions and lists every hit
  with its stable id, name, provenance, and confidence, de-duplicated by stable id. Pick a result
  to open the detail panel.
* The **function detail panel** shows one function in full: its name, type signature, provenance,
  confidence, and the evidence behind the claim. It is the human-readable view of a single
  annotation record, the same data `GET /api/symbol/{stable_id}` returns.
* The **time-travel history panel** walks one function across every version it appears in, backed
  by `GET /api/history/{stable_id}`. It marks when the function was **first seen**, flags each
  version where the **body changed** even though the identity carried over, and lists the
  **annotation events** that named or renamed it: oracle matches, human edits, agent guesses,
  rejections, and diff carry-over.

The tint follows the provenance economy. Higher-authority sources read as cooler, more
trustworthy hues; lower-authority guesses read as warm amber so they invite a second look.

| Provenance   | Tint         | Meaning                                    |
| ------------ | ------------ | ------------------------------------------ |
| `human`      | Emerald      | Sovereign, human-verified name.            |
| `oracle`     | Blue         | Matched against a known corpus signature.  |
| `export`     | Cyan         | A free fact read straight from the binary. |
| `diff-carry` | Amber        | Carried across a version bump.             |
| `agent`      | Darker amber | Model guess, the lowest-trust source.      |
| (unnamed)    | Zinc         | No symbol at all.                          |

Within a color, the cell gets more opaque as confidence rises, so a strong claim is bright and a
weak one is faint. Switch versions to recolor the whole grid.

### The JSON API

The page is driven by a small read-only JSON API. The whole surface is the pure function
`handle_route(db_path, path, query)`, which opens a fresh `KnowledgeBase`, answers, and closes it,
so you can test it without opening a socket. Every response below `/` is JSON. There is no write
endpoint.

| Method and path                    | Returns                                                                                                                                                                                                                                                                          |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /`                            | The single-page dashboard (HTML).                                                                                                                                                                                                                                                |
| `GET /api/versions`                | All versions: `id`, `label`, `emscripten_version`, `functions`, `shared_memory`, `coverage_pct`.                                                                                                                                                                                 |
| `GET /api/versions/{id}/functions` | Every defined function: `index`, `name`, `provenance`, `confidence`, `type`, `stable_id`. This is the data the heatmap draws.                                                                                                                                                    |
| `GET /api/versions/{id}/coverage`  | Coverage for one version: `defined`, `named`, `coverage_pct`, `oracle_named`, `human_named`, `agent_named`.                                                                                                                                                                      |
| `GET /api/diff?from={a}&to={b}`    | The diff report as a dict (the same shape as `DiffReport.as_dict()`). It serves the stored diff if one exists, otherwise it computes the diff as a pure read (`carry=False`, `store=False`) that writes nothing. A `404` only means an unknown version id.                       |
| `GET /api/search?q={name}`         | Named functions whose name contains `q` (case-insensitive substring), across all versions: each result has `stable_id`, `name`, `provenance`, `confidence`. Sorted by name, de-duplicated by stable id, and capped. An empty or missing `q` returns `[]`. Drives the search box. |
| `GET /api/symbol/{stable_id}`      | The full annotation record for one function, or `404` if no symbol exists. This is the data the detail panel shows: `name`, `type_signature`, `provenance`, `confidence`, `evidence`, and the rest of the record.                                                                |
| `GET /api/history/{stable_id}`     | The time-travel history for one function: when it was first seen, every version it appears in with a `body_changed` marker, and the annotation events that named or renamed it. Drives the history panel.                                                                        |
| anything else                      | `404` with a JSON `{"error": "..."}` body.                                                                                                                                                                                                                                       |

The `{id}` path segment is the numeric version id from `/api/versions`. Unknown version ids and
unknown routes both return a `404` JSON body. The ids are the same ones the
[library](/reference/library) and the [MCP server](/reference/mcp) use, so a client can move
between surfaces without remapping anything.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
import json
from warden.ui import handle_route

# Test the API in process, no socket required.
status, content_type, body = handle_route("project.db", "/api/versions", {})
assert status == 200
versions = json.loads(body)
```

The `query` argument is the parsed query string, a `dict[str, list[str]]` as produced by
`urllib.parse.parse_qs`.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Read the API directly with curl once the server is running.
curl http://127.0.0.1:8787/api/versions
curl "http://127.0.0.1:8787/api/versions/1/coverage"
curl "http://127.0.0.1:8787/api/versions/1/functions"
curl "http://127.0.0.1:8787/api/search?q=malloc"
curl "http://127.0.0.1:8787/api/history/<stable_id>"
```

## The studio: a function browser

`warden serve` also exposes a Ghidra-like studio at `GET /studio` (linked from the dashboard
header). It is the place to read what the per-function agents recovered. Pick a version, search the
function list, then open any function to see:

* A **Raw WASM / Inferred C / Cleaned C** toggle. Raw WASM is the disassembly, Inferred C is the
  lifter output, and Cleaned C is the agent's version with variables renamed (run `warden deep`
  first to populate it).
* The recovered **understanding**, provenance, and confidence.
* **Cross-references**: callers and callees as clickable links, so you jump from function to
  function the way you would in a disassembler.
* The **rename history** for that function (every change is reversible).
* A live **Agents** panel that polls the event feed, so you watch `warden deep` work in real time.

The studio is served by `warden.ui.deepview.deep_routes`, which opens its own read-only knowledge
base (the same `query_only` guarantee as the dashboard). Its endpoints:

| Method and path                             | Returns                                                                                                        |
| ------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `GET /studio`                               | The studio single-page app (HTML).                                                                             |
| `GET /api/analysis/{stable_id}`             | The deep-analysis record: `raw_c`, `clean_c`, `understanding`, `rename_map`, `status`, `confidence`, or `404`. |
| `GET /api/disasm/{version_id}/{func_index}` | The function's `mnemonics` (raw WASM) and `lifted_c`.                                                          |
| `GET /api/callgraph/{version_id}`           | `nodes` (index, stable id, name, status) and `edges` (caller, callee) for navigation.                          |
| `GET /api/renames/{stable_id}`              | The reversible rename trail for one function.                                                                  |
| `GET /api/events?since={n}`                 | New agent events after `n` (the live feed): `last_id` and `events`.                                            |

<CardGroup cols={2}>
  <Card title="CLI reference" icon="square-terminal" href="/reference/cli">
    Every `warden` command, including the diff and coverage commands these views build on.
  </Card>

  <Card title="MCP server" icon="plug" href="/reference/mcp">
    The same read surface for agents and IDEs, plus the one economy-gated write tool.
  </Card>
</CardGroup>
