Receipt Dashboard
Serve the operator dashboard from the trust control plane and trace any call to its signed receipt and capability chain.
On this page
The receipt dashboard runs inside the trust control plane, on the same address as its API: an operator summary across the top, a filterable receipt list, and a detail panel that follows each call to its signed receipt and the capability chain behind it.
Every panel calls a documented trust-control route, the query contract the chio CLI uses, and each route admits only the principals its class allows. Two requests made a minute apart can return different rows as receipts arrive.
The summary is the operator report
The summary panels come from GET /v1/reports/operator, composed on the server from the receipt and budget stores. Budget utilization is current state, so the receipt time window leaves it unchanged. Operator reports.
1. Start the trust control plane with the dashboard
Point the service at its receipt, authority, and revocation stores, with the admin service token in CHIO_TRUST_SERVICE_TOKEN. The three store flags are global flags on chio.
$ export CHIO_TRUST_SERVICE_TOKEN="$(cat secrets/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.sqliteChio trust control service listening on http://127.0.0.1:8940
You should see the listening line. The dashboard is a static catch-all mounted after every API route on the same router, so one address serves both and there is no second port. chio trust serve is flag-driven, with no separate config file: --service-token sets the admin principal and each --tenant-read-token adds a tenant principal, as Trust Control Plane covers.
Run it with Docker Compose
services:
chio-trust:
# The release container image: the chio binary with the dashboard embedded.
image: ghcr.io/backbay-labs/chio:0.2.0
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
environment:
# The admin service token, read from the host environment.
CHIO_TRUST_SERVICE_TOKEN: ${CHIO_TRUST_SERVICE_TOKEN:?set the admin service token}
ports:
- "8940:8940"
volumes:
- chio-state:/var/lib/chio
volumes:
chio-state:chio trust serve is a subcommand of the single chio binary, so the dashboard ships in the release container image with no separate trust-control image. Mount a volume for the stores so they survive a container restart.
2. Check that the API and the dashboard answer
$ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8940/health
$ curl -sI http://127.0.0.1:8940/ | grep -i '^content-security-policy'200 content-security-policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self'; img-src 'self' data:
You should see 200 from the health route, then the dashboard's content security policy: scripts, styles, and API calls load only from the service's own origin.
3. Sign in with the admin principal
Open http://127.0.0.1:8940/ and sign in with the admin service token. Dashboard data requests carry it in the Authorization header, and the service rejects a token placed in the URL query string.
You should see the operator summary. Without a credential the dashboard shows an operator guidance state and sends no unauthenticated requests, so a misconfigured deployment shows an empty dashboard and exposes no receipt metadata. The full operator view needs the admin principal; a tenant read token reaches only its own tenant's receipts, never the summary, analytics, lineage, or approval routes.
4. Trace a call to its receipt and its authority
The dashboard has three panes: filters on the left, the operator summary across the top, and a receipt table that opens a detail panel on the right. Narrow the table with the filters, then select the row for the call.
- Filter. Set the agent subject, tool server, tool name, outcome, or time window. Each filter is a parameter on
GET /v1/receipts/query, so the view matcheschio receipt listwith the same filters and ordering. Changing a filter returns to page 1; results arrive 50 to a page with cursor-based previous and next controls. - Open. The detail panel shows the decision (allow, deny, canceled, or incomplete), tool server and name, timestamp, capability ID, financial metadata, the raw parameters, and the full receipt JSON for a ticket.
- Follow the authority. The delegation chain lists every capability from the root to the leaf the agent held, with issuer, subject, window, depth, and grants.
You should see the signed receipt and, beneath it, how the capability it names was delegated and attenuated before it reached the agent. The panel renders the receipt struct field for field; Receipt format defines each field, and the detail reference lists the panel's routes.
The summary is the operator report, composed on the server
The summary above the table comes from GET /v1/reports/operator, built by the service from its stores, so it covers every matching receipt beyond the page the table has loaded. It answers whether an agent or tool slice is active, within budget, and ready to export.
| Panel | Shows | Use it for |
|---|---|---|
| Activity | Receipt totals, allow and deny ratio | Whether the slice is doing anything |
| Spend | Spend totals, top root budget holder | Who drives cost in the window |
| Budget pressure | matchingGrants, nearLimitCount, exhaustedCount | Grants near or at their limit |
| Compliance state | checkpointCoverageRate, lineageCoverageRate, uncheckpointedReceipts | Coverage indicators |
| Settlement readiness | pendingSettlementReceipts, failedSettlementReceipts, proof completeness | Settlement work before an invoice export |
| Shared evidence | Reference counts, latest partner and share | Federated evidence context |
Budget utilization is current state, so the receipt time window leaves it unchanged. The settlement card names pending settlements, failed settlements, and incomplete proofs before you attempt an invoice export. Coverage figures are report counts; an evidence export carries the inclusion proofs, as Operator Reports explains.
Approvals reach a person through the dashboard
The dashboard is the operator web client for the trust control plane. Its approvals panel lists pending requests for a person to decide, the same queue chio approvals pending reads and chio approve <id> decides. Approval routes admit only the admin principal.
The same client carries the issuance panel, an authority-tree view, and pool views, each calling its own trust-control route under the same principal check. Require human approval covers the approval flow end to end.
A passport compares against local history beside its subject
With the agent subject filter set, a comparison panel appears above the table. Upload a passport JSON document and the dashboard calls POST /v1/reputation/compare/{subject_key}, the contract chio reputation compare --control-url ... uses, with no second scoring path in the browser.
- Whether the live local subject key matches the passport's subject DID.
- The current local effective score and resolved tier.
- A relying-party acceptance state, when the passport carries 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.
Reputation is an optional module, off in default builds of the control plane and CLI; the panel answers when the deployment enables it. Reputation covers scoring.
Imported evidence stays beside local history
GET /v1/federation/evidence-shares returns the shared-evidence report shape that operator reports and reputation comparison use, and the summary's shared-evidence card reads it. Imported remote references appear as references, kept apart from the native local receipt history.
$ chio trust evidence-share list \
--agent-subject <subject-hex> \
--jsonA dashboard problem shows at sign-in or in an empty panel
The dashboard shows the operator guidance state
No credential reached the service. Sign in again with the admin service token or a tenant read token; a token pasted into the URL is rejected.
The summary and lineage panels stay empty
The credential is a tenant read token. Tenants read their own receipts through Tenancy & Read Scoping; the operator summary, analytics, and lineage need the admin principal.
Approve is refused
The signed-in credential is a tenant read token, and approval routes admit only the admin principal. Sign in with the admin service token, or decide from the CLI with chio approve <id>.
Dashboard reference
Try outcome, lineage, timeBucket, or --listen.
Receipt filters
| Filter | Type | Selects |
|---|---|---|
Agent subject | Hex Ed25519 public key | Receipts produced against that agent's capability tokens |
Tool server | Exact-match string | One tool server identifier |
Tool name | Exact-match string | One 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 |
The outcome values are the four Decision variants. The time window applies to receipt queries; current budget utilization is a state view outside it.
Detail panel contents
- Decision badge: Allow, Deny, Canceled, or Incomplete.
- Tool server and tool name, with a formatted timestamp, and the full capability ID.
- Financial metadata when present: cost charged, budget remaining, total budget, delegation depth, and settlement status, formatted from minor units in the receipt's own currency.
- The agent subject key when attribution metadata is present.
- A per-day cost sparkline, the raw tool-call parameters, and the full receipt JSON.
Delegation chain
The DelegationChain component fetches GET /v1/lineage/{capability_id}/chain and renders every CapabilitySnapshot from root to leaf. Each snapshot shows subject_key, issuer_key, issued_at, expires_at, delegation_depth, and the raw grants JSON.
Budget sparkline
When the selected receipt has financial metadata, the panel renders a BudgetSparkline from GET /v1/receipts/analytics?agentSubject=...&timeBucket=day. It uses the receipt's attribution subject key and falls back to capability lineage when attribution metadata is absent. The chart is inline SVG, with no charting library in the bundle.
Routes the panels call
| Panel | Route |
|---|---|
Operator summary | GET /v1/ |
Receipt table | GET /v1/ |
Delegation chain | GET /v1/lineage/{capability_id}/chain |
Budget sparkline | GET /v1/ |
Reputation comparison | POST /v1/ |
Shared evidence | GET /v1/ |
Service flags
| Flag | Default | Notes |
|---|---|---|
--listen | 127.0.0.1:8940 | Bind address for the API and the dashboard |
--receipt-db | none | Global flag; receipt SQLite database path |
--authority-db | none | Global flag; authority store path |
--revocation-db | none | Global flag; revocation store path |