Dashcam
Integrations

Generic JSONL

Basic event capture for any Claude Code wrapper.

Generic JSONL Integration

Not every tool supports hooks. Some Claude Code wrappers, alternative AI CLIs, or custom orchestration scripts produce session data but do not provide lifecycle hook points. For these tools, Dashcam includes a generic JSONL file watcher that monitors Claude Code's project directory for new session data and ingests it automatically.

If you can get your tool to write JSONL files to ~/.claude/projects/, Dashcam will pick them up.

How the JSONL Watcher Works

The watcher uses fs.watch() to monitor ~/.claude/projects/*/ for changes to .jsonl files. When a file changes — whether a new line is appended or a new file appears — the watcher reads the new content and parses it into events.

~/.claude/projects/
  ├── my-project-abc123/
  │   ├── session-001.jsonl    ← watcher detects changes
  │   └── session-002.jsonl
  ├── another-project-def456/
  │   └── session-003.jsonl

The watcher is always active. It starts with the daemon and requires no special flags or configuration.

Incremental Parsing

The JSONL watcher does not re-read entire files on every change. It tracks the byte offset for each watched file path. When a change notification fires:

  1. The watcher reads from the last known offset to the end of the file
  2. Each new line is parsed as a JSON object
  3. Events are normalized and inserted into SQLite
  4. The offset is updated

This means Dashcam can efficiently tail multi-megabyte JSONL files without re-parsing content it has already ingested. File offset state is held in memory and reset on daemon restart (at which point the watcher scans from the beginning, deduplicating against existing events by ID).

File:    [████████████████████░░░░░░░░]
                              ▲
                         last offset
                              │
         New content: ────────┘░░░░░░░░
                              ▲
                         parse only this

Extracted Events

From each JSONL line, the watcher extracts:

FieldDescription
event_typeuser_message, assistant_message, tool_use, tool_result, thinking
timestampISO 8601 timestamp from the JSONL entry
session_idDerived from the file path or embedded metadata
dataThe full JSON payload for deep inspection
summaryAuto-generated one-line summary
tool_nameFor tool events: Write, Edit, Bash, etc.
file_pathPrimary file affected (when applicable)
tokens_in / tokens_outToken counts (when present)

Events flow through the same normalization pipeline as hook-sourced events — they appear identically on the timeline, trigger screenshot evaluation, and are searchable via full-text search.

Debouncing

File system watch events fire frequently — sometimes multiple times for a single write operation. The watcher debounces notifications with a 100ms window: after the first change notification for a file, it waits 100ms before reading, batching any additional notifications that arrive during that window.

Compatible Tools

The JSONL watcher works with any tool that writes Claude Code-format JSONL files:

  • Codex CLI — OpenAI's CLI writes session data to similar paths
  • Gemini CLI — Google's CLI can be configured to output JSONL
  • Custom wrappers — Any script that wraps Claude Code and writes to ~/.claude/projects/
  • Claude Code itself — The watcher supplements hook-based capture by also ingesting the full JSONL conversation log

The JSONL watcher provides basic event capture — timeline events, chat reconstruction, and tool use tracking. For live streaming, screenshot triggers, and window management, use the Claude Code hooks integration instead.

Importing Historical Sessions

The JSONL watcher handles live tailing, but you may also have historical JSONL files from past sessions. Use the dashcam import command to ingest them:

Terminal
dashcam import                      # Import all historical sessions
dashcam import --since 2026-03-01   # Import sessions since a specific date

The import command scans ~/.claude/projects/ for existing JSONL files, parses them from the beginning, and inserts all events into SQLite. Duplicate events (by ID) are skipped, so running import multiple times is safe.

On this page