drydock

Web UI

drydock ui serves a small web app over the broker socket: the same board, approval gate, diff, and history you get from the CLI, in a browser. It binds to loopback only and is gated by a one-time token.

Launch

drydock ui                 # prints: UI ready: http://127.0.0.1:7878/#t=<token>
drydock ui --open          # also open it in your default browser
drydock ui --port 8080     # bind a different loopback port (default 7878)

drydock start must already be running; the UI is a thin client over the same broker socket the CLI uses and keeps no state of its own. Open the printed URL; the token rides in the #t= fragment, so it is never sent as a query parameter, written to server logs, or leaked in Referer headers. The page reads it from the fragment and sends it as a bearer token on every API call.

What's in it

Where the cost figures come from

Two different numbers, deliberately labelled differently.

The push gate shows spent: $X (broker-metered) — the credential gateway's own metering, computed host-side from the proxied response bodies. That is the figure to make an approval decision on. Where the lane carries no USD metering at all (subscription, or an openai_compat lane with no prices) it says so rather than showing $0.00, and where the broker has no figure — a task resumed after a restart whose previous process left no terminal row — it says unknown rather than inventing one.

The running card's ~$0.05 is parsed from the agent's own output stream and is an estimate, marked with ~. The agent's stdout is untrusted text, so it is useful as a progress signal and is never presented as measured spend. The history table follows the same rule: a cost the broker measured is plain, and a cost that exists only because an agent reported it carries a ?.

On the board, when exactly one task is at a gate: R review · A approve · D deny. ⌘/Ctrl+Enter submits the form; ? lists the shortcuts.

Trust brief panel

Opening a review renders the task's trust brief above the diff: the same broker-observed evidence drydock inspect <id> prints, so you can weigh the diff without leaving the overlay. The panel shows the repo and base commit (with sensitive / auto-approve chips where set), the runtime (agent, vendor, model, image), the effective policy (budget, timeout, policy snapshot hash), egress rules, broker-metered spend, and a diff summary — hash, size, file/line counts, and any FLAG rows for structurally risky changes (binaries, symlinks, exec bits, dependency manifests, lockfiles, CI workflows, git metadata, submodule gitlinks). When an execution profile or verification is configured, its block appears too: overall status, the VMs' capability posture, and per-command exit codes and durations (the setup block first — setup runs before the agent).

Everything in the panel is what the broker observed — none of it is the agent's own account of what it did. It is read-only, fetched from the same loopback-only, token-gated API as the diff, and a task recorded before briefs existed simply shows "no trust brief recorded"; the diff still loads.

Security

The server is loopback-only (127.0.0.1) and token-gated: every API call must carry the token minted at launch. It drives the same broker socket the CLI does, so the approval gate, audit trail, and egress rules are unchanged: the UI never widens what a task can reach or push. See the threat model for the guarantees it inherits.

Every response also carries a strict Content-Security-Policy (default-src 'self' — no inline script, no external loads, no framing) plus X-Content-Type-Options: nosniff and X-Frame-Options: DENY. That is defense-in-depth behind the loopback bind and token, not a substitute for them.

--no-token removes the gate for a trusted single-user machine. drydock prints a warning when you use it, because then any local process or web page can submit tasks, approve pushes, and kill tasks through the server. Don't pair it with anything that exposes the port beyond loopback.