Live TUI demo of ChioBridge.receiptStream() — watch
signed receipts flow past a running chio daemon in real time, with inline
verifyReceipt and exportEvidence hotkeys.
The raw receiptStream() is a cold async iterable yielding ChioReceipt
values. That's fine for plugins, but nobody's going to paste an iterator
into a marketing page. A 80x24 live terminal is the smallest possible
surface that makes the cryptographic audit trail visible.
We looked at blessed (heavy, jQuery-era event model) and ink
(React overhead, SSR quirks on Windows). For a single-pane status table
with <1k lines of render code, raw ANSI escapes via process.stdout.write
wins:
- Zero runtime dependencies beyond
@chio/bridge. - Bundle stays under 200 LOC of render logic.
- Renders identically on macOS Terminal / iTerm2 / Alacritty / Kitty / GNOME Terminal / tmux.
- No "mystery React reconciler dropped my last frame" debug sessions.
cd chio-receipt-stream-demo
bun install
bun run buildTwo terminals. In both, source the harness env:
source /Users/connor/Medica/backbay/standalone/chio-test-harness/bin/env.shTerminal A — synthetic workload:
node scripts/drive-receipts.mjsThis starts the harness (idempotent), bonds a passport, and runs a 30s
workload of mixed echo / delete_file / paid_action / wire_transfer
calls through ChioBridge.check. Expect a mix of allow/deny/cancelled
verdicts — that's the point.
Terminal B — TUI:
bun start
# or: ./dist/index.jsYou should see rows fade in as receipts land. Columns:
| col | what it shows |
|---|---|
| time | receipt.timestamp (UTC, HH:MM:SS) |
| agent | first 10 hex of receipt.capability_id |
| tool | tool_server/tool_name |
| decision | allow (green) / deny (red) / cancel (yellow) |
| budget | per-receipt $USD when present (metadata.cost_usd or params.usd) |
| receipt-hash | first 14 hex of receipt.id |
| ok | ✓ / ✗ — ed25519 signature + parameter-hash verification |
| key | action |
|---|---|
q / Ctrl-C |
quit |
p |
pause/resume the stream |
v |
re-verify the selected row via ChioBridge.verifyReceipt |
e |
exportEvidence({since: streamStart}) to ./stream.bundle.json |
j / k |
select row down / up |
The underlying receiptStream() polls every 2s. If the trust plane goes
away mid-stream (e.g. someone kills the harness), we catch the
ECONNREFUSED / HTTP 5xx and back off exponentially (200ms → 8s cap,
with 100ms jitter). When receipts start flowing again the TUI prints
reconnected (N caught up) in the footer and bumps the reconnects
counter in the header.
Advance the since= pointer across reconnects so we don't re-emit
receipts that landed during the brief outage.
Capture a live run for the marketing page:
asciinema rec screenshots/stream.cast -c "./dist/index.js"Upload and replace the placeholder below:
https://asciinema.org/a/REPLACE_ME
For repos without asciinema, script(1) also captures ANSI directly:
script -q screenshots/stream.raw ./dist/index.jsA 40-line ANSI frame from the run that produced VERIFY.md lives at
screenshots/ascii-capture.txt.
src/
index.ts # CLI entry; arg parsing, passport-status poll, cleanup
tui.ts # render + key handling (alt-screen, no TUI lib)
stream.ts # bridge.receiptStream() wrapper with reconnect + inline verify
colors.ts # ANSI escape helpers (truncate, padRight, etc.)
scripts/
drive-receipts.mjs # synthetic workload generator
screenshots/
ascii-capture.txt # 40-line frame capture
- No modifications to
chio-bridge—receiptStreamis consumed as-is. - Real async iteration; no polling wrapper around
receipts(). - Reconnect with exponential backoff; announces caught-up count.
- Verification is inline at receipt arrival; the hash column turns red if a receipt ever fails.
- Responsive to terminal resize; tool column flexes, everything else
truncates with
…. - SIGINT restores the main screen buffer and exits 0.
Apache-2.0.