Coverage dashboard for binary-matching decompilation projects.
See every byte. Track every match. Ship the decomp.
Install · Quick Start · Screenshots · Potato Mode
recoverage serves a local web dashboard that visualises per-byte match
status across .text, .data, .bss, and other PE sections of a
decompilation project. Think of it as a defrag map for your decomp —
every byte of the original binary is a cell in a grid, colored by how
closely your C code matches the original compiled output.
- Byte-Perfect Confidence: Stop guessing if your C code produced the correct assembly. See exact byte comparisons visually.
- Fast Iteration: Quickly identify which parts of a function are matching and which parts have diverged (e.g. register allocation differences, instruction reordering).
- Interactive Triage: Click any block in the grid to immediately view the corresponding C source, disassembled binary, and hex diff.
| 🧱 Defrag-style grid | One cell per chunk — Exact (green), Reloc (cyan), Matching (yellow), Stub (red), None (gray) |
| 🔎 Function detail panel | Click any cell to see metadata, C source, disassembly, and hex dump side-by-side |
| 🌗 Light & dark themes | Retro CRT dark mode by default, clean light mode one click away |
| 🔗 Clickable cross-references | Hex addresses in disassembly are live links — click to jump to that chunk |
| 📊 Interactive progress bar | Segmented by status; click a segment to filter the grid |
| 🗜️ First draw in first TCP packet | HTML + CSS + JS inlined & compressed (Brotli/Zstd) to ~14.5 KB |
| 🥔 Potato Mode | Zero-JS server-rendered fallback for constrained environments |
| 🔄 Live regen | One-click re-catalog + rebuild without restarting the server |
Potato Mode is a zero-JavaScript, server-side rendered HTML fallback. Every view is a plain HTML table — no CSS, no JS — so it works on low-spec machines, restricted browsers, or anywhere you just want a quick glance without loading the full SPA.
pip install recoverageFor development:
uv pip install -e .Install an extra to enable its feature: pip install 'recoverage[<extra>]'
(or uv sync --extra <extra> in a workspace).
| Extra | Package | What it does |
|---|---|---|
capstone |
capstone | Enables on-demand disassembly in the detail panel |
pygments |
pygments | Syntax highlighting in Potato Mode |
playwright |
playwright, pytest-playwright | Browser integration tests (tests/test_playwright.py) |
# 1. Generate the coverage database (from your project directory)
uv run rebrew catalog --json
# Analyzes the target binary, parses your annotations, and dumps raw match data to db/data_*.json
uv run rebrew build-db
# Consumes the JSON files and builds a fast SQLite database (db/coverage.db) for the dashboard
# 2. Start the dashboard
uv run recoverage serve
# Starts a lightweight Bottle web server serving the frontend SPA and providing the API backendNote
The server resolves coverage.db from the current working directory:
[project] db_dir in rebrew-project.toml when set, falling back to
db/coverage.db — so run it from your project root.
Start the dashboard web server.
| Flag | Default | Description |
|---|---|---|
--port |
8001 |
HTTP port to serve on |
--bind |
127.0.0.1 |
Interface to bind to (use 0.0.0.0 for LAN access) |
--allow-remote |
off | Required with a non-loopback --bind: acknowledge the API is reachable on the network |
--token |
off | Require this token for every request (Authorization: Bearer, ?token=, or open /?token=<token> to set the SPA cookie) |
--no-open |
off | Don't auto-open the browser |
--regen |
off | Run rebrew catalog + rebrew build-db before starting |
--cors |
off | Enable CORS processing (allowlisted origins only; the wildcard is never emitted) |
--cors-origin |
none | Origin URL allowed to read the API cross-origin (repeatable; without it --cors allows no cross-origin reads) |
Print per-section coverage stats as a Rich table, or as JSON with --json.
recoverage stats # all targets
recoverage stats --target SERVER # single target
recoverage stats --json # machine-readableExport coverage data to stdout.
recoverage export --format json # JSON (default)
recoverage export --format csv # CSV
recoverage export --format md # Markdown tableCI gate — exits non-zero if coverage is below a threshold. Sections the
grid never records matches for (e.g. .bss/.data when only .text
matches are tracked) are skipped, not failed.
recoverage check --min-coverage 60 # all targets, all sections
recoverage check --min-coverage 60 --target SERVER --section .text # specific
recoverage check --min-coverage 60 --json # machine-readable verdictExit codes: 0 = gate passed, 1 = coverage below threshold (or bad input), 2 = infrastructure error (database missing/unreadable).
Re-run rebrew catalog + rebrew build-db to regenerate coverage.db.
recoverage regenOpen the dashboard in a browser (useful when --no-open was used).
recoverage open --port 8001| Path | Method | Description |
|---|---|---|
/ |
GET | Main SPA dashboard |
/potato |
GET | Potato Mode (pure-HTML fallback) |
/api/health |
GET | Server version, DB info, installed extras |
/api/targets |
GET | List available targets |
/api/targets/<target>/stats |
GET | Per-section coverage stats with percentages |
/api/targets/<target>/data |
GET | Section + cell data (?section=.text for partial) |
/api/targets/<target>/functions |
GET | Paginated list (?status=&search=&sort=&limit=&offset=) |
/api/targets/<target>/functions |
POST | Batch lookup: {"vas": [...]} → function/global details in input order |
/api/targets/<target>/functions/<va> |
GET | Single function/global detail |
/api/targets/<target>/asm |
GET | Disassembly (?format=json for structured output) |
/api/targets/<target>/sections/<section>/bytes |
GET | Raw byte slice (?offset=&size=) |
/api/events |
GET | Server-Sent Events: db-updated when coverage.db changes (SPA auto-refresh) |
/api/regen |
POST | Re-run catalog + build-db (localhost only, rate-limited) |
recoverage is designed as a standalone consumer of the data that rebrew produces — the two packages are intentionally decoupled.
rebrew catalog --json rebrew build-db recoverage (Bottle + SQLite)
│ │ │
db/data_*.json ──────────▶ db/coverage.db ──────────▶ VanJS Dashboard
rebrew catalog --json: Scans your project's source annotations and writes intermediatedb/data_*.jsonfiles containing coverage metrics. Jump table / switch data bytes are absorbed into their parent function's size. Use--export-ghidra-labelsto generateghidra_data_labels.jsonfor round-trip Ghidra sync.rebrew build-db: Consumes those JSON files and builds a structureddb/coverage.db(SQLite v4 schema) database, storing per-function metadata (detected_by,size_by_tool,textOffset), per-global metadata (module,size), per-cell metadata (label,parent_function), and stampingdb_versionfor schema detection. See DB_FORMAT.md for the full schema.recoverage: Starts a Bottle web server. The backend serves API endpoints querying the SQLite database, while the frontend is a zero-build Single Page Application (SPA) powered by VanJS, rendering the interactive defrag grid.
You can run recoverage independently on any machine (or even host it remotely) as long as it has access to a compiled coverage.db — no rebrew dependency or compiler toolchain is required.
recoverage/
├── pyproject.toml
├── README.md
├── docs/ # Screenshots, mascot & design doc
│ ├── DESIGN.md # Detailed architecture & design doc
│ ├── DESIGN_PRINCIPLES.md # Core operational philosophies
│ ├── USER_STORIES.md # User stories with acceptance criteria
│ └── ideas.md # Future improvement ideas
├── tests/
│ ├── conftest.py # Shared fixtures (synthetic coverage.db)
│ ├── test_api.py # API validation & security tests
│ ├── test_cli.py # CSV export, formatting tests
│ ├── test_lifecycle.py # Process lifecycle (regen timeouts, opener reaping)
│ ├── test_paths.py # DB path resolution tests
│ ├── test_server.py # Compression, encoding tests
│ ├── test_potato.py # Potato Mode rendering tests
│ └── test_playwright.py # Browser integration tests
└── src/recoverage/
├── __init__.py
├── __main__.py # python -m recoverage
├── _paths.py # DB path resolution (rebrew-project.toml db_dir)
├── cli.py # Typer CLI entry point
├── server.py # Bottle app, shared helpers & compression
├── regen.py # rebrew regen subprocess lifecycle (group kill + reap)
├── api.py # REST API routes (/api/*)
├── ui.py # UI routes (/, /potato, static files)
├── potato.py # Potato Mode renderer
├── webapp.py # Composition root: imports api+ui so app has every route
└── assets/
├── index.html # SPA shell
├── style.css # All styles
├── print.css # Print stylesheet
├── app.js # VanJS frontend
├── detail.js # Deferred panel logic (hex dump, modal, live reload)
├── van.min.js # VanJS library (~2 KB)
├── favicon.svg # Retro "R" logo favicon
├── hljs.min.js # Highlight.js core
├── hljs-c.min.js # Highlight.js C grammar
├── hljs-x86asm.min.js # Highlight.js x86 asm grammar (hex lang is in detail.js)
└── hljs.css # Highlight.js theme
The browser libraries under src/recoverage/assets/ are vendored so the
dashboard works air-gapped (see docs/DESIGN.md); nothing is fetched from a
CDN at runtime. Licenses and versions are recorded here because the minified
blobs themselves carry little provenance:
| File | Upstream | Version | License |
|---|---|---|---|
van.min.js |
VanJS core, classic-script build (window.van) |
not embedded in the blob | MIT (upstream license) |
hljs.min.js |
Highlight.js core | 11.11.1 (in-file banner) | BSD-3-Clause |
hljs-c.min.js |
Highlight.js c grammar |
compiled for 11.11.1 | BSD-3-Clause |
hljs-x86asm.min.js |
Highlight.js x86asm grammar |
compiled for 11.11.1 | BSD-3-Clause |
hljs.css is a first-party theme (not upstream Highlight.js CSS). When
re-vendoring any of these files, keep the upstream license banner in the
minified output so this table stays verifiable against the blobs.
MIT



