JSONL observability gaps: session status, permission state, and lifecycle records

Resolved 💬 5 comments Opened Mar 30, 2026 by murraystubbs Closed May 9, 2026

Summary

External tools that monitor Claude Code sessions by tailing JSONL transcript files must rely on complex heuristics to infer basic session state. Adding a few explicit record types would make JSONL a reliable observability surface for IDE extensions, dashboards, and multi-agent monitors.

Context

We build Serac (source), a VS Code extension that monitors Claude Code sessions. It shows live status cards, subagent tracking, usage quotas, and transcript viewing in the sidebar.

To provide this, Serac currently maintains 62 distinct heuristics and workarounds including a 13-state inference machine, 30+ hardcoded timeouts, timer-based permission detection with tool-profile exemptions, fuser PID liveness checks, and confidence degradation curves — all to answer three basic questions: is this session running, waiting, or done?

The gaps (in priority order)

1. No session status record

There is no explicit record in the JSONL indicating session state. Serac infers running vs waiting vs done from activity recency, pending tool_use blocks, output timing, and stale demotion timeouts (3s, 5s, 6s, 30s, 3min, 10min thresholds depending on context).

Suggested record:

{"type": "status", "status": "running" | "waiting_for_input" | "idle" | "done", "timestamp": "..."}

Emitted on state transitions. Would eliminate the core inference state machine.

2. No permission state record

When Claude invokes a tool that requires user approval, there is no record of the permission prompt being shown or resolved. Serac guesses by: starting a 3s timer after tool_use (6s for slow tools like Bash, MCP, WebSearch), doubling the delay if a tool_result arrived recently, and exempting read-only tools.

Suggested records:

{"type": "permission_request", "tool": "Edit", "tool_use_id": "...", "timestamp": "..."}
{"type": "permission_response", "tool_use_id": "...", "action": "approved" | "denied", "timestamp": "..."}

Would make permission detection exact instead of probabilistic.

3. No session lifecycle records

No explicit "session started" or "session ended" signals. Serac infers session end from: 3-minute silence ceiling (covers laptop sleep, quota hits, VS Code quit), 10-minute ceiling for permission waits, fuser PID checks to detect crashed processes, and a 30s extended-thinking grace period with process liveness fallback.

Suggested records:

{"type": "session_start", "sessionId": "...", "timestamp": "..."}
{"type": "session_end", "reason": "completed" | "crashed" | "interrupted" | "quota_exceeded", "timestamp": "..."}

Would eliminate stale detection, hard ceilings, and PID checking entirely.

4. No consolidated token usage

Token counts are scattered across individual assistant records as input_tokens, cache_creation_input_tokens, and cache_read_input_tokens. Serac sums these manually. A periodic or end-of-session summary would simplify quota-aware tooling.

What this enables

These records wouldn't just help Serac — they'd make JSONL a general-purpose observability surface for any tool that reads Claude Code transcripts: CI integrations, cost dashboards, multi-agent orchestrators, and IDE extensions beyond VS Code.

The records are append-only, backward-compatible (new record types don't break existing parsers), and low-volume (status transitions, not per-token).

Environment

  • Claude Code v2.1.87
  • macOS (darwin arm64)
  • Serac v1.1.0

View original on GitHub ↗

This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗