Using Keyhole

Recording to JSONL

Any live tail can be recorded to a lossless JSONL file — one JSON object per line — that's friendly to jq and browsable in-app.

Recording a tail

With a live tail focused, press r to start or stop recording — a red● REC n (bytes) indicator appears in the header while it runs. Files are written to ~/.local/share/keyhole/recordings/ as<connection>-<source_type>-<target>-<timestamp>.jsonl.

note

Recording is lossless even when the on-screen feed drops events under load. r only acts on a live tail — it's a no-op on the Console, Pub/Sub, and Tail anchors.

JSONL format

Each line is a self-contained record: a sequence number, an RFC 3339 timestamp, the connection and source, the payload encoding (utf8, json, orbase64), and the payload. A meta array carries source-specific extras (a stream entry id, a routing key) and is omitted when empty.

{"seq":0,"ts":"2026-06-27T14:02:09.118247Z","connection":"prod-cache","source":"orders.created","source_type":"pubsub","encoding":"json","payload":"{\"id\":48213,\"total\":24.9}"}
{"seq":1,"ts":"2026-06-27T14:02:09.640512Z","connection":"prod-cache","source":"orders.paid","source_type":"pubsub","encoding":"json","payload":"{\"id\":48213,\"ok\":true}"}

Working with jq

# pull the payload of every recorded pub/sub event
$ jq -r 'select(.source_type=="pubsub") | .payload' *.jsonl

Browse recordings

Open the Recordings tab with Tab / Shift+Tab to browse saved files read-only, newest first. Ctrl+← /Ctrl+→ switch between the list and the viewer; ↑ ↓scroll; r renames and d d deletes.