Session Analytics and Statistics#
Decant's analytics layer queries the local SQLite archive and is governed by three core rules: inclusive UTC date filtering, root-session-only session counts with inclusive subagent metric aggregation, and recursive subagent cost summation in per-session summaries. The authoritative implementation is split across src/date-filter.ts, src/stats.ts, src/query.ts, and src/ui/session-summary.ts. The methodology is documented in docs/analytics-methodology.md and practical query patterns are in docs/api/recipes.md.
Date Filtering#
Date ranges are applied by sessionDatePredicate in src/date-filter.ts. Both from and to are inclusive — a session belongs to the window when the date prefix of its started_at ISO timestamp falls within [from, to] . Filtering uses a substr(started_at, 1, 10) >= ? / <= ? comparison, so the timezone of started_at (UTC) is what matters — not the caller's local time .
Inputs that don't match YYYY-MM-DD or that represent an invalid calendar date are silently discarded by isoDate(). Callers that need a strict contract should validate dates before sending them .
Practical note: Exclude the current UTC date when you want only complete days, since an in-progress day is still open .
The same predicate is reused by listSessions, searchPage, listToolCalls, fileHotspots, mcpUsage, and every other query that accepts from/to — so date semantics are uniform across the API .
Session Counts vs. Metric Aggregation#
The sessions field in aggregate statistics counts only top-level (non-subagent) sessions — those where is_subagent = 0 . Message, tool-call, token, and estimated-cost totals include all visible sessions (root + subagent) in the filtered scope .
The same split applies to dimension breakdowns: the byDimension function sums CASE WHEN s.is_subagent = 0 THEN 1 ELSE 0 END for session counts, while token/cost columns sum across every row in the filtered set .
Why this matters: A single top-level session can spawn many separately metered subagent runs. Counting only roots keeps the session count comparable across different parallelism strategies, while including subagents in cost/token totals gives a complete picture of spend .
The GET /api/sessions list endpoint mirrors this by omitting subagents as top-level rows by default; include_subagents=true includes them as list entries, and with_subagents=true attaches nested summaries .
Warning on double-counting: Do not add a parent session's estimated_cost_usd to archive-wide totals: aggregate statistics already include every visible run .
Subagent Cost Summation#
Each session row carries two subagent cost fields:
| Field | Meaning |
|---|---|
subagent_count | Number of direct child subagent sessions |
subagent_estimated_cost_usd | Cost of direct children only |
These are computed by a LEFT JOIN aggregation in sessionSummarySelect, which groups session rows where is_subagent = 1 and parent_session_id IS NOT NULL .
For nested subagent trees, the UI computes the full recursive cost via sessionThreadCost in src/ui/session-summary.ts:
- If the session has loaded
subagents(i.e.,with_subagents=truewas requested), the function recurses into them. - Otherwise, it falls back to
session.estimated_cost_usd + subagent_estimated_cost_usd(direct children only) .
This means the cost shown in summary cards is a thread total (session + all visible descendants), while the raw estimated_cost_usd on each row is the session's own spend only .
Nested summaries are capped at five levels deep — see buildSubagentDetails and the recursive CTE in getSession . For a complete deeper tree, request subagents as rows and join by parent_session_id .
Key Files#
| File | Role |
|---|---|
src/date-filter.ts | sessionDatePredicate — inclusive UTC date SQL fragments |
src/stats.ts | totals, byDimension, toolUsage, mcpUsage — aggregate statistics with root/subagent split |
src/query.ts | listSessions, sessionSummarySelect — per-session summaries and subagent rollups |
src/ui/session-summary.ts | sessionThreadCost, sessionCardMetrics — recursive UI-side cost summation |
docs/analytics-methodology.md | Canonical definitions for all metric semantics |
docs/api/recipes.md | Reproducible curl query patterns with date windows |