Inspect telemetry (NATS CLI)
Live-tail and filter agent telemetry events straight from the NATS CLI — no forwarder or sink required.
Prerequisites
The
natsCLI on$PATH(install).Optional:
jqfor filtering and pretty-printing JSON.An auditor JWT scoped to the agent(s) you want to read. See How to verify what your agent publishes for issuance.
Your
natsCLI configured with that auditor's.credsfile:nats context save auditor --creds=/path/to/auditor.creds
Tail all events from one agent
scripts/telemetry_tail.sh CortexA
The script subscribes to telemetry.agent.CortexA.> and pipes
each event through jq -c if available. Each line is one event in
the catalog (see event reference).
Tail every agent's events
scripts/telemetry_tail.sh
Subject becomes telemetry.agent.*.> — one stream of every
agent in your scope. Pre-deployment debugging only; in production a
forwarder handles fan-in.
Filter by event type
The script writes one JSON object per line; pipe through jq to
filter:
scripts/telemetry_tail.sh | jq 'select(.type == "llm_request_complete")'
scripts/telemetry_tail.sh | jq 'select(.type | startswith("task_"))'
scripts/telemetry_tail.sh | jq 'select(.type == "llm_request_failed" and .error_class != "transport")'
Aggregate over a time window
Tail for N seconds, then aggregate:
timeout 60 scripts/telemetry_tail.sh \
| jq -s 'group_by(.type) | map({type: .[0].type, count: length})'
Compute p95 LLM latency by provider_backend
timeout 60 scripts/telemetry_tail.sh \
| jq -s '
[.[] | select(.type == "llm_request_complete")]
| group_by(.provider_backend // "unknown")
| map({
backend: .[0].provider_backend,
p95_ms: (sort_by(.latency_ms) | .[(length * 95 / 100) | floor].latency_ms),
n: length,
})
'
Spot context-overflow rate
scripts/telemetry_tail.sh | \
jq 'select(.type == "llm_request_failed" and .error_class == "context_overflow")
| "agent=\(.agent_id) model=\(.provider_id) ts=\(.ts)"'
Spot prompt-exposure detections
scripts/telemetry_tail.sh | \
jq 'select(.type == "prompt_exposure_detected" and .blocked == true)
| {agent_id, terminal_tool, hit_count, sample_hits}'
Notes
- Field naming:
nulland "field absent" are equivalent on the wire (the catalog uses#[serde(skip_serializing_if = "Option::is_none")]). When filtering on optional fields, use// nulldefaults:select(.queue_wait_ms // null). - The
nosess-{agent}-{uuid}trace_idshape onnats_connection_stateevents flags the no-task-context case. Filter those out withselect(.job_id != null)if you only want task-scoped events.