Skip to content

Output and Automation

Aaron Wasserman edited this page Jul 10, 2026 · 1 revision

Output & Automation

Output formats

Every command that produces structured output supports -o text|json|jsonl:

  • text — human-readable tables, borderless and space-padded so MAC addresses and UUIDs stay double-click-selectable in common terminals.
  • json — indented JSON, treated as the canonical representation (not a secondary export). Assessment commands emit {address, test, summary, findings[]}.
  • jsonl — one JSON object per line, for streaming commands (scan --live, listen), each event a discrete record as it arrives.

enumerate --compact emits one key=value line per characteristic, designed for grep or an LLM context window where tokens matter.

-o json / -o jsonl output is authoritative and complete. Do not re-run a command in text mode after running it with JSON. The JSON has every field the text table shows and more; re-running just doubles the BLE traffic.

caeruleus assess check-auth -b $A -o json | jq '.findings[] | select(.severity=="high")'
caeruleus enumerate -b $A --compact | grep -i write
caeruleus scan --live -o jsonl | jq -c '{addr:.address, rssi:.rssi, name:.name}'

Holding one connection across many operations

Most peripherals accept a single central at a time, and a fresh CLI invocation pays a ~1.5s reconnect cost. Three ways to keep one link warm:

serve / send — warm-link daemon. Best for an agent or script issuing many sequential commands.

sudo caeruleus serve -b $A            # holds one GATT connection open on a Unix socket
caeruleus send "enumerate"
caeruleus send "read 0x0029"
caeruleus send "write 0x002c deadbeef"

batch — one connection, commands from stdin. No readline overhead, no async pump; output goes straight to stdout (safe for piping/grep). If -b is given, the connection is established up front.

caeruleus batch -b $A <<'EOF'
read 0x0015
write 0x002b -s "test" --req
read 0x0029
EOF

shell — interactive REPL. For humans; gatttool-style verbs, scan + connect <#> by index.

Atomic trigger-then-capture

Notifications often fire within milliseconds of a write, so a separate write then listen misses the response. listen --trigger-value (optionally --trigger-handle when the write and notify characteristics differ) sets up the subscription, sends the write, and captures the response in one command:

# subscribe on 0x0083, write to 0x0081, capture the reply
caeruleus listen -b $A -a 0x0083 --trigger-handle 0x0081 --trigger-value FEDCBA0003000101EF

# repeated triggers, capture every response
caeruleus listen -b $A -a 0x0083 --trigger-handle 0x0081 --trigger-value 01 --trigger-count 5 --count 0

Pipe payloads

echo -e "deadbeef\ncafebabe\n01020304" | caeruleus write -b $A -a 0x002c --each-line
caeruleus read -b $A -a 0x0029 --extract | xxd -r -p    # bare hex out, for piping

See also Agents & LLM Usage for driving caeruleus from an assistant.

Clone this wiki locally