Warehouse records are missing sessionId and isSidechain (subagent) from the source JSONL

Author: nguyenminhthi90Created Jul 16, 2026Updated Jul 16, 2026

Warehouse records are missing sessionId and isSidechain (subagent) from the source JSONL

Version: claude-monitor 4.0.0 (installed via uv tool install claude-monitor)

Summary

UsageWarehouse._entry_to_record() (src/claude_monitor/data/warehouse.py) writes a fixed set of fields per record (model, project, tokens, cost, message_id, request_id, source, timestamp) but never captures sessionId or isSidechain from the original Claude Code JSONL entries — even though both fields are present on every JSONL line and would be cheap to carry through, since UsageEntry (core/models.py) doesn't hold them either, so the gap starts at the reader/mapper stage (reader.py::_map_to_usage_entry), not just in the warehouse writer.

Why this matters

I'm building a small downstream tool that ingests the warehouse file to track token usage per project/session across multiple machines. Two things I wanted to derive from warehouse data alone aren't possible without also re-reading the raw JSONL:

  • Session-level aggregation (how long was this session active, how many total tokens did it consume) — needs sessionId to group records.
  • Subagent/sidechain-heavy detection (the kind of insight the Claude Code /status panel itself surfaces — "99% of usage came from subagent-heavy sessions") — needs isSidechain.

Right now the warehouse is schema-versioned (WAREHOUSE_SCHEMA_VERSION = "1.0", WAREHOUSE_RECORD_VERSION = 1) and looks designed for exactly this kind of downstream analytics use ("DuckDB-style analytics can consume this file later without becoming a runtime dependency" per the module docstring) — so I'd guess this is an oversight rather than intentional, but wanted to check before assuming.

Repro

bash
claude-monitor --once --warehouse
python3 -c "
import json
doc = json.load(open('~/.claude-monitor/warehouse/usage.json'.replace('~', __import__('os').path.expanduser('~'))))
r = doc['records'][0]
print(list(r.keys()))
"
# -> ['record_version', 'timestamp', 'day', 'project', 'model', 'message_id', 'request_id',
#     'source', 'input_tokens', 'output_tokens', 'cache_creation_tokens', 'cache_read_tokens',
#     'total_tokens', 'cost_usd', 'key']
# no 'session_id', no 'is_subagent'

Compare to the source JSONL, which has both:

json
{"isSidechain": false, "message": {...}, "requestId": "...", "sessionId": "...", ...}

Suggested fix

Add session_id (from sessionId) and is_subagent (from isSidechain) to UsageEntry in core/models.py, populate them in reader.py::_map_to_usage_entry, and carry them through in warehouse.py::_entry_to_record. Bumping WAREHOUSE_RECORD_VERSION might be worth considering since it changes the record shape, though both are simple additive fields so old records without them would just be missing the keys (not broken).

Happy to send a PR if this is the direction you'd want — wanted to raise it first in case there's a reason these were deliberately left out (e.g. wanting the warehouse to stay account/session-anonymous by design).

Source: Maciek-roboblog/Claude-Code-Usage-Monitor