CLI tool that generates usage heatmaps for Amp, Claude Code, Codex, Crush, Cursor, Gemini CLI, Google Antigravity, Open Code, and Pi Coding Agent for the rolling past year (ending today).
packages/
cli/
registry/
tooling/
typescript-config/
bun install
bun run check# Build once
bun run build
# Run from built output
node packages/cli/dist/cli.js
# Run the CLI package directly in dev mode
bun run --cwd packages/cli dev
# Or if installed as a package binary
slopmeter# Output file (default: `./heatmap-last-year.png`; explicit provider flags add suffixes like `./heatmap-last-year_cursor.png`, and `--all` uses `./heatmap-last-year_all.png`)
slopmeter --output ./out/heatmap.svg
slopmeter -o ./out/heatmap.svg
# Output format
slopmeter --format png
slopmeter --format svg
slopmeter --format json
slopmeter -f svg
# Dark theme
slopmeter --dark
slopmeter --dark --format svg
# Merge all providers into one graph
slopmeter --all
# Provider filters (optional)
slopmeter --amp
slopmeter --antigravity
slopmeter --claude
slopmeter --codex
slopmeter --cursor
slopmeter --gemini
slopmeter --opencode
slopmeter --crush
slopmeter --pi- Monday-first contribution-style heatmap for the last year.
- Top metrics per provider:
LAST 30 DAYSINPUT TOKENSOUTPUT TOKENSTOTAL TOKENS(includes cache tokens)
- Bottom metrics per provider:
MOST USED MODEL(with total tokens)RECENT USE (LAST 30 DAYS)(with total tokens)LONGEST STREAKCURRENT STREAK
Model names are normalized to remove a trailing date suffix like -20251101.
- Default format is PNG.
- If
--outputis omitted, the default filename is./heatmap-last-year.<ext>,./heatmap-last-year_<providers>.<ext>for explicit provider flags, or./heatmap-last-year_all.<ext>for--all. - If
--formatis omitted, format is inferred from--outputextension (.png,.svg, or.json). - If neither provides a format, PNG is used.
- Use
--format json(or an.jsonoutput filename) to export data for interactive rendering. - Export includes fixed
version: "2026-03-11". - Each provider includes:
titleandcolorsdailyrows withdate,input,output,cache,totaldaily[].breakdownper-model usage for that day, sorted bytokens.total(includesinputandoutput)insights(mostUsedModel,recentMostUsedModel) when available
- If no provider flags are passed, the CLI renders all providers with available data.
- If
--allis passed, the CLI renders one merged graph across all providers with consolidated totals, streaks, and model rankings. - Pi Coding Agent usage is derived from assistant messages in Pi session logs, grouped by the model that handled each turn.
- Google Antigravity usage is aggregated from local Antigravity request logs, synced
trajectorySummariesstate, browser recording metadata, annotation view timestamps, and Antigravity-managed conversation/implicit file mtimes. - Google Antigravity currently reports activity, streaks, and best-effort model counts. It does not expose real input/output token totals from local state, so activity-only graphs show
N/Afor token counters. - If provider flags are passed,
slopmeteronly loads those providers and only prints availability for those providers. - If no provider flags are passed, the CLI loads all providers and prints availability for all providers.
- If explicit provider flags are passed and any requested provider has no data, the command exits with an error.
- If no provider flags are passed and no provider has data, the command exits with an error.
SLOPMETER_FILE_PROCESS_CONCURRENCY: positive integer file-processing limit for Claude Code and Codex JSONL files. Default:16.SLOPMETER_MAX_JSONL_RECORD_BYTES: byte cap for Claude Code and Codex JSONL records, Gemini CLI session files, OpenCode JSON documents, and OpenCode SQLitemessage.datapayloads. Default:67108864(64 MB).ANTIGRAVITY_LOGS_DIR: overrides the Antigravity extension logs directory.ANTIGRAVITY_STATE_DB: overrides the Antigravitystate.vscdbpath used for synced trajectory summaries.ANTIGRAVITY_DATA_DIR: overrides the Antigravity local data dir used for browser recordings, annotations, conversations, and implicit state. Default:~/.gemini/antigravity.
- Claude Code and Codex now share the same bounded JSONL record splitter and do not materialize whole files in memory.
- Oversized Claude Code JSONL records fail the affected file with a clear error that names the file, line number, byte cap, and
SLOPMETER_MAX_JSONL_RECORD_BYTES. - OpenCode legacy JSON message files use a bounded JSON document reader before
JSON.parse. - OpenCode SQLite
message.datapayloads use the same byte cap beforeJSON.parse. - Oversized OpenCode JSON documents and SQLite message payloads fail clearly with the source path or row label, byte cap, and
SLOPMETER_MAX_JSONL_RECORD_BYTES. - Codex now streams JSONL records and only parses records that affect usage aggregation.
- Oversized irrelevant Codex records are skipped and summarized with a warning after processing.
- Oversized relevant Codex records fail the affected file with a clear error that names the file, line number, byte cap, and
SLOPMETER_MAX_JSONL_RECORD_BYTES. - Pi Coding Agent session logs are streamed and only assistant messages are parsed for usage aggregation.
- Claude Code:
$CLAUDE_CONFIG_DIR/*/projects(comma-separated dirs) or defaults~/.config/claude/projectsand~/.claude/projects - Codex:
$CODEX_HOME/sessionsor~/.codex/sessions - Cursor: reads
cursorAuth/accessTokenandcursorAuth/refreshTokenfrom$CURSOR_STATE_DB_PATH,$CURSOR_CONFIG_DIR/User/globalStorage/state.vscdb,~/Library/Application Support/Cursor/User/globalStorage/state.vscdb(macOS),%APPDATA%/Cursor/User/globalStorage/state.vscdb(Windows), or~/.config/Cursor/User/globalStorage/state.vscdb(Linux), then loads usage from Cursor's CSV export endpoint - Amp:
$AMP_DATA_DIRor$XDG_DATA_HOME/ampor~/.local/share/amp - Gemini CLI:
$GEMINI_CONFIG_DIR/tmp/**/chats/session-*.jsonor~/.gemini/tmp/**/chats/session-*.json - Open Code: prefers
$OPENCODE_DATA_DIR/opencode.dbor~/.local/share/opencode/opencode.db, and falls back to$OPENCODE_DATA_DIR/storage/messageor~/.local/share/opencode/storage/message - Crush: reads
crush.dbfrom the current workspace./.crush,~/.crush, tracked Crush project data dirs listed in globalprojects.json, the global data dir itself, and project-local.crush/crush.dbfiles discovered underHOMEwhen Crush has not tracked them yet. The global metadata dir is discovered from$CRUSH_GLOBAL_DATA,$XDG_DATA_HOME/crush,%LOCALAPPDATA%\\crush, or~/.local/share/crush - Pi Coding Agent:
$PI_CODING_AGENT_DIR/sessionsor~/.pi/agent/sessions - Google Antigravity logs:
$ANTIGRAVITY_LOGS_DIRor~/Library/Application Support/Antigravity/logs(macOS),%APPDATA%\\Antigravity\\logs(Windows), or$XDG_CONFIG_HOME/Antigravity/logs/~/.config/Antigravity/logs(Linux) - Google Antigravity synced state:
$ANTIGRAVITY_STATE_DBor~/Library/Application Support/Antigravity/User/globalStorage/state.vscdb(macOS),%APPDATA%\\Antigravity\\User\\globalStorage\\state.vscdb(Windows), or$XDG_CONFIG_HOME/Antigravity/User/globalStorage/state.vscdb/~/.config/Antigravity/User/globalStorage/state.vscdb(Linux) - Google Antigravity local data:
$ANTIGRAVITY_DATA_DIRor~/.gemini/antigravity