Start the global collection from any directory:
e5r project new ./a.out --name parser
e5r uiIn this checkout, use ./target/release/e5r if e5r is not installed. Open the
printed http://127.0.0.1:7879 address. The collection shows every project's
live tasks, blockers, review requests and binary availability. Select a project
to open its task dashboard and decompiler; All projects returns to the
collection. The UI is read-only. Ask an agent to register projects and edit tasks through
the CLI. An unavailable binary does not prevent reading that project's tasks.
Project storage follows h5i's convention, in this order:
E5R_PROJECT_HOME$XDG_DATA_HOME/e5r/projects(absolute XDG paths only)~/.local/share/e5r/projects
Each name owns <root>/<name>/project.e5rproj and
project.e5rproj.work/. Binaries and existing annotation logs remain at their
recorded absolute paths. Creation refuses existing names. Omitting --name
uses the binary filename; --out FILE keeps the explicit local-file workflow.
Named project commands work from any directory. A registered name takes
precedence over a same-named local file; use ./FILE to select a local manifest:
e5r project list --json
e5r project task parser list --json
e5r project task parser add 'Trace input validation' --owner agent-a
e5r project import ./old.e5rproj --name older-investigation
e5r project relocate parser /new/path/to/a.out
e5r project dashboard parser # optional single-project modeImport copies the manifest and task history, preserving the original files.
Legacy relative references resolve against the original manifest's directory;
use --base-dir ORIGINAL_CWD if they were recorded relative to a different
working directory. New manifests always use absolute references. Relocate
checks content before changing a path. The collection checks existence and
size only; the content digest is verified before loading a binary.
Both UI modes support --port 0 for a free port. Single-project mode also
accepts --binary PATH as a temporary path override. Ctrl-C stops the server.
Assets ship inside the Rust executable; no frontend build step, CDN, font
download, or Node runtime is required.
The overview answers “what needs me?” before showing the rest of the work. Blocked work always carries a reason, review requests carry their handoff, and ready tasks have no unfinished prerequisites. High priority sorts first within these groups. Counts have literal meanings; there is no inferred health score. Search and state filters keep completed work available without crowding the initial view. Tasks refresh every five seconds, including changes from agents. Open task details follow agent updates. Full view expands the popup; Back to popup restores it. Evidence occupies its own full-width section.
The decompiler gives code the center of attention: project navigation occupies a compact top strip, the searchable function browser sits on the left, and the Evidence & tasks panel sits on the right on wide screens. Layout buttons let you hide either side to give long expressions more space. On narrow screens, functions and evidence open as dismissible overlays; selecting a function closes the function browser. Evidence remains accessible at every width.
Use / to focus function search, and Back / Forward or Alt+Left /
Alt+Right to retrace function navigation. Following a known function name or
address keeps the browser selection visible, clearing a filter that excludes it.
Pseudocode, disassembly, references, call graph, control flow, records and
annotations share the same selected function. Arrow keys move between focused view tabs. A− / A+ adjust code
text from 12 to 22 pixels (14 by default), with the preference retained in this
browser; Wrap also persists. Copy code or its CLI command, and ask an agent
to retain the function address as evidence in a task.
Call graph groups unique callers on the left, the selected function in the center, and unique callees on the right. Click a caller or callee to navigate. Unresolved indirect call targets are not included. Large function lists are loaded in display batches; search always searches the complete list. Variables are shown for pseudocode only.
Disassembly shows each instruction's address, raw encoding, length, control flow kind and known target name. Saved comments appear at their instruction address, with author and anchor match. Annotations shows saved names, types and comments together; low-confidence anchor matches are marked explicitly. Comments are also readable in the context panel while viewing pseudocode; e5r keeps their instruction addresses rather than inventing source-line positions.
References defaults to incoming references to the selected entry address. Its selector also offers All outgoing references, covering every recovered block, and Strings & data, showing data/read/write references with section, symbol, extracted string and encoding, or up to 32 mapped bytes. References into a string retain its start address and byte offset. Click an instruction address to open it in disassembly, or a known function target to navigate to that function. A split function's unanalysed gaps do not contribute references.
Control flow draws the function's basic blocks and recovered successor edges, with instruction counts, block endings and unresolved states. View instructions opens the block's disassembly. A table retains every block, successor and target outside the recovered blocks. Graphs with more than 160 blocks use the table to keep the browser responsive; the table loads 200 blocks at a time with a button to reveal the next batch. This graph describes control inside one function; Call graph describes calls between functions.
The overview's Binary information section shows format, architecture, bitness, endianness, entry point, image base, counts, container metadata and loader warnings. Unavailable binaries leave the project records and tasks readable.
The visual hierarchy follows a repeatable reading path: project and mode at the top, function selection at the left, function identity and output in the center, then supporting evidence at the right. Body and code text carry the findings; metadata is quieter but readable. Blue marks selection and navigation; keyboard focus uses a bright neutral outline. Clickable code names have persistent underlines; plain addresses and encodings use quieter neutral text. Comments share one color across code views, and CFG edges use a neutral tone rather than the navigation color; amber marks attention and incomplete analysis. Status and provenance always remain words, so color alone never carries an analysis claim. Project work and records use the same surfaces and type hierarchy.
Design references: h5i's local console uses restrained surface steps and reserves color for meaningful signals. IDA's subviews keep function selection synchronized with the active view and retain navigation history. Ghidra's CodeBrowser provides a stable function/listing/decompiler context. e5r uses these navigation principles at function granularity; its analysis does not supply instruction to pseudocode correspondence.
The library owns all analysis facts and all task readiness rules. The pane
shows boundary strength, source evidence, incomplete control flow, unmodelled
operations and signature conflicts. It does not imply that pseudocode is
verified source or fabricate a source-to-instruction mapping. Binary analysis
and annotations are a snapshot taken when the decompiler first loads. Restart
the server after changing binary bytes or annotations. Manifest changes and
relocated paths invalidate the cached analysis. Task data stays live. Signature-library references and patch-set references
remain in the project file; they are not automatically applied to the loaded
binary. Unknown analysis settings and custom readers are refused. Supported
analysis settings are scan_gaps, follow_calls, strings, xrefs, noreturn,
data (boolean) and threads (integer).
The CLI writes the task store that the browser reads:
e5r project task investigation.e5rproj add 'Trace input validation' \
--owner agent-a --next 'Inspect parse_header and its callers' \
--priority high --evidence function:0x401000 --author agent-a
e5r project task investigation.e5rproj list --json
e5r project task investigation.e5rproj update T-0001 \
--revision 1 --input task.json --author agent-aadd and update return the saved task as JSON. list --json returns
e5r.work.v1, with each saved task, ready, waiting_on and attention.
update takes the last observed revision and a complete content document:
{
"title": "Trace input validation",
"description": "Determine whether the parser validates length before copying.",
"state": "active",
"priority": "high",
"owner": "agent-a",
"next": "Inspect the copy call and its guard",
"blocker": "",
"evidence": ["function:0x401000", "notes/input-validation.md"],
"depends_on": []
}States: planned, active, blocked, review, done. Priority: high,
normal, low. Active work requires an owner; blocked work requires a reason.
Clear blocker when leaving the blocked state. Prerequisites must exist, be
unique, and not form a cycle. Active, review and done tasks require completed
prerequisites. Reopening a prerequisite is refused while a dependent is active,
in review or done. Next actions and evidence are free text; their correctness
remains the writer's responsibility. Link a task to a function with the exact
function:0xADDRESS evidence string shown in the function pane.
Task content is limited to 64 KiB. Writer names contain 1–200 bytes. --input
can also create a task from a full content document. Content flags
apply when supplying a title and cannot be combined with --input, which
supplies the whole content instead.
--author defaults to E5R_AUTHOR, then the OS user. The browser has no write controls.
Coordination lives in <project>.work/T-0001.json, one file per task, separate
from the existing binary project and annotation log. Each task retains previous
contents, writer names and timestamps. Commit the directory with the project.
Different task files merge normally; concurrent edits to the same task, or two
branches allocating the same new id, require a git conflict review. This store
does not claim the annotation log's order-independent merge semantics.
Local writes take a directory lock, check the revision and prerequisites, write
a synced temporary file, and rename it over the task. A stale update is refused
instead of overwriting the human or agent who edited first. Agents must reread and reconcile rejected updates. The lock and
scratch files are ignored by git. If a process dies during a write, inspect the
PID in <project>.work/.lock; remove that lock only after confirming the writer
is no longer running. Corrupt JSON is an error, never an invisible missing task.
The workspace binds IPv4 loopback only. Host and Origin checks reject cross-site and rebound-host requests. All non-GET requests are refused with 405. Edits use the CLI. Analysis endpoints accept only a recovered function's address.
| Route | Meaning |
|---|---|
GET /api/projects |
all registered projects and live task signals |
GET /api/project |
project identity and container information |
GET /api/tasks |
shared task snapshot |
GET /api/functions |
recovered functions, using the existing e5r/1 JSON |
GET /api/decompile/0xADDRESS |
one function's pseudocode |
GET /api/disas/0xADDRESS |
one function's instructions |
GET /api/xrefs/0xADDRESS |
incoming references |
GET /api/callgraph/0xADDRESS |
incoming and outgoing direct-call edges |
GET /api/context/0xADDRESS |
function-local annotations, outgoing references with target context, and CFG blocks (e5r.context.v1) |
GET /api/records |
findings, notes and reports |
In collection mode, workspace routes are prefixed with /p/NAME (for example,
/p/parser/api/tasks); /api/projects remains global.
Responses are JSON; task conflicts return 409, missing routes/functions return 404, invalid content returns 400. Analysis runs on a separate worker with a bounded queue, so project monitoring and task viewing remain responsive during decompilation. Only one analyzed program is resident at a time; switching projects evicts it. The existing budget is checked between functions, so it is not a hard preemptive timeout for one very large function. The CLI remains available independently during analysis.
Run cargo test --release --workspace for Rust checks. For the browser workflow,
install Playwright and its Chromium browser outside the checkout, then run:
cargo build --release -p e5r-cli
E5R_PLAYWRIGHT_MODULE=/path/to/playwright/index.mjs node scripts/test-dashboard.mjs
E5R_PLAYWRIGHT_MODULE=/path/to/playwright/index.mjs node scripts/test-projects.mjsThe integration check compiles a small C binary with cc, starts an isolated
workspace on a free port, compares decompiler output with the CLI, tests live agent updates, read-only HTTP routes, records, call graphs and task full view, checks function navigation, comments, encodings, function-local outgoing/data references, CFG edges and linked evidence,
and verifies cross-origin rejection and mobile layout. It removes its temporary
project and stops the server when finished. Screenshots are written under /tmp.
The collection check verifies global registration/import, working-directory
independence, project isolation, CLI creation and read-only collection, decompiler access and binary
relocation with a temporary E5R_PROJECT_HOME.
Agents write records; humans read them in the overview and function workspace. Each kind has a separate
revisioned store under <project>.work/{finding,note,report}/, using the same
content and history format as tasks. IDs and prerequisites are local to a kind.
Records do not contribute to task readiness or task counts. Imports preserve
all three stores along with tasks.
e5r project record parser finding add 'Length check before copy' \
--description 'The recovered guard rejects lengths above 32 before the copy.' \
--evidence function:0x401000 --author agent-a
e5r project record parser note add 'Open questions' --description 'Check indirect callers.'
e5r project record parser report add 'Parser investigation' --description 'Investigation text'
e5r project record parser finding list --json
e5r project record parser finding update T-0001 --revision 1 --input finding.jsonAttach a note to a recovered function using its exact address as evidence:
e5r project record parser note add 'Input length checks' \
--description 'The parser rejects lengths above 32 before the copy.' \
--evidence function:0x401000 --author agent-aThe decompiler's Function records section shows notes, findings and reports
linked to the selected function. Click a record or open the Records tab to
read full text beside the function browser. Writer and revision are displayed; updates refresh every five
seconds without restarting analysis. Records linked to other functions and records
without a function link stay in the project overview. Selecting another function
changes the displayed records. The Records tab is also accessible on narrow screens.
The CLI command panel supplies a note creation command for the selected function.
Existing annotate comment entries remain analysis annotations, separate from
these live project records; comments are shown in disassembly and Annotations.
Full record text lives in description; use --input FILE for large content.
The UI renders text literally, including Markdown, without executing HTML.
Disassembly JSON (e5r/1) includes additive bytes and target_name fields for
each instruction. bytes is the mapped encoding in hex, or null if unavailable;
target_name is a known name for a direct flow target, or null. The JSON includes
encodings regardless of the CLI's text-only --bytes switch. Other CLI consumers
continue to receive the same fields as before.