BuildOperations
Receipt Dashboard
The operator dashboard indexes the kernel receipt log and is served by the trust control plane API.
What It Shows
The dashboard is a thin skin over the same HTTP API the chio CLI uses. Every panel is driven by a documented endpoint on the trust-control service, so the view in the browser and the view from the CLI stay in sync. No client-side reconstruction, no shadow scoring path.
- Receipts by agent: filter on an agent subject (hex-encoded ed25519 public key) to see only receipts produced against that agent's capability tokens.
- Receipts by tool server and tool name: exact-match filters for narrowing to one route or tool.
- Receipts by outcome: the four
Decisionvariants.allow,deny,cancelled,incomplete. - Budget pressure: per-grant utilization with near-limit and exhaustion counters.
- Time range: unix-second
since/untilwindow applied to every query.
The browser and the CLI see the same thing
GET /v1/receipts/query. A dashboard view and the equivalent chio receipt list invocation return the same rows in the same order.Layout at a Glance
The dashboard is a three-pane layout: filters on the left, a composed operator summary across the top, and a paginated receipt table that opens a detail panel on click.
Clicking any row opens a detail panel on the right. The panel renders the full receipt JSON, financial metadata (cost charged, budget remaining, total budget, delegation depth, settlement status, all formatted from minor units), a per-day cost sparkline, and the full delegation chain from root capability to leaf.
Operator Summary
Above the receipt table sits a composed operator summary backed by GET /v1/reports/operator. It is not a client-side reconstruction over paged receipts. The summary is the primary view for answering the question is this agent or tool slice healthy and exportable right now?
| Panel | Surfaces | Use For |
|---|---|---|
| Activity | Receipt totals, allow / deny ratio | Is this slice doing anything at all |
| Spend | Spend totals plus top root budget holder | Who is driving cost in the filtered window |
| Budget Pressure | matchingGrants, nearLimitCount, exhaustedCount | Grants about to trip or already tripped |
| Compliance State | checkpointCoverageRate, lineageCoverageRate, uncheckpointedReceipts | Audit readiness of the receipt log |
| Settlement Readiness | pendingSettlementReceipts, failedSettlementReceipts, proof completeness | Is this slice exportable for invoicing |
| Shared Evidence | Reference counts plus the latest referenced partner / share | Federated reputation context |
Export scope
Filtering Receipts
The left sidebar exposes six filters. All of them map directly to GET /v1/receipts/query. Changing any filter resets pagination to page 1. Results are paginated 50 per page, with cursor-based previous and next controls.
| Filter | Type | Description |
|---|---|---|
| Agent Subject | Hex ed25519 pubkey | Only receipts produced against this agent's capability tokens |
| Tool Server | Exact-match string | Single tool server identifier |
| Tool Name | Exact-match string | Single tool name within a server |
| Outcome | Enum | allow, deny, cancelled, incomplete |
| Since | Unix seconds (u64) | Lower bound on receipt timestamp |
| Until | Unix seconds (u64) | Upper bound on receipt timestamp |
Launching the Dashboard
The dashboard SPA is served as a static catch-all from dashboard/dist/ on the same axum router as the control API, mounted after all API routes. It is gated on dashboard/dist/index.html being present at startup: build the bundle into that path and chio trust serve hosts the UI and the API on one address. There is no separate dashboard bind.
Local development
# Default listen address: 127.0.0.1:8940. The service token is required;
# supply it via CHIO_TRUST_SERVICE_TOKEN so it stays out of ps/proc.
$ export CHIO_TRUST_SERVICE_TOKEN=$(cat ./secrets/chio_service_token.txt)
$ chio trust serve \
--listen 127.0.0.1:8940 \
--receipt-db ./receipts.sqlite \
--authority-db ./authority.sqlite \
--revocation-db ./revocations.sqlite
# Then open http://127.0.0.1:8940/ in a browserThe server serves the dashboard bundle as a static catch-all after all API routes, so the same address hosts the API and the UI. There is no second port to open.
Docker compose
services:
chio-trust:
# An image carrying the chio binary plus the compiled dashboard/dist
# bundle. chio trust serve is a subcommand of the single chio binary,
# not a separate trust-control product image.
image: your-registry/chio:latest
command:
- chio
- trust
- serve
- --listen
- 0.0.0.0:8940
- --receipt-db
- /var/lib/chio/receipts.sqlite
- --authority-db
- /var/lib/chio/authority.sqlite
- --revocation-db
- /var/lib/chio/revocations.sqlite
ports:
- "8940:8940"
volumes:
- chio-state:/var/lib/chio
environment:
# Required bearer token. hide_env_values keeps it out of --help output;
# source it from your secret manager or a .env file, never commit it.
CHIO_TRUST_SERVICE_TOKEN: ${CHIO_TRUST_SERVICE_TOKEN}
volumes:
chio-state:Authentication
Every request the dashboard makes is bearer-authenticated. The token is resolved in this order:
sessionStoragekeychio_token(set from a previous visit).- URL query parameter
?token=<value>.
When a token is found in the URL it is promoted to sessionStorage and removed from the URL bar via window.history.replaceState. That keeps the token out of browser history and out of the Referer header on outbound navigations.
# Hand an operator a one-shot URL
$ echo "http://127.0.0.1:8940/?token=$(cat ./secrets/chio_service_token.txt)"
http://127.0.0.1:8940/?token=sv_live_8f2c...No token means no data
Closing the tab clears sessionStorage. Reopening the dashboard later requires either a fresh ?token= URL or the previous tab still being alive.
Receipt Detail Panel
Clicking a row opens a right-hand detail panel that renders everything needed for a spot audit without leaving the browser.
- Decision badge (Allow, Deny, Canceled, Incomplete).
- Tool server and tool name, plus a formatted timestamp.
- Full capability ID.
- Financial metadata when present: cost charged, budget remaining, total budget, delegation depth, settlement status. All formatted from minor units using the receipt's own currency field.
- Agent subject key when attribution metadata is present.
- Cost-over-time sparkline, aggregated per day by the backend analytics API for the receipt subject.
- Raw tool-call parameters.
- Full receipt JSON for copy-paste into tickets.
Delegation chain view
The DelegationChain component fetches GET /v1/lineage/{capability_id}/chain and renders every CapabilitySnapshot in the chain from root to leaf. Each snapshot shows subject_key, issuer_key, issued_at, expires_at, delegation_depth, and the raw grants JSON. Operators can trace exactly how a capability was delegated and attenuated before it reached the agent.
Budget sparkline
When the selected receipt has financial metadata, the panel renders a BudgetSparkline backed by GET /v1/receipts/analytics?agentSubject=...&timeBucket=day. It uses the receipt's attribution subject key, falling back to capability lineage when attribution metadata is absent. The chart is inline SVG, which keeps the dashboard bundle small without pulling in a charting framework.
Portable Reputation Comparison
When the Agent Subject filter is set, an extra panel appears above the receipt table. Operators can upload a passport JSON document and the dashboard calls POST /v1/reputation/compare/{subject_key} on the trust-control service.
The panel renders:
- Subject match vs mismatch between the live local subject key and the passport subject DID.
- Current local effective score and resolved tier.
- Optional relying-party acceptance state when the uploaded passport document contains a verifier-evaluation result.
- Per-credential drift for composite score, reliability, delegation hygiene, and resource stewardship.
- Shared-evidence provenance: partner and share IDs, remote capability IDs, local anchor capability IDs, and local receipt counts.
Receipt-store data
chio reputation compare --control-url .... There is no second local scoring path embedded in the dashboard.Shared Evidence API
Trust-control exposes GET /v1/federation/evidence-shares, which returns the same shared-evidence report shape used inside operator reports and portable reputation comparison. The CLI wrapper is:
$ chio trust evidence-share list \
--agent-subject <subject-hex> \
--jsonThis surfaces imported remote evidence references directly without merging foreign receipts into native local receipt history. The dashboard uses the same endpoint for its shared-evidence summary card.
Configuration Reference
chio trust serve is flag-driven; there is no separate config file. The dashboard rides on the same address as the API, so configuration is a handful of flags:
| Flag | Default | Notes |
|---|---|---|
--listen | 127.0.0.1:8940 | Bind address for both the API and the dashboard SPA |
--service-token | required | Bearer token; prefer CHIO_TRUST_SERVICE_TOKEN so it stays out of ps//proc |
--receipt-db | — | Global flag; path to the receipt SQLite database |
--authority-db | — | Global flag; authority store path |
--revocation-db | — | Global flag; revocation store path |
# --service-token has no default, so the server cannot start without it.
$ export CHIO_TRUST_SERVICE_TOKEN=$(cat ./secrets/chio_service_token.txt)
$ chio trust serve \
--listen 127.0.0.1:8940 \
--receipt-db ./state/receipts.sqlite \
--authority-db ./state/authority.sqlite \
--revocation-db ./state/revocations.sqliteFor deeper queries on individual receipts, consult the receipt format reference. The dashboard renders the exact same struct, field for field.