Surface interactions
Every surface is a client of the same runtime. Keys stay server-side; the surfaces hold no business logic.
Extension ↔ Runtime
The Sentinel browser extension is a thin client of the runtime. Its content script captures an AI response on the page; the extension's API gateway posts it to POST /api/v1/audit/conversation and renders the returned verdict in an overlay. The extension performs no model calls and holds no keys, keys live server-side only, which is the whole point of the server-side audit boundary.
sequenceDiagram
autonumber
participant P as Page (content_script)
participant BG as Extension (api_gateway.js)
participant API as VerifAIer runtime
P->>BG: captured AI response
BG->>API: POST /api/v1/audit/conversation {task, instructions, input}
API-->>BG: verdict + routing + envelope/receipt/provenance
BG-->>P: overlay UI verdict
Note over BG,API: keys live server-side only, the extension never sees one
Extension ↔ Runtime, the extension is a client of the audit endpoint. Source: extension/, api/routes.py.The extension also uses the deterministic POST /sentinel/verify path for the fast hallucination check (validation engine, no provider), mapping confidence/verifiability to ACCEPT / REVIEW / REJECT. Either way the runtime is the source of truth and the only holder of provider credentials.
Dashboard ↔ APIs
The enterprise dashboard is a static, framework-free client. dashboard/js/api.js resolves the API base URL at runtime, window.VD_API_BASE, then localStorage["vd_api_base"], then same-origin when served over http(s), falling back to http://localhost:8000 when opened via file://. Every page calls the governance APIs through this one client; no business logic is duplicated in the browser.
flowchart LR
subgraph B["Base URL resolution, dashboard/js/api.js"]
U["window.VD_API_BASE → localStorage 'vd_api_base' → same-origin (http) → 'http://localhost:8000' (file://)"]
end
U --> API["VerifAIer API"]
API --> A1["/api/v1/trust · risk · quality · compliance /assess"]
API --> A2["/api/v1/passport/issue · /reputation/assess"]
API --> A3["/api/v1/registry/observe · /agents · /agents/{id}"]
API --> A4["/api/v1/control-center/overview"]
API --> A5["/api/v1/signals/export"]
Dashboard ↔ APIs, a static client with runtime-resolved base URL. Source: demo/dashboard/js/api.js.The client wraps the same endpoints documented in the API reference: the four assessment endpoints, passport/reputation, the registry (observe / list / get), the control-center overview and signal export. Requests carry a plain {evidence: …} (or the relevant inputs); responses are the full export dicts.
Control Center ↔ Runtime
The Control Center is a read-only aggregation. GET /api/v1/control-center/overview calls ControlCenterEngine.overview(_registry), which lists the registry entries and rolls up their cached latest values into fleet metrics. It never re-runs identity/trust/passport/reputation logic and never touches prompts or secrets.
flowchart LR DASH["Control Center UI"] --> EP["GET /api/v1/control-center/overview"] EP --> CCE["ControlCenterEngine.overview(_registry)"] CCE --> RG["_registry.list() → AgentRegistryEntry[]"] RG --> AGG["aggregate cached latest_* values"] AGG --> LVL["reuse trust/reputation level_for_score()"] LVL --> OUT["ControlCenterOverview (totals · averages · level counts · agents)"]Control Center ↔ Runtime, read-only aggregation over the registry. Source: control_center/engine.py.
Trust and reputation levels in the overview are derived from the entries' cached scores by reusing the existing trust.scoring.level_for_score and reputation.scoring.level_for_score functions, no thresholds are re-implemented. Per-agent risk/quality levels are not yet cached on registry entries, so they are honestly reported as unknown (a future phase can cache them). An empty registry yields a valid, zeroed overview.