## Context

BooCode already accumulates token/cost data across multiple backend paths:

- **opencode warm server**: `stepEndedToUsage()` normalizes per-step events → `agent_sessions.input_tokens/output_tokens/cost` (opencode-server.ts, opencode-usage.ts)
- **claude-sdk backend**: accumulates per-turn `input_tokens/output_tokens/cost` on `agent_sessions` (claude-sdk.ts)
- **Native inference**: `UsageFrame` WS frame carries `completion_tokens/ctx_used/ctx_max`; tasks persist `token_breakdown` JSONB (`{system,user,assistant,tools,reasoning,total}`) at terminal state
- **Tool cost stats**: `tool_cost_stats` DB view provides per-tool 100-call rolling window (`/api/tools/cost_stats`)
- **Arena contestants**: `token_breakdown` JSONB + `tokens_per_sec` + `cost_tokens` on contestant rows

The gap: no dedicated page to view any of this data in aggregate.

## Goals / Non-Goals

**Goals:**
- Add a nav button above Settings in the sidebar linking to `/analytics`
- Create a Token Analytics page at `/analytics` that displays:
  - Aggregate usage summary cards (total tokens, cost, sessions)
  - Per-session token/cost table (from `agent_sessions`)
  - Per-tool cost breakdown (from `tool_cost_stats`)
  - Per-category breakdown where `token_breakdown` exists
  - Loading/error/empty states
- Reuse existing API endpoints where possible; add one new aggregate endpoint if needed

**Non-Goals:**
- Real-time streaming updates (page-level refresh on mount is fine)
- Export/download of analytics data
- Per-user or per-project filtering in v1 (global view only)
- Historical time-series charts (summary cards + tables are sufficient for v1)
- Arena token analytics (deferred — data exists but integration adds scope)

## Decisions

### D1 — New page route vs pane in existing workspace

**Decision:** New standalone page at `/analytics` (not a workspace pane).

**Rationale:** Token analytics is a global overview, not scoped to a specific chat/session. A workspace pane would only be accessible when a session is active. A standalone route works from anywhere. The Settings page already uses this pattern (`/settings`).

### D2 — API strategy

**Decision:** Reuse existing endpoints; add one new aggregate endpoint.

**Existing endpoints to use:**
- `GET /api/tools/cost_stats` — per-tool token stats
- `GET /api/coder/sessions/:id/agent-sessions` — per-session token data (fetched per session)

**Potential new endpoint (TBD during implementation):**
- `GET /api/coder/analytics/summary` — aggregate across all sessions (total input/output tokens, total cost, session count). If this adds too much backend scope, the frontend can aggregate from the existing session list endpoint instead.

### D3 — Styling

**Decision:** Match existing page patterns (`Settings` page layout: max-w container, card components, muted headers, shadcn table).

**Rationale:** Consistency. Every page in the app follows the same visual language (Tailwind v4 + shadcn nova). No new styling patterns needed.

### D4 — Visual token category breakdown

**Decision:** Simple CSS-only stacked bar for the `token_breakdown` category visualization (no chart library dependency).

**Rationale:** A stacked horizontal bar (system + user + assistant + tools + reasoning = total) can be done with CSS divs and `w-%` classes. Avoids adding a charting dependency for v1.

## Risks / Trade-offs

| Risk | Mitigation |
|------|------------|
| `agent_sessions` data is per-(chat,agent) — may be sparse if user doesn't use opencode/claude-sdk backends | Graceful: section shows empty state with explanation |
| Data freshness: the page fetches on mount, not on WebSocket push | Acceptable for v1 (analytics is a "check on things" page, not a dashboard) |
| Token count accuracy differs by backend (opencode reports model counts, analyzer estimates at chars/4) | Document the estimation methodology on the page |
| New page adds bundle size | Negligible — reuses existing shadcn components and API types |
