Warehouse records are missing sessionId and isSidechain (subagent) from the source JSONL
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
sessionIdto group records. - Subagent/sidechain-heavy detection (the kind of insight the Claude Code
/statuspanel itself surfaces — "99% of usage came from subagent-heavy sessions") — needsisSidechain.
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
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:
{"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