Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

What the cost figures mean

← back to the README

Claude, Codex, and Gemini costs are estimates: tokens multiplied by published per-token rates, taken from built-in tables and falling back to the LiteLLM database (cached for 24 hours). OpenCode and Pi already persist provider-calculated costs, which cctop reads directly — except where the figure is $0.00 against tokens that were spent, which is what both write for a provider they have no rates for rather than a model that was genuinely free; those turns are estimated like the rest.

Gemini records a per-turn token breakdown but no cost. Its cached count is the part of the prompt served from context cache rather than an addition to it, so only the uncached remainder is priced at the full input rate; thinking tokens are priced as output, which is how Google bills them. A Gemini session on a bundled Code Assist tier will still show an estimate — the transcript carries nothing that says which tier it ran on, and the figure is honest about what the tokens would cost at retail.

Cursor native-agent transcripts expose projects, conversation activity, and tool calls. The model, the title, the real folder and the context occupancy come from Cursor’s own state.vscdb when cctop finds it. Tokens and cost are recorded nowhere — not in the transcript, not in the database — so they display as unavailable rather than as free, and there is no dedicated per-session process: live status is read off the transcript’s last turn and how recently it changed.

Windsurf goes further: its workspace state records the conversation and its tool calls but no model, tokens, or cost at all — the credit accounting lives on Codeium’s servers. Those sessions report cost as unavailable rather than as free, and their timestamps come from the workspace database’s mtime, which is the only clock Windsurf leaves behind.

Devin is the third harness with no figure of its own, and the only one that still fills every other column: its ATIF transcript records per-step token metrics and its database records which model ran them, so CTX%, TOOLS, TOKENS and ERR% are all real. Neither store holds a dollar amount, so a Devin row’s cost reads as unavailable rather than as an estimate — the price of its tokens is not something cctop can know, only guess, and a guess printed in the $ column would be indistinguishable from one. --plan max counts Devin as bundled, but that changes nothing on screen: incl stands for a figure cctop computed and then withheld, and a Devin row has no figure to withhold.

Mistral Vibe is estimated: its token totals at Mistral’s published API rates (docs.mistral.ai/inference/pricing), built into cctop because LiteLLM lists Mistral’s models only through resellers and under other names. A model that table does not carry falls back to LiteLLM, and to nothing after that. Vibe’s Python CLI wrote a session_cost of its own, but priced from whatever rates the user’s Vibe config carries, and its newer session store writes none, so cctop uses neither and prices both layouts the same way. Vibe records no time on any message, so a session’s cost counts toward “today” and the month on the day it was last active.

Subscription plans — Claude Max, Pro, Team — are flat-rate or bundle tokens differently, so these numbers will not match your invoice. Treat the $ column as a measure of resource consumption, not as billing. Use --plan max or --plan included to display bundled usage as incl instead.

Today’s model mix

The Overview’s Models row is today’s spend split by model: a short stacked bar, then each model’s name in its segment’s colour with its share of the day. Colours go by rank, not vendor, since the mix worth seeing is usually two Claude models against each other; past the fourth, models share one dim tail so the bar is always the whole of today. Like the Today figure, it counts every session rather than only the ones a filter leaves on the table. The names are placed first and the bar takes what they leave, up to sixteen cells; when that is fewer than eight the bar is left off and the row is the plain list of percentages.

Where each provider’s data comes from

SourcePath
Claude Code (CLI)~/.claude/projects/<slug>/<uuid>.jsonl
Claude for Mac~/Library/Application Support/Claude/{claude-code,local-agent-mode}-sessions/
Codex~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl
Cursor~/.cursor/projects/*/agent-transcripts/*/*.jsonl
Gemini CLI~/.gemini/tmp/<project>/chats/session-*.json{,l}
Devin~/.local/share/devin/cli/sessions.db (platform data directory), with transcripts/<id>.json beside it
OpenCode~/.local/share/opencode/opencode*.db (platform data directory)
Pi~/.pi/agent/sessions/**/*.jsonl
Mistral Vibe~/.vibe/logs/session/{session_*,unified/*}/meta.json
Windsurf<Windsurf User dir>/workspaceStorage/*/state.vscdb

CLAUDE_CONFIG_DIR, CODEX_HOME, CURSOR_HOME, GEMINI_DIR, OPENCODE_DATA_DIR, PI_CODING_AGENT_DIR, PI_CODING_AGENT_SESSION_DIR, VIBE_HOME and WINDSURF_USER_DIR are honoured, along with OPENCODE_CONFIG_DIR for the plugin --install-hooks writes. CHISEL_SESSION_DB moves Devin’s, and is the only one that names a file rather than a directory: cctop takes the parent of the database it points at, because the transcript has to sit beside it. Caches live in ~/.cache/cctop/.

Gemini and Windsurf sessions are read from disk but not matched to a running process: neither takes a session id on its command line, so there is nothing to tie a PID to a transcript. Their rows always read as stopped, and the CPU and memory columns stay blank rather than showing another session’s figures.

The left status dot is green while an agent is working, amber after its latest response is waiting for your input, and red when the newest transcript event is an API error. A hollow grey dot is a stopped session, and a filled ◉ is the session that rang in the last 30 seconds.