{"id":"session-usage","repo":"panrafal/paseo-plugins","url":"https://github.com/panrafal/paseo-plugins/tree/main/session-usage","name":"session-usage","description":"Agent session usage from local Claude, Codex, OpenCode, Kilo, Devin CLI and Cursor records: sortable stats, provider charts, cost estimates, and CSV export.","categories":["monitoring","productivity"],"platforms":[],"caveats":["Reads local Claude and Codex transcripts; does not contact provider billing APIs"],"images":["https://raw.githubusercontent.com/panrafal/paseo-plugins/004c6a80c6aa8e76bb563694c3eee5c2c0b0466f/session-usage/images/allowances.png","https://raw.githubusercontent.com/panrafal/paseo-plugins/004c6a80c6aa8e76bb563694c3eee5c2c0b0466f/session-usage/images/session-usage.png"],"themes":[],"health":{"manifestValid":true,"hasReadme":true,"hasLicense":true,"hasTests":true,"hasTypecheckScript":true,"updatedRecently":true},"scannedAt":"2026-10-15T12:34:28.073Z","addedAt":"2026-09-10T11:29:03+03:00","path":"session-usage","version":"0.1.0","security":{"status":"failed","blockingFindings":1,"advisoryFindings":0,"scannedAt":"2026-10-15T12:14:24.405Z","commit":"004c6a80c6aa8e76bb563694c3eee5c2c0b0466f"},"author":"panrafal","license":"MIT","paseoVersionRequirement":">=0.7.2-0","descriptionNodes":[{"type":"text","text":"Agent session usage from local Claude, Codex, OpenCode, Kilo, Devin CLI and Cursor records: sortable stats, provider charts, cost estimates, and CSV export."}],"caveatNodes":[[{"type":"text","text":"Reads local Claude and Codex transcripts; does not contact provider billing APIs"}]],"manifest":{"id":"session-usage","requirements":{"paseo":">=0.7.2-0"}},"repoMeta":{"stars":6,"defaultBranch":"main","pushedAt":"2026-10-15T04:33:35Z"},"owner":{"login":"panrafal","avatarUrl":"https://avatars.githubusercontent.com/u/1268900?v=4"},"installNotesHtml":"<pre><code class=\"language-bash\">paseo plugin add panrafal/paseo-plugins:session-usage\n</code></pre>\n<p>From a checkout on the daemon host (Node 22.13+ for the test runner and <code>node:sqlite</code>):</p>\n<pre><code class=\"language-bash\">npm install\nnpm run typecheck\npaseo plugin install /absolute/path/to/paseo-plugins/session-usage\npaseo plugin ls\n</code></pre>\n<p>After editing, typecheck and run <code>paseo plugin reload session-usage</code>. Use <code>--host &#x3C;target></code> for\nanother daemon.</p>","limitationsNotesHtml":"<ul>\n<li>Measures Claude, Codex, OpenCode, Kilo, and Devin CLI from local records. Cursor sessions include\nmessages, tool calls, and models but no token usage. Other providers appear only through Paseo's\nagent records, with unknown usage.</li>\n<li>Cost figures are a standard short-context API equivalent from a fixed price table, not a bill\nor subscription meter. The plugin contacts no pricing or provider account API.</li>\n<li>Allowance percentages and reset times are whatever Paseo reports; window lengths are inferred,\nand the pace projection assumes usage continues at the average rate so far.</li>\n<li>Message text, tool arguments, tool results, and credentials never leave the daemon parser.</li>\n<li>An em dash means a measurement is absent; averages divide by known sessions only.</li>\n</ul>","readmeText":"# session-usage\n\nAdds **Session usage** to Paseo's sidebar and Command Center. It reads Claude Code and Codex\ntranscripts and the OpenCode, Kilo, Devin CLI, and Cursor session stores on the selected daemon, including\narchived sessions, subagents, and sessions started outside Paseo, then joins them with Paseo's\nproject, workspace, and agent records. Agents of other providers are listed from Paseo's records\nwith unknown usage. Subscription allowance cards show how much of each provider's limits is used,\nwhere the tokens went, and how long the allowance lasts at the current pace.\n\n![Session usage](./images/session-usage.png)\n\n## Using the surface\n\n- The **sortable table** is grouped by workspace by default; choose **Sessions** under **Table\n  grouping** for one row per provider session. Choose **Columns** to show any\n  measurement, press a heading to sort in either direction, and press a session name for all\n  measurements, its tool-call breakdown, and a link to its agent or workspace. Missing values\n  sort last in both directions. The session column stays fixed while the other columns scroll\n  horizontally, on desktop and mobile. The table pages through 40 rows at a time.\n- **Table grouping** independently switches between Sessions, provider, project, workspace,\n  label, model, effort, day, week, and month. It preserves the selected metric columns and does\n  not change Compare providers or the calendar. Group rows show metric totals, weighted\n  percentages, session counts, and coverage for partially known measurements. Click a group\n  for all metrics and its member sessions; session details show that member's activity in the group.\n  Sessions with multiple labels appear once in each label group, so label totals can overlap.\n  Unlabeled sessions get their own group. Date/model/effort groups split recorded activity;\n  session span and transcript size remain unknown there because they cannot be divided across\n  those groups. Other groupings sum those lifetime values once per member within each group.\n  Numeric cell backgrounds scale independently per metric across all filtered table rows,\n  including other pages. Zero and unknown values have no tint.\n- **Effort**, beside Models, shows the recorded levels for the selected activity (for example,\n  `low` or `xhigh`). A session that changed effort lists each level; sorting uses its highest\n  recorded level. Details and CSV include effort too. An em dash means effort was not recorded;\n  provider defaults and current agent settings are not inferred for historical usage.\n- **Subscription allowances**, at the top of the page, has a card for each provider that Paseo\n  reports allowance limits for and that has sessions on this host. The cards stay on one line and\n  scroll horizontally when they do not fit. Each limit (for example Claude's\n  session, weekly, and weekly Fable limits) is a narrow column with:\n  - a 50 px token chart for the current window, by UTC hour for windows up to a day and by UTC\n    day otherwise. Input tokens (including cache reads and writes) rise above the baseline in\n    blue and output tokens hang below it in orange. Each half is scaled to its own maximum.\n    Future slots are dimmed. A slot's total can include activity from shortly before the window\n    opened.\n  - Paseo's used percentage and reset time, with a mark for the share of the window that has\n    already passed. Usage to the right of the mark is ahead of time.\n  - a two-line pace projection with the values in bold: \"Lasts **4h 8m**\" over \"**17%** at\n    reset\", or, in yellow, \"Runs out in **3d 6h**\" over \"**15h** before reset\". A used-up\n    allowance says \"Used up\" in red. The projection extrapolates the used percentage over the\n    elapsed time; token counts are not used, because how they map to a provider's allowance is\n    unknown.\n\n  Choosing a bar focuses the whole report on that hour or day and on the provider; for a\n  model-scoped limit such as Fable, it also selects that limit's models. Choosing it again clears\n  the period. The cards always cover every session on the host and ignore the report filters.\n\n  Paseo reports reset times but not window lengths, so the length is inferred:\n  - from the limit's name: session and five-hour windows are 5 h, daily 24 h, weekly 7 days, and\n    monthly one calendar month;\n  - otherwise, or when the time left exceeds the named length, from the shortest of 5 h, 24 h,\n    7 days, or one month that covers the time left. A Codex \"Session\" limit that resets in two\n    days is treated as weekly.\n\n  Limits that local records cannot be attributed to (surface-scoped limits, code review, Cursor's\n  model pools) and providers without local token records show a short note instead of a chart.\n  Allowances refresh every five minutes and with **Refresh**. Provider balances are not shown.\n\n![Subscription allowances](./images/allowances.png)\n\n- **Compare providers** shows a bar for each provider in the filtered sessions, all on the same\n  zero-based scale. A provider keeps its color while filters change. Choose a\n  metric, total or average per known session, and group by provider, day, week, month, project,\n  or model. Weeks start on Monday. Large charts initially show 14 groups; **Show more** reveals\n  the rest. Time charts initially show the latest groups.\n- **Daily activity**, below the bars, shows a GitHub-style calendar for the last 12 months on\n  desktop or one month on compact/narrow screens. Previous/next controls browse older periods.\n  It uses the bars' selected metric and total/average setting, combining the selected providers.\n  Each day's color is normalized against the highest value across the visible calendar.\n  Selecting a day filters the summary cards, bars, table, details and CSV to that UTC day; selecting the\n  same day again clears the date filter. The calendar\n  ignores date filters so its days and color scale stay visible; all other filters still apply.\n  **Clear date filter** restores the report's full date range. Empty days remain selectable;\n  future days are disabled. Hover or focus a day to see its value and measurement coverage.\n  Dashed cells mark unknown measurements. Lifetime session span and file size leave the calendar\n  uncolored because those measurements cannot be attributed to individual days.\n- Filters include provider, project, workspace, label, model, active/archived state, source\n  (Paseo linked/outside Paseo), main/subagent, data availability, and UTC calendar dates.\n  Custom dates also accept UTC hours as `YYYY-MM-DD HH:00`; allowance charts set these. The model\n  filter opens automatically when a chart sets it.\n  Search matches session metadata, titles, directories, branches, labels, models, and effort.\n  The provider filter lists only providers with sessions on this host, using the labels from\n  Paseo's provider settings.\n  Filter, column, table grouping, and sort choices survive navigation per host until the app restarts.\n- **Export CSV** exports every filtered row in the current sort order, with all measurements\n  as raw numbers (durations in milliseconds, ratios from 0 to 1, USD, bytes). On native clients\n  it uses the platform share sheet. Spreadsheet formulas in text fields are neutralized.\n  When the table is grouped, the export contains grouped totals and per-metric known-session counts.\n- **Refresh** scans for new or changed files and asks Paseo for fresh allowances. The surface\n  also refreshes every 30 seconds and polls scan progress every two seconds. The sessions are\n  only transferred again when they have changed since the last response. A previous completed\n  snapshot stays visible during refresh, and a spinner with the scan progress appears beside the\n  title without moving the page; data from a different host is never used as a placeholder.\n\n## Measurements\n\n| Category | Measurements |\n| --- | --- |\n| Tokens | Total input, uncached input, cache reads, cache writes, Claude 1-hour cache writes, output, reported reasoning/thinking, total input + output, weighted cache hit percentage |\n| Calls and messages | Model responses, user messages, assistant messages, model tool calls, explicit tool errors, tool error percentage, named tool-call counts |\n| Executions | Codex completed command, MCP, file-change and search events, and their explicit failures, including operations inside an `exec` call |\n| Length and time | User/assistant/tool input/tool output character counts, first/last timestamps, lifetime session span, recorded completed/aborted turn time, transcript bytes, compactions |\n| Cost | Explicitly reported USD where present; standard short-context API token cost estimate for known models |\n\n**Token categories are normalized.** Claude's base input excludes cache reads/writes, so those\ncategories are added to produce total input. Codex's input already includes them, so they are\nsubtracted to obtain uncached input. OpenCode, Kilo, and Devin CLI record uncached input and cache\nreads/writes separately, like Claude; OpenCode and Kilo record reasoning outside output, so it is\nadded to output. Cache writes include the 1-hour subset. Reasoning is a subset\nof output and is never added a second time to total tokens. Character counts use Unicode code\npoints, exclude images, and are not estimates of token counts.\n\n**Dates filter activity, not session creation.** Activity is recorded per UTC hour, model, and\neffort. A session spanning several days contributes only the buckets selected. Date presets include today and the preceding 6, 29, or 89 UTC\ncalendar days. Unknown-date buckets appear only without date bounds; activity without a recorded\nhour is included by an hour filter only when the filter covers its whole day. Recorded turn duration is\nattributed to the completion day. Session span and transcript size always cover the entire file;\nthose two metrics can be charted only by provider or project. Model filters omit activity that\ncannot be attributed to the selected model, such as initial prompts before a model is recorded.\n\n**Unknown is different from zero.** An em dash means a measurement is absent. Cards and bars\nshow the number of sessions with that measurement. Aggregates are known subtotals, and averages\ndivide by known sessions. Cache/error percentages use the ratio of sums for sessions with both\nvalues. A partially readable session can contribute known values; its badge and details explain\nthe missing coverage. Token totals cannot recover deleted requests or unrecorded usage.\n\n## Cost estimates\n\nThe **Base API estimate** uses a fixed price table checked on **2026-09-23** against\n[OpenAI pricing](https://developers.openai.com/api/docs/pricing) and\n[Claude pricing](https://platform.claude.com/docs/en/about-claude/pricing).\nEach usage record is priced using its recorded model, including separate read/write rates and\nClaude's reported 1-hour cache-write rate. Without a recorded cache TTL, writes use the 5-minute\nrate. Supported families are listed explicitly in `shared/pricing.ts`; unknown/private models\n(including `codex-auto-review` and Kilo's `kilo-auto/*`) remain unpriced. Dated model IDs, router\nIDs such as `anthropic/claude-sonnet-4.5`, and Devin model names with an effort suffix use the\ncorresponding base model rate. Historical usage is valued at this price snapshot, not historical prices.\n\nThis is a **standard, short-context API equivalent**, not a bill or subscription allowance meter.\nIt excludes priority/fast processing, long-context and regional premiums, tool fees, negotiated\ndiscounts, tax, and plan charges. It does not infer what you paid for Claude Pro/Max or ChatGPT.\n**Reported cost** is separate. OpenCode and Kilo record a USD cost per message; Claude transcripts\nrarely contain the SDK's `result.total_cost_usd` events, and Codex, Devin CLI, and Cursor record none. The plugin contacts\nno pricing or provider account API. Subscription allowances come from Paseo, whose daemon queries\nthe provider accounts.\n\n## Data sources and accounting\n\n| Source | Location |\n| --- | --- |\n| Claude | `<config dir>/projects/**/*.jsonl`, including nested `subagents` files, for every Claude configuration directory (see below); default `$CLAUDE_CONFIG_DIR` or `~/.claude` |\n| Codex | `<home>/sessions/**/rollout-*.jsonl` and `<home>/archived_sessions/**/rollout-*.jsonl` for every Codex home (see below); default `$CODEX_HOME` or `~/.codex` |\n| OpenCode, Kilo | `$XDG_DATA_HOME/opencode/opencode.db` and `$XDG_DATA_HOME/kilo/kilo.db`, default `~/.local/share`; only the `session`, `message`, and `part` tables |\n| Devin CLI | `$XDG_DATA_HOME/devin/cli/sessions.db`, default `~/.local/share`; only the `sessions` and `message_nodes` tables |\n| Cursor | `$CURSOR_CONFIG_DIR/{acp-sessions/*,chats/*/*}/store.db`; without it, both `$XDG_CONFIG_HOME/cursor` (default `~/.config/cursor`) and `~/.cursor`; only the `meta` and `blobs` tables |\n| Paseo | `$PASEO_HOME/projects/{projects,workspaces}.json`, `$PASEO_HOME/agents/*/*.json`, and provider labels from `$PASEO_HOME/config.json`, default `~/.paseo` |\n| Allowances | Paseo's provider usage report (`paseo.providers.listUsage`), which the daemon caches for five minutes; only window names, percentages, reset times, and plan labels are kept |\n| Index | Written by this plugin: `$PASEO_HOME/plugin-data/session-usage/index.sqlite`, or `$PASEO_SESSION_USAGE_DB` |\n\n- **Provider profiles (several accounts).** Paseo providers that extend Claude or Codex and set\n  `CLAUDE_CONFIG_DIR` or `CODEX_HOME` in their `env` (for example `claude-work` and `claude-personal`)\n  each contribute their directory to the scan. Sessions found there are attributed to that provider\n  ID and label, so the Provider filter and charts separate the accounts. A profile that points at\n  the daemon's default directory claims it; only those two variables are read from a provider's\n  environment. Without profiles the daemon's own `CLAUDE_CONFIG_DIR` / `CODEX_HOME` defaults apply.\n- No transcript, registry, configuration, or provider state is changed. The only file written is\n  the plugin's own index. Only metadata, numeric\n  statistics, tool names and coverage notices are sent to the client. Message text, tool arguments,\n  tool results, and provider credentials never leave the parser. Session titles are metadata.\n- SQLite stores are opened read-only and closed after each read. Account and credential tables are\n  never queried, and JSON fields are reduced to numbers, tool names, and text lengths inside\n  SQLite. A store is reread when its database or WAL file changes. Sessions without messages are\n  skipped unless a Paseo agent owns them. Reading stores needs the daemon Node's built-in\n  `node:sqlite`; otherwise the scan shows a warning.\n- Store sessions join Paseo agents by session ID. A custom provider ID, such as a configured `kilo`\n  ACP provider, comes from the matching agent records; unlinked sessions in the same store use the\n  ID most linked sessions use, or the store's name.\n- OpenCode/Kilo: one model response per assistant message with usage. Turn time runs from each\n  user message to its last completed reply. Tool errors use the tool's `error` status, and\n  compaction parts count as compactions. Child sessions are subagents of their parent session;\n  archived state follows the store's archive time.\n- Devin CLI: compaction copies message nodes, so messages and tool calls count once per ID. Effort\n  comes from the generation model suffix (`gpt-6-astra-medium` is `gpt-6-astra` at `medium`).\n  Cache keepalive pings are not user messages. Tool errors use the recorded tool result status.\n  Turn time, reasoning, and compactions are unknown.\n- Cursor: one store per session. Only messages listed by the latest root blob count; older roots and\n  edited-away messages in the store are ignored. Cursor records no token usage or message times\n  locally, so tokens, cost, and turn time are unknown, sessions show partial coverage, and all\n  activity falls on the session's start day. Effort comes from the model name su"}