Control plane

A local web app for rupu — launch runs, watch them stream live, author agents and workflows, and review findings and coverage, all in one browser tab.

A web command center

The control plane is rupu's window onto everything it's doing on this host. One command opens a browser UI where you can observe every run, session, and event as it happens; control what runs and approve the steps that ask for it; and author your agents and workflows — without leaving the page. It's a thin web adapter over the same on-disk stores the CLI uses (your runs, agents, workflows, sessions, and the coverage ledger under ~/.rupu/), so the browser and the terminal are always looking at the same reality. Anything the CLI started — a rupu run, a cron trigger, an autoflow — shows up in the browser, and anything the browser starts is an ordinary run the CLI can see.

Start it with one command:

# serve the control plane and open it in your browser
$ rupu cp serve
#   ➜  rupu Control Plane  →  http://127.0.0.1:7878

By default it binds to 127.0.0.1:7878 and opens the URL in your browser when you run it interactively; the URL is always printed.

FlagDefaultMeaning
--bind <addr>127.0.0.1:7878Address and port to listen on.
--token <token>noneRequire the token on every /api/* route — a bearer header, or the browser cookie the printed link sets (see Authentication).
--no-openoffDon't open the URL in a browser.
--no-weboffServe /api and /mcp only, no web UI (implies --no-open).
--no-mcpoffDon't serve /mcp. Refused together with --no-web.
--tools <grant>every toolNarrow the MCP to these tools, operator tools and wait included (exact names, ns.*, *; comma-separated). Refused with --no-mcp; a bad grant fails before binding.
--max-open-files <N>—Raise the process's open-file limit (overrides RUPU_MAX_OPEN_FILES and [runtime].max_open_files).
# bind a custom port and require a token on /api/*
$ rupu cp serve --bind 127.0.0.1:9000 --token "$RUPU_CP_TOKEN" --no-open

# try it against an empty store
$ RUPU_HOME=$(mktemp -d) rupu cp serve --bind 127.0.0.1:9100 --no-open

Serve modes

Besides the web UI and /api, the server serves an MCP endpoint at /mcp so Claude Code, Cursor and other MCP clients can operate rupu (see The MCP endpoint). The two --no-* flags choose what is served:

CommandServes
rupu cp serveweb UI + /api + /mcp
rupu cp serve --no-web/api + /mcp, no web UI (implies --no-open)
rupu cp serve --no-mcpweb UI + /api, no /mcp

--no-web --no-mcp is refused (nothing to serve), and so is --tools with --no-mcp. At startup the server prints the MCP URL and the command that connects Claude Code to it.

One server per port. If the bind address is taken, cp serve exits non-zero at once; when the occupant is another rupu control plane, the error names its PID (/healthz answers ok with x-rupu-pid and x-rupu-version headers). Restart after upgrading. cp serve is a long-running daemon: installing a new rupu binary does not change a running server. bind and token are restart-only settings, and so are the switches and intervals of its background loops (see Background loops).

Authentication

Without --token the API is open to anything that can reach the bind address. That is the intended posture on 127.0.0.1. Do not bind a non-loopback address without a token. With --token, every /api/* route needs the token, in one of two forms:

The cookie is HttpOnly, SameSite=Strict, lasts 30 days, and is named rupu_cp_token_<port>, so control planes on different ports never overwrite each other. Its value is derived from the token, not the token itself, and it is refused as a bearer: browsers send localhost cookies to every port, so another local server could read it, but it never learns the token. A write made with the cookie must also carry an Origin naming this server, so a page served from another origin (another localhost port included) can't drive runs with it. Behind a reverse proxy, preserve the Host header: the cookie name and the origin check both read it. Restarting with a different token makes the old cookie a 401 until the browser opens the new link.

/healthz, the node WebSocket and the static UI shell stay open; they hold no data, since everything the UI shows comes from /api/*. The server log prints the URL without the token, and Settings only ever shows whether a token is set. /mcp sits behind the same token. See the HTTP API for the wire details.

Single binary, no setup. The web UI is compiled into the rupu binary — there's nothing to install or build. rupu cp serve serves the embedded app and reads your existing file-based stores directly; there is no database.
control plane rupu cp serve runs live graph + log sessions chat turns authoring agents + workflows findings coverage ledger
One local web app, hub for everything rupu is doing on this host.

Background loops

Besides the HTTP server, cp serve runs background work in-process, so autoflows, triggers and gate timeouts work without an external cron:

LoopWhat it doesKeys
Resume workerEvery 4 s, claims runs the UI marked for resume (an approved gate, a resume of a paused run) and spawns a detached rupu workflow approve / rupu workflow resume --if-unfinished child for each.always on
Autoflow reconcileThe same entry point as rupu autoflow tick: issue and PR entity autoflows.[cp].autoflow_reconcile_enabled, [cp].autoflow_reconcile_interval_secs
Cron tickrupu cron tick's core: cron- and polled-event-triggered workflows.[cp].cron_tick_enabled, [cp].cron_tick_interval_secs
Gate sweepFires overdue gates' on_timeout routing (reject runs the on_reject chain; approve spawns a detached workflow approve) and reaps orphaned Running/Pending runs whose recorded runner_pid is dead, marking them Failed.[cp].gate_sweep_enabled, [cp].gate_sweep_interval_secs
Agentiflow reaperOn the gate-sweep tick: finalizes an agentiflow run whose coordinator died.[agentiflow].reaper_enabled
ASN refreshOn the gate-sweep tick: refreshes the netflow ASN table when missing or stale.[netflow].asn_auto_refresh
Bucket pollerEvery 15 s, reads results from bucket-transport hosts.always on (no-op without bucket hosts)

All enabled flags default to true, all intervals to 60 s. The gate-sweep tick runs if any of its three duties is enabled; each duty is then checked on its own, so turning off gate timeouts doesn't stop the reaper. See Configuration.

# ~/.rupu/config.toml
[cp]
cron_tick_interval_secs = 30   # tick triggers twice a minute
gate_sweep_enabled = false     # no gate timeouts; reaper and ASN refresh still run

Observe

The observability surface is the heart of the control plane — watch everything rupu is doing, live, in the browser.

Live updates arrive over server-sent events: a global firehose behind Live Events, the new-run pill and status patching, and per-run streams for each run view. The firehose covers orchestrator runs (workflows, autoflows); a standalone rupu run never enters the run store and so doesn't appear on it. Runs the control plane started stream straight from the executor; runs started elsewhere (the CLI, a cron trigger, an autoflow) are tailed from their on-disk event log — so the same live view works no matter what kicked the run off. A run's stream resumes where it left off after a dropped connection rather than replaying the run, and closes once the run has settled; the run page keeps checking every 15 s, so a retried run streams back in.

The query line

Every list — Workflow Runs, Agent Runs, Sessions, Findings, Live Events and a project's Runs and Sessions tabs — has one query line, sent to the server as ?q= and evaluated there before the page is cut. The grammar is the findings grammar: a term's values OR, terms AND, - negates, a bare word searches the list's text fields, comparisons are case-insensitive, and time fields take 30m, 12h, 7d, 2w, a UTC date or an RFC 3339 time.

# workflow runs: failed or cancelled, not the nightly, last week
status:failed,cancelled -workflow:nightly since:7d "two words"

# agent runs on one host; sessions still active
host:sutajio agent:recon is:running
is:active model:sonnet
ListFields
Workflow runsstatus, workflow, id, codename, trigger (manual / cron / event), host, customer, since, until, is:archived (lists the archive; local only)
Agent runsstatus, agent, provider, model, is (running / completed / failed), source (standalone / session), session, trigger, codename, id, host, customer, since, until
Sessionsstatus (idle / running / failed / stopped), agent, model, provider, codename, id, host, customer, project, is:active / is:archived, since, until
Eventsgroup (activity / await / warning / error), type, run, project, workflow, agent, step, codename, provider, model, severity, message, since, until
FindingsThe findings query language — severity>=high tag:needs-poc -tag:false-positive "sql injection"; see Findings.

A query that doesn't parse is flagged on the line: the server answers it with the token and its span rather than a page. Facets — counts of each facet field's values over the list's scope before the query — come back with the rows (?facets=1). A host: term asks only the hosts it names; with remote hosts, their rows are filtered on this server, and a host whose rows can't report a field the query names (an older rupu) is left out and named in a one-line host alert rather than quietly shown unfiltered. A list's implicit defaults (the running statuses on the run lists, Agent Runs' source:standalone, Sessions' is:active) apply only while the query doesn't name that key.

Token flow

A run page carries a Token flow chart: tokens per model call across the whole run, in order, with the step each call belongs to. Selecting a span of it narrows the page — the Transcript, Events, Findings and Messages tabs show only what happened in those calls — because every point knows which transcript it is in, which turn of that transcript, and when the call finished (from the usage ledger; runs that predate the ledger have no time). A session page draws the same chart over its turns in its Session details disclosure. Older remote hosts send the points without the position fields, so a remote run's chart can't narrow the page.

Transcripts

Every transcript surface — the standalone /transcript page, a run's focused step, a session's turns, an agentiflow's units — renders through the same reader: one continuous reading column with a spine down the left, read top to bottom like a document rather than nested boxes. Turns are numbered markers on the spine (the live turn's marker glows), and each event carries a gutter glyph keyed to its kind: an operator message, thinking (shown in full, quiet, collapsible), what the assistant said (the loudest text), a tool call as one scannable row — verb, target, a result chip, its duration — that expands its input and output inline, a bash command rendered as a terminal line with its exit code, and a finding as a severity card, the one place colour lives. Skill loads, notices, gate pauses and decisions, context compaction, the seed prompt, and the outcome and recovery events written when a reply needed recovering are quiet one-line rows. A line the viewer doesn't recognise is shown as raw data with an unparsed badge rather than dropped, so a transcript from a newer rupu never silently loses content.

A long run is navigated from a metrics strip (turns, tool calls, commands, findings, tokens), sticky filter chips (All · Said · Thinking · Commands · Findings, with per-kind counts), Expand-all / Collapse-all, and a thin clickable outline rail of turn, finding and command tick marks with the current position highlighted. In a run transcript, an ast_grep tool call's matches open a line-numbered source slice around the match and a syntax-tree viewer for that region, read from the run's own working directory (or its host); a file that's gone or outside the workspace shows the reason instead.

Messages

A run with a message space — a workflow run, a session, an agentiflow, or a standalone run's transcript page — has a Messages tab over the space's log: every message the participants exchanged (posts, directs, broadcasts, directives and retractions), who it was delivered to and who has seen it, and the participants; a local live run's log is followed as it grows. Messages also appear as bubbles in transcripts, cross-linked to the tab.

The tab's composer sends as the operator, the same channel as rupu message send: pick a recipient — a participant, a codename, a role (role:<agent>), a step (step:<id>), an agentiflow's lead or everyone — and mark it urgent to put it ahead of everything else (and end an agentiflow lead's round early). The message reaches its recipients before their next model call, framed as an instruction from the human running the run. A run that isn't running takes no message: the composer is disabled with the server's reason. A send is shown as pending until its id reaches the log, never optimistically. Remote hosts answer over HTTP and SSH when their rupu advertises messages; tunnel and bucket hosts can't carry them, and the tab says so.

Findings

Each finding has its own page at /findings/<id>. A finding recorded as a full report opens with a section rail (description, impact, location, root cause, call chain, evidence, proof-of-concept artifacts, replication, remediation, patch, CI/CD and regression commands, references), a ledger of ownership and risk fields, and a completeness meter (n/11) that names the gaps. Every evidence claim carries a badge saying whether the file still matches what the agent saw (current, changed, missing), and the artifact browser previews text and images and pulls a remote host's artifacts on first view. Reports export to Markdown, HTML or PDF. When a finding's project has a known remote, its rows carry a View on repository link to the file and line range on the forge's web UI.

The findings tables triage in place: expand a row for root cause, attack path, owner and completeness; filter with the query line (severity>=high tag:needs-poc -tag:false-positive "sql injection"); and tag findings one at a time from a finding's page or in bulk from a table selection, with every change kept in a per-project tag history. See Findings for the report format, the query language and tagging.

Many hosts, loaded host by host

With remote hosts registered, the Activity tables, the Usage headline and the ⌘K palette's runs and sessions ask each host on its own (?host=<id>) and merge the answers as they arrive. A fast host paints at once; a slow one fills in when it answers; each request is bounded at 45 s. A host that doesn't answer is shown as:

ShownStatusMeaning
offline502The host couldn't be reached or failed (SSH down, connection refused, an error).
unavailable501The host answered but can't serve this listing — typically an older rupu that lacks the command.
(row dropped)404The host id is no longer registered.

A per-host freshness strip shows who has answered. The hosts list serves each host's last health probe from a cache (fresh for 15 s; a stale answer is served while one background refresh runs), so opening a page never waits on a fresh SSH probe, and SSH listings share a 5 s single-flight cache that any mutation clears. Pages that read history are served from in-process caches re-checked against the files on every request, so opening a page doesn't re-read every run ever recorded.

Control

Beyond watching, the control plane drives rupu from the browser. Because runs are detached processes, a control action's 200 means recorded, not done: the run's own status, arriving on the live stream, is what confirms it.

Same engine, new surface. The control plane doesn't reimplement any logic — launching, approving, and sending all route through the very same code the CLI uses. The browser is just another way in. Everything the UI does goes through the control plane's HTTP API, which you can script too — see the API reference.

Author

You can edit your agents (.md) and workflows (.yaml) right in the browser. Agents open in a code editor; workflows open in the visual workflow editor.

The workflow editor is a single screen: a drag-and-drop DAG on top and the live YAML below, kept in lock-step. Drag node cards from a palette onto the canvas, wire steps left→right exactly like the Runs graph, and watch the YAML rewrite itself underneath — or type in the YAML and watch the graph reconcile as you go. YAML stays the source of truth: the graph is a projection of it, and every save passes through the same validation the orchestrator already applies.

Every step kind has its own shape. The editor paints nodes as flowchart silhouettes rather than identical cards, so a workflow still reads when it's zoomed out far enough to see whole: a branch is a decision diamond, an action connector a parallelogram, an approval gate the trapezoid of a manual operation, a for_each a hexagon, and parallel / panel keep growing rectangular bodies for their sub-steps. Connection handles anchor to the silhouette itself, so nodes drag and wire by their real shape — and shape carries the kind independently of colour.

A Blocks palette with its own tab. The rail is one tab bar — Blocks · Step · Settings · Reference — so the palette and the editor no longer compete for height. Blocks sits on a dense chip grid with a filter across both the step kinds and the whole connector catalog, each chip previewing the silhouette it will place. Selecting a chip shows what it does, its required fields, and a short example before you commit it; drag-to-place or Add to canvas drops the node and jumps you straight to its form.

Per-kind authoring forms. The Step tab renders the form the selected node actually needs. Connector (action) steps get a form generated from the tool catalog's own JSON schema — required parameters marked, values that round-trip whether they're numbers, booleans, lists, or {{ … }} expressions — so new tools appear in the editor with no editor changes. Approval gates get editors for their notify hooks and their on-reject cleanup steps; panels and branches get their sub-schemas, with constrained choices (severity thresholds, minimums) instead of free text you can typo into a failed run. Any step that runs an agent has skills and preload_skills fields.

One visual language, author and run. The live run graph paints from the same kind palette as the editor, with connectors animating along the active path — kind colour carries identity while status stays the overlay, so a running step pulses, a gate awaiting you glows amber, and a failure still reads as a failure. Watching a run and editing it look like the same thing.

Every expression field — a step's prompt, when, a branch's condition, or a panel's subject — gets syntax highlighting and context-aware autocomplete. Inside {{ … }} it suggests the right vocabulary for where you are: declared inputs, the outputs of steps that run before this one (never a forward reference), loop locals like item inside a for_each, panel findings, and the available filters. A searchable expression reference panel surfaces the whole vocabulary and inserts at the cursor. Validity is checked live — at the field, on the node, and in a header badge — so mistakes show up before you ever save. New workflow starts one from YAML, or has a model generate a draft from a description.

Agent Builder. New agent opens a full-page card composer: drag field cards (identity, prompt, model, tools, permission, reasoning, output and more) from a palette onto a canvas and watch the .md file build in a live preview beside it. A Cards · Raw · AI switch lets you edit the file directly or describe the agent and have a model draft it. Its Skills card edits the agent's skills: and preloadSkills: with the installed names as suggestions, and the control plane checks them the way rupu agent validate does: an agent whose skills aren't all installed shows This agent can't be launched with the reason and the install hint. Saving such an agent is allowed, so it can be written before its skills are installed; only a malformed entry is refused.

Library: agents, workflows, autoflows, skills

The Library holds every definition the control plane can see, global or project-scoped, with a Run on each. Its Skills tab lists the installed Agent Skills: the global layer, plus the picked project's layer, like rupu skill list. Each row shows its layer, status, source and description; an invalid skill shows its error, and a layer that can't be read is left out with a warning while the other layer still lists. A skill's page shows its description, compatibility, license, allowed-tools with the rupu tools they map to (informational, never a grant), metadata, files, body, content hash and install record. Installing and updating skills stay CLI operations (rupu skill install / update).

Settings & project config

You can edit rupu's configuration from the browser. A global Settings page writes the global ~/.rupu/config.toml, and a Config tab on each Project detail view writes that project's .rupu/config.toml. Config is layered global → customer → project (a locked key in a higher layer wins; see Configuration), and the control plane shows the effective value for every key together with its provenance — which layer won.

Each surface is hybrid: a typed Form tab with per-field validation, plus a raw TOML tab with validate-on-save, both writing the same file. Alongside them sit a policy view (what's locked) and a runtime status view — the latter shows restart-required settings such as bind and token read-only (the token masked). Saving the global config reports which of the start-time-only keys you changed (the [cp] background-loop toggles and intervals, agentiflow.reaper_enabled, netflow.asn_auto_refresh): those apply after cp serve restarts, everything else at once.

Policy enforcement. An admin can lock specific settings at the global level so projects — and the UI — can't override them. Locked keys are pinned to the global value wherever config is resolved (CLI, agent runs, cron, and the control plane alike), and appear read-only on the project Config tab. Locks are declared as dotted key paths in a [policy] section of the global config:

# ~/.rupu/config.toml — lock keys so projects can't override them
[policy]
lock = ["permission_mode", "autoflow.max_active", "cp.max_workspace_bytes"]

# control-plane runtime settings live in their own section
[cp]
max_workspace_bytes = 104857600

Writes go through validated config endpoints — GET the effective config with provenance, and PUT the global config, a project's config, or the policy lock list. Every write is validated, backed up, and written atomically; project-config paths are confined under the project's .rupu/ (no path traversal), and writes require the full rupu cp serve runtime.

Models. Settings has a Models tab listing every model each configured provider offers, with its input limit, output cap and where each number came from (your [[providers.X.models]] entry or the provider's own model list, cached for an hour). Refetch pulls a fresh list from one provider or all of them. Runs resolve their limits from the same catalog — an agent's own pins win — so the context gauge and compaction use the numbers you see here.

Customers

If you work for several clients, a customer scope picker in the header narrows the whole UI to one of them — all, no customer, or a named customer. Runs, sessions, workflows, agents, findings, projects and usage follow it, and the choice is remembered in the browser. A page that can't be filtered says so rather than quietly showing everything. The Customers page manages customers and their project assignments, shows per-customer rollups priced with that customer's own pricing, and edits each customer's config layer. Before a launch, the launcher shows which customer the run will be attributed to and which provider, fallback and SCM accounts it will authenticate as — resolved exactly the way the launch itself resolves them. See Customers.

Multi-host

One control plane can drive rupu running on other machines, not just the one it's on. Register a remote host — over HTTP, SSH, a dial-home tunnel, or an object-store bucket — and launch runs, agents, and sessions on a chosen host, observe and control them, all from one browser, with a Fleet → Hosts surface and host filtering on run lists. See Multi-host for setup and the transport roadmap.

The MCP endpoint

rupu cp serve also serves an MCP endpoint at /mcp (streamable HTTP), behind the same token as /api. An MCP client such as Claude Code, Cursor or Claude Desktop connects to it and operates rupu — lists and launches workflows and agents, watches runs, approves gates, drives sessions and messages a live run — with one operator tool per control-plane route, a wait tool that long-polls for a run to settle, and rupu's own tool catalog (files, shell, SCM, issues, findings) as plain tools. It adds no permission layer of its own: what runs is decided by the MCP client's harness, so treat the bearer token like a key to the whole control plane and narrow what is served with --tools. The old rupu mcp serve is deprecated and now runs rupu cp serve --no-web. Connecting a client, the tools, resources and prompts are in MCP & tools.

# connect Claude Code (loopback, no token)
$ claude mcp add --transport http rupu http://127.0.0.1:7878/mcp

UI tour

A page-by-page map of the web app, with the route each page lives at. Every route can be bookmarked or shared, and the ⌘K command palette jumps to any page, run or session.

Two navigation shells

The app ships two sidebars over the same pages. The default (v1) shell lists every page in grouped sections — Runs, Security, Build, Fleet. The newer v2 shell folds them into seven destinations (/overview, /activity, /projects, /security, /library, /fleet, plus Customers), each a tab bar whose active tab sits in ?tab=. Old links keep working: under v2, /agents redirects to /library?tab=agents, /hosts to /fleet, /findings?q=… to /security?tab=findings&q=…, and so on. Pick the shell in the global config; it is read on every page load, so a browser refresh applies it, no restart needed:

# opt into the v2 navigation shell
$ rupu config set ui.cp.shell v2
v2 destinationTabs
/overviewThe dashboard.
/activityagents · workflows · autoflows · sessions (run lists)
/securityfindings · coverage · catalog
/libraryagents · workflows · autoflows · skills (definitions)
/fleethosts · workers

Runs and transcripts

RouteWhat it shows
/runs/agents, /runs/workflows, /runs/autoflows, /runs/agentiflowsOne run list per kind, on the query line (host, status, time window, customer). /runs redirects.
/runs/<id>The live run view: graph, Token flow, the focused step's transcript, and the Events, Findings, Messages and Network tabs, with the run's controls.
/transcript?path=…A transcript on its own page, for agent runs, sessions and sub-agents that have no workflow graph. It streams while the run is live, and resolves a remote host's transcript when the link carries host and run.
/sessions, /sessions/<id>Session list and chat view (Conversation and Messages tabs).
/agentiflows/<id>Agentiflow detail (see Observe above).
/eventsLive Events: the vitals strip, the Needs-you deck and the event rail.
/usageSpend over time and the outlier panel.
/netflowThe global network explorer. With no since: or until: in its query it opens on the shorter of the last hour and the latest run's span.

Library: agents, workflows, autoflows, skills

RouteWhat it shows
/agentsEvery agent definition the control plane can see, global or project-scoped, with its last run. New agent opens the builder.
/agents/newThe Agent Builder (see Author above). Saving opens the new agent's page.
/agents/<name>Provider, model and limits up top, the highlighted definition file below, with Edit, Delete, and Run (which opens the launcher), plus the agent's recent runs.
/workflowsWorkflow definitions. New workflow starts one from YAML, or has a model generate it from a description.
/workflows/<name>The visual workflow editor (see Author above), with a validity badge and Save, Revert, Delete and Run.
/autoflowsWorkflows that declare autoflow triggers, each with a toggle to enable or disable it.
/skills, /skills/<layer>/<name>The installed skills (global and project layers) and a skill's page (see Library above).
No feature flags. The Agent Builder and the visual workflow editor are always on. The old [cp].agent_authoring_ui and [cp].workflow_editor_ui keys picked between a classic and a newer UI; the classic UIs are gone, and the keys are now ignored. rupu logs a warning if your config still sets them. Delete them.

Projects

/projects lists every project this control plane tracks, with its customer. Each project's page has an identity header with rollup tiles and a tab per route:

RouteTab
/projects/<id>Overview: a usage timeline, recent runs, coverage, sessions, and a summary of the project's definitions.
/projects/<id>/runsRuns started in this project, on the query line.
/projects/<id>/findingsFindings filed against the project.
/projects/<id>/codeCode: a file tree and syntax-highlighted source viewer for the project's checkout, with findings shown inline at their lines and a link to the repository.
/projects/<id>/sessionsSessions in this project, on the query line.
/projects/<id>/coverageCoverage for the project's targets.
/projects/<id>/networkNetwork: the netflow explorer scoped to this project.
/projects/<id>/configConfig: the project's .rupu/config.toml (see Settings & project config).
/projects/<id>/definitionsThe agents, workflows and autoflows this project can use: global definitions merged with its own .rupu/ ones, each badged project or global. Linked from the Overview tab.

Security: findings, coverage, assets

RouteWhat it shows
/findings, /findings/<id>The findings table and report page (see Findings above).
/coverageCoverage status for every target.
/coverage/<target>Overview: findings, files touched (by kind of touch), and how many concerns were assessed clean, with a finding, examined, or not applicable.
/coverage/<target>/catalogThe concern catalog that applied to the target.
/coverage/<target>/auditPer-concern coverage: which in-scope files were assessed and which weren't, plus cross-model and serendipitous findings.
/coverage/<target>/gapOnly the concerns with unassessed files, filterable by severity and file.
/coverage/<target>/diffTwo runs' contributions to the target side by side (previous vs latest by default).
/coverage/templatesThe bundled concern templates, independent of any target.
/assetsSecurity → Assets: the asset inventory across every project: hosts and services for network engagements, sites and routes for web, files for code.

Fleet: hosts and workers

RouteWhat it shows
/hostsRegistered hosts and their health.
/hosts/<id>One host's details and health, plus the workflow runs on it.
/workersRead-only list of workers: the machine-and-identity pairs that have run something (a rupu workflow run or a session turn registers one), with their capabilities, recent activity and when each was last seen. A worker is not a running process; one that hasn't checked in for a while shows as stale.

Settings

/settings has typed tabs for General, Providers, Models, Autoflow, SCM / Issues, Pricing and CP-Runtime, then Raw (the global config.toml, read-only until you click Edit), Policy (every key with a lock checkbox), and Runtime status. Each typed field shows its effective value, which layer it came from, and a lock toggle. The control plane's own token is never shown or editable, only whether one is set.

Customers

/customers and /customers/<slug> (with a tab per sub-route) manage customers; see Customers above.