Claude Code usage analyzer. Parses your local ~/.claude/ data to show costs, cache efficiency, anomalies, and optimization tips — with --deep, cost-aware behavioral insights about how you actually work, and with --habits, whether a change you made to how you work actually held.
Zero runtime dependencies. Reads local files only, never modifies them, never phones home.
This repo is its own plugin marketplace. In Claude Code:
/plugin marketplace add Optibus/ccalyze
/plugin install ccalyze@ccalyze
That's it — the plugin ships a pre-built, dependency-free JS bundle, so there is no clone/npm/build step. You get:
- The
ccalyzeskill — ask Claude "analyze my usage", "why did I hit my limit?", "how's my cache hit rate?", or say "insights" for the deep behavioral report. /ccalyze:install-cli— optional: puts the bundledccalyzecommand on your PATH (a symlink into the plugin, no npm needed) so you can run it outside Claude Code too.
git clone https://github.com/Optibus/ccalyze.git
cd ccalyze
npm install
npm run build
npm linkTo also register the skill (so Claude Code answers "analyze my usage" without the plugin):
mkdir -p ~/.claude/skills
ln -sf "$(pwd)" ~/.claude/skills/ccalyzeccalyze # last 7 days
ccalyze today # today only
ccalyze 30d # last 30 days
ccalyze 2026-03-01 2026-03-15 # custom date range
ccalyze today --json # raw JSON output
ccalyze --deep # add the per-session behavioral index (see below)
ccalyze --habits # compare the last 7 complete days with the 7 before (see below)- Cost breakdown by model, project, and day — at model list price. On a subscription plan read the dollars as relative weight / quota burn, not money out of pocket.
- Session details with a name derived from your opening prompt, plus duration, prompt count, and transcript size
- Cache efficiency —
cacheReadRatio, the share of input-side tokens served from cache. The API is stateless, so every turn resends the whole conversation; a cache read costs a tenth of fresh input and, on a subscription, burns quota at that same discount. Two people doing identical work can burn very different amounts of plan on this one number. Healthy usage runs 90-99%. - Cold-start detection — times a session sat idle past the cache TTL and then rebuilt its whole context at the write rate, priced as the premium over what a warm cache would have cost. This is the turn that looks like a small question and is often the most expensive one of the day.
- Anomaly detection: sessions without
/compact, long-running sessions, concurrent Opus usage, cost spikes, poorly-cached expensive sessions, repeated cold rebuilds, and (with--deep) main-thread model churn in expensive sessions - Optimization tips based on detected patterns
--deep adds a top-level deep object to the JSON: a per-session, cost-sorted behavioral
index — transcript paths, the prompts you actually typed, a model-switch timeline, and both
all-inclusive and main-thread-only switch counts (main-thread switches discard the prompt
cache and pay to rebuild it, so they carry a real cost story).
That index is what powers the skill's insights-fusion report: Claude Code's native
/insights command produces a rich behavioral narrative but has zero cost precision;
ccalyze has exact costs but no behavioral read. With --deep, the skill fuses them into an
/insights-style report — what you work on · how you use Claude Code · friction · patterns ·
suggestions — where every claim is tied to a session and its real cost:
- "Your highest-friction sessions (lots of corrections) are also your priciest Opus burn — $X"
- "Your cache ratio is fine at 96%, but $Z of the week went on cold rebuilds — the cost isn't how you work, it's coming back to stale sessions"
Just ask Claude for "usage insights" (or run ccalyze --deep --json yourself). See
SKILL.md → "Deep analysis & insights fusion" for the full contract.
Everything above measures one window. --habits compares two — the last N complete days
against the N complete days before them — because totals cannot tell "more work" apart from "a
worse habit": both produce a bigger number and call for opposite responses.
ccalyze --habits # 7 days vs. the 7 before (default)
ccalyze 15d --habits # 15 vs. 15
ccalyze 30d --habits # 30 vs. 30The output is a findings document, not a usage summary: a headline naming which of the three
explanations the data supports (volume — the extra usage is workload, nothing to fix;
efficiency-regression — a habit; mixed), a scorecard with a mechanical verdict per measure,
levers sizing what is still on the table, and caveats that keep the figures honest.
The scorecard has two groups. Consumption rows ask what the work cost (the long-session premium, re-read per output token, cold starts, compaction, model mix, off-hours, …). Effectiveness rows ask how well it went — whether instructions landed the first time:
| Row | Reads | Better when |
|---|---|---|
| Agent turns per typed instruction | how much work one instruction sets off | higher |
| Consumption per typed instruction | what one instruction costs | lower |
| Instructions that correct the last turn | "no, …", "that's wrong", "revert" as the opening words | lower |
| Interrupts per 100 instructions | times you pressed Esc to stop Claude mid-turn | lower |
| Tool calls that errored | failed commands, missing files, denied permissions | lower |
| Usage-limit stops | times a usage limit halted the work | lower (0 is the target) |
Every effectiveness rate divides by the instructions a person actually typed — not by
prompts, most of which are tool results Claude Code files under the user role. A sub-5% move reads flat, not better — a scorecard that books noise as a win stops
being worth reading.
A row with a numeric target (0% auto-compacted, 90%+ cache-read, under 40% flagged, ...) also gets
goalMet, and the page shows GOOD in green when it is reached, whatever the trend was. Every
row carries an about text, shown in a collapsible under the measure, that says what it means in
day-to-day work.
Two things it deliberately refuses:
- A date range. The window length is settable; the endpoints are not. ccalyze picks them, ending yesterday — a window ending today pairs N−1 complete days plus however much of today has happened against a prior window of N complete ones, so the deltas would depend on the clock. And picking endpoints after seeing the numbers is how a comparison turns into an argument.
- A pair it cannot compare. ccalyze only sees transcripts still on disk, so a 30-day window asked for on 41 days of history comes back the right length and nearly empty; that once reported a +11,661% cost delta and called it an efficiency regression. Lopsided or sparse coverage exits non-zero and names a shorter length to retry with.
Comparison flags, for when the report leaves the machine — project labels are directory names and routinely carry a customer or personal name:
ccalyze --habits --redact-projects # every label becomes project-1, project-2, …
ccalyze --habits --alias acme-migration=customer-a
ccalyze --habits --unit "quota units" # what to call the cost figure
ccalyze --habits --top 5 # projects in the table
ccalyze --habits --weekend fri,sat # Sun-Thu work week (default is sat,sun)
ccalyze --habits --single-window # first-ever run: describes habits, cannot track themEvery --habits run writes one too — the same findings as a self-contained HTML file:
conclusion and recommendations first, then the scorecard, the effectiveness table, the charts, and
the reading notes.
The JSON still goes to stdout unchanged, and the page path is printed on stderr:
ccalyze --habits 7d # page in ~/.claude/ccalyze/habits-FROM_TO.html
ccalyze --habits 7d --html ~/usage-report.html # or a path you choose
ccalyze --habits 7d > findings.json # page on disk, JSON capturedThere is no way to turn the page off: it is the report. (--no-html was removed and is refused by
name.)
Nothing in the page is fetched from anywhere: no CDN, no font host, no analytics. Every number renders from the findings JSON embedded in the file itself, and the prose is generated from that same object — so a paragraph can never contradict the table beside it.
Ask the ccalyze skill in Claude Code ("why do I keep hitting my limit?") and you get a
shareable claude.ai link rather than a path: the skill publishes that page with the Artifact tool
and answers with the URL. Run the CLI bare in a terminal and you get the file, which is complete on
its own — a standalone Node binary cannot talk to claude.ai, so publishing is always the agent's
half of the job.
Check the project labels before sharing either form. They are directory names; --alias and
--redact-projects above apply to the page exactly as they do to the JSON.
Install terminal-visualizer for graphical charts in your terminal. ccalyze works without it (falls back to markdown tables).
ccalyze reads these files from ~/.claude/ (never modifies them):
history.jsonl— prompt history with timestamps and session IDsprojects/*/*.jsonl— session transcripts with per-message token usageprojects/*/subagents/*.jsonl— subagent transcripts
It stream-parses the JSONL files (handling 100MB+ transcripts), deduplicates streaming updates by requestId, computes costs using published model pricing, and outputs a compact JSON summary.
npm run verify # typecheck (src + tests) + tests — the full gate
npm run bundle-skill # rebuild the committed skill bundle in skills/ccalyze/The plugin ships the compiled bundle in skills/ccalyze/ (plugin installs are plain git
clones with no build step), so re-run bundle-skill and commit the result after changing
src/ or SKILL.md.