cc-cost / Guide

Using cc-cost.

Every command and flag, every setting, and how the numbers are worked out.

CLI reference

Commands

$ cc-cost                          # sync this machine, print a summary
$ cc-cost sync                     # sync, print nothing else

$ cc-cost daily                    # cost per day
$ cc-cost weekly                   # cost per week, weeks start on Monday
$ cc-cost monthly                  # cost per month
$ cc-cost daily --breakdown        # per-model rows under each period

$ cc-cost models                   # cost per model; fast mode shows as <model>-fast
$ cc-cost machines                 # cost per machine
$ cc-cost accounts                 # cost per Claude account
$ cc-cost projects                 # cost per git repository
$ cc-cost sessions                 # most expensive sessions (20 by default)
$ cc-cost agents                   # main thread vs each subagent type
$ cc-cost skills                   # calls Claude Code attributes to a skill
$ cc-cost mcp                      # calls Claude Code attributes to an MCP server

$ cc-cost insights                 # overview, cache, context size, attribution, models, busiest times, limits
$ cc-cost plan                     # per month: API equivalent, per-30-day rate, × each plan, limit hits; then per
                                 # account against its own plan, and all of them against the paid plans together
$ cc-cost blocks                   # 5-hour windows, the active one with time left; one timeline per account

$ cc-cost report                   # serve the data folder on localhost and open the dashboard; the server stops
                                 # by itself once the page is closed
$ cc-cost report --location        # print where the dashboard is, without serving it
$ cc-cost pricing                  # prices in use and their source
$ cc-cost pricing --refresh        # fetch the pricing page now

$ cc-cost setup                    # interactive first-time setup
$ cc-cost setup --yes              # no questions: the first synced folder found, the plans found in the logins
$ cc-cost setup --sync-dir <path>  # skip the folder question
$ cc-cost setup --no-schedule      # don't schedule the daily run
$ cc-cost setup --no-hook          # don't add the SessionEnd hook
$ cc-cost setup --remove           # remove the schedule and the hook (asks first in a terminal)

$ cc-cost status                   # settings, machines and their last update, schedule, hook, prices
$ cc-cost update                   # update to the latest version with the package manager that installed it
$ cc-cost config                   # settings menu in a terminal; prints them with --json or without one
$ cc-cost config --json            # current settings as JSON
$ cc-cost config set <key> <value> # change one; see configuration.md

Unknown commands exit 1 with a --help hint.

Filters

Every report accepts them; each takes a comma-separated list or can be repeated.

Flag Keeps
--since <YYYY-MM-DD> Days from this date
--until <YYYY-MM-DD> Days up to this date, inclusive
--last <n> The last n calendar days, today included
--machine <name> Machines whose name contains it
--account <name> Claude accounts whose name (given in setup, else the folder’s) contains it
--project <name> Projects whose name contains it
--model <name> Models whose id contains it: opus, fable-5-1, fast
--session <id> Sessions whose id starts with it
--agent <name> main, or a subagent type such as Explore
--skill <name> Calls attributed to these skills
--mcp <name> Calls attributed to these MCP servers

blocks works on hourly data, which has no project, session or attribution; those filters are ignored there with a note on stderr.

Output

Flag Effect
--json JSON on every command
--csv CSV for table commands (periods, dimensions, plan, blocks); raw numbers, no totals row
--limit <n> Rows in sessions, projects, blocks (default 20) and any other dimension
--lang <en\|tr> Language of the terminal output and the dashboard
--tz <zone> IANA time zone for day boundaries, e.g. Europe/Istanbul
--no-color Plain text; also off when output isn’t a terminal or NO_COLOR is set
--no-sync Report from the stored snapshots without scanning transcripts
--offline Don’t fetch prices or check for a new version; use the stored or bundled price table
--quiet Print nothing on success; for schedulers and hooks
--sync-dir <path> Data folder for this run, instead of the configured folder or the server
-h, --help / -v, --version  

Examples

$ cc-cost daily --last 14 --breakdown
$ cc-cost projects --machine macbook --since 2026-09-01
$ cc-cost sessions --project api --limit 5 --json
$ cc-cost monthly --csv > usage.csv
$ cc-cost insights --model fable
$ cc-cost plan --account work
$ cc-cost blocks --last 2

Configuration

Settings

cc-cost config opens a menu to change them in a terminal, and prints them with --json or without a terminal; cc-cost config set <key> <value> changes one. The file is %APPDATA%\cc-cost\config.json on Windows and $XDG_CONFIG_HOME/cc-cost/config.json (~/.config/cc-cost/config.json) elsewhere.

Key Default Meaning
syncDir <config dir>/data The folder shared between machines. With the default, only this machine is counted; with remote, the data is on the server instead
machine hostname Name this machine appears under
lang en Interface language: en or tr
timezone system zone IANA zone that decides where one day ends
plan max5x Plan for usage that belongs to no account (synced before accounts were told apart); each account has its own, below
anonymizeProjects false true stores a hash of each project name instead of the name
pricing   Price overrides of cc-cost 1.x; copied into pricing.json in the data folder on the next sync, see below
remote   user@host:path of a server that keeps the data, reached over SSH; see below
claudeDirs ~/.claude, ~/.config/claude Claude Code data folders to read, one per account; comma-separated with config set. Overrides CLAUDE_CONFIG_DIR
accounts   Name, plan and price per Claude account; set in setup or cc-cost config → Claude accounts
unassigned   The account this machine’s usage from before accounts were told apart belongs to

Command-line flags win over the file for a single run: --sync-dir, --lang, --tz.

The shared folder

Any folder a sync service keeps identical on your machines works: Dropbox, iCloud Drive, OneDrive, Google Drive, Syncthing, a network share. cc-cost only reads and writes files there; it never talks to the service. setup looks for Syncthing folders beta, Dropbox (including business folders), OneDrive, iCloud Drive and Google Drive, and proposes a cc-cost folder inside the first one found, or an existing cc-cost or claude-cost folder there. Syncthing comes first because it is never installed by default; to use another folder, pick Another folder… and type its path.

beta marks what rests on something not checked against the real thing yet: where Syncthing keeps its list of folders, where a second Claude Code folder keeps its login, and the Team prices. cc-cost shows the same yellow mark wherever these appear.

Each machine writes only its own files, machines/<machine>.json and machines/<machine>/<month>.json, so the sync service never sees two writers on one file. Two files are shared: dashboard.html, which a machine writes only when its cc-cost is newer than the one the page came from, and pricing.json, refreshed at most once a day by whichever machine syncs first. A “conflicted copy” of either can be deleted.

Machine names come from the hostname. If a hostname changes, new files appear and the old ones keep counting; delete machines/<old name>.json and machines/<old name>/ if that machine is gone, or set machine to keep the old name.

Your own server over SSH: Raspberry Pi, home server, VPS

To keep the data on a machine you own, set remote to a server you can reach with ssh. Nothing extra is installed anywhere: cc-cost runs the ssh and scp that come with macOS, Linux and Windows 10 and later, and the server needs only an SSH server and a POSIX shell (Raspberry Pi OS, any Linux, a NAS). cc-cost does not run on the server.

The server keeps the data and nothing stays on the machines but config.json. Every command pulls the server’s folder into a temporary folder, works there and pushes back the files it changed, so a report needs the server as much as a sync does: when it can’t be reached, the command stops with ssh’s message; only status and config go on without it. cc-cost report serves the pulled copy on localhost, in a process that stops once the page is closed, and opens it. To open the dashboard from a phone or another computer, serve the folder with any web server on the server (python3 -m http.server in it, nginx, …): the page reads the files next to it.

  1. Key login. The daily schedule and the Claude Code hook cannot type a password, so log in with a key that has no passphrase, or one held by an agent that is running when the schedule fires.

    $ ssh-keygen -t ed25519                  # skip if you already have ~/.ssh/id_ed25519
    $ ssh-copy-id pi@raspberrypi.local

    Windows has no ssh-copy-id; in PowerShell: type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh pi@raspberrypi.local "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

  2. Point cc-cost at it on every machine, with the same path:

    $ cc-cost config set remote pi@raspberrypi.local:cc-cost

    The address takes one of two forms:

    Form Example Port
    scp’s user@host:path pi@raspberrypi.local:cc-cost 22
    a URL, ssh:// or scp:// ssh://pi@raspberrypi.local:2222/cc-cost the one given, else 22

    The path is relative to the home folder on the server (~/ is allowed); in a URL, a second / after the port starts an absolute one: ssh://pi@host:2222//srv/cc-cost. The folder is created on first use, and its name must not contain spaces. In the scp form only the first : separates the server from the path, so pi@host:2222:cc-cost is refused rather than read as a folder named 2222:cc-cost.

    A Host alias from ~/.ssh/config also works as the host, with its port, user and key:

    Host pi
      HostName raspberrypi.local
      Port 2222
      User pi

    With that, the address is pi:cc-cost, and ssh pi works by hand too.

    setup offers it as “SSH server…” and tries the connection at once. The first connection records the server’s host key, the way ssh does with StrictHostKeyChecking=accept-new; if that key changes later, cc-cost refuses to connect.

  3. Run cc-cost. It prints exchanged with pi@raspberrypi.local:cc-cost; cc-cost status shows the server. To stop, cc-cost config set remote "".

--offline skips the pricing page and the version check, not the server. --sync-dir <path> (or CC_COST_DIR) uses that folder for a run instead of the server.

A network share mounted from the server (SMB or NFS) also works as syncDir, without remote, but only while it is mounted: away from home, or with the server off, sync fails.

Price overrides

Prices come from Anthropic’s pricing page (see how-it-works.md) into pricing.json in the data folder (on the server, with remote). To use your own, for a negotiated rate or a model the page doesn’t list yet, add them to that file under overrides, in $ per million tokens; the rest of the file is rewritten daily, overrides is kept:

{
  "overrides": {
    "claude-opus-5": [5, 6.25, 10, 0.5, 25],
    "claude-opus-5-fast": [10, 12.5, 20, 1, 50]
  }
}

The order is input, cache write 5 minutes, cache write 1 hour, cache read, output. A -fast key prices fast-mode calls. A model with no price anywhere is left out of every total and listed at the end of the output as “No price for”. The pricing key of a cc-cost 1.x config is copied there on the next sync, if the file has no overrides yet.

Environment

Variable Effect
CLAUDE_CONFIG_DIR Where Claude Code keeps its data; a comma-separated list is read in full. Ignored when claudeDirs is set
CC_COST_DIR Shared folder for this run, like --sync-dir
NO_COLOR No colors
XDG_CONFIG_HOME Base of the config folder outside Windows

Without claudeDirs or CLAUDE_CONFIG_DIR, cc-cost reads ~/.claude and ~/.config/claude.

Several Claude accounts

Each account keeps its own folder (for example CLAUDE_CONFIG_DIR=~/.claude-work claude). setup finds the ~/.claude* folders and offers to read them all, and adds the SessionEnd hook to each one’s settings.json. Or set them yourself: cc-cost config set claudeDirs "~/.claude,~/.claude-work", then run setup again for the hooks. The list wins over CLAUDE_CONFIG_DIR on purpose: a hook started from one account’s session inherits that account’s variable and would otherwise sync only that account.

Accounts and plans

cc-cost tells accounts apart by the login Claude Code keeps in .claude.json (~/.claude.json for ~/.claude, inside the folder for any other beta), so the same account counts as one on every machine: a Team seat on a Mac and the same seat in ~/.claude-work on a PC add up. A folder without a login, such as one used with an API key, is an account of its own on its own machine.

setup asks each account for a name and a plan. The plan found in the login is preselected: Pro and Max are named there outright; for Team the login does not say which seat or what it costs, so pick Team Premium ($125 a month), Team Standard ($25) beta, Sponsored / free (a seat someone else pays for: its cost shows, but it stays out of the plan multiple), or Another price… for annual billing or a negotiated price. Change them later in cc-cost config → Claude accounts.

Reports can show the accounts together or one at a time:

  • cc-cost accounts lists the cost per account, and every report takes --account <name>.
  • cc-cost plan sets each account against its own plan, then all of them against the paid plans together: what you pay in total.
  • cc-cost blocks and the rate-limit hits are per account, since every subscription has its own limits.
  • The dashboard shows the accounts as buttons above the other filters and, with all of them selected, a card per account inside the total: its cost, share and multiple against its own plan (a card picks that account). The chart can be stacked by account. The plan multiple sets the accounts in view against their paid plans, over the days they were in use; sponsored seats and accounts without a known plan are named under it instead.

Usage synced before an account was known (cc-cost 0.1 and earlier) has none. setup asks whose it is on each machine; until then it shows as (unknown) and is priced against the plan setting.

Privacy

A snapshot contains, per day, project, session, model and attribution: token counts, call counts, the largest context and a context-size histogram. It also holds session ids with their first and last timestamps and the rate-limit events Claude Code recorded. It never contains prompts, answers, code, file names or paths; a project is the name of its repository folder, or a hash of it with anonymizeProjects. An account is a hash of the ids in its login, with the name and plan you gave it; the e-mail address and name in .claude.json are never read into a snapshot.

Reports make at most two network requests a day: the public pricing page, and the npm registry to see whether a newer cc-cost is out. Neither sends anything about your usage. --offline turns both off; --json, --csv and --quiet skip the version check. With remote set, every command copies the files described above from and to your server over SSH.

How it works

Per run

  1. Finds every *.jsonl transcript under ~/.claude/projects (or each claudeDirs folder, or CLAUDE_CONFIG_DIR), subagent transcripts included.
  2. Reads the assistant messages that carry a usage block, and the rate-limit events. Message content is never parsed beyond that.
  3. Removes duplicates (below) and sums the tokens per day, project, session, model and attribution.
  4. Merges the result into this machine’s snapshot in the data folder (see the archive), one file per month, so only the months that changed are written. With remote set, the data folder is the one on the server: pulled over SSH before the run, the changed files pushed after it.
  5. Reads every machine’s snapshot, prices it and prints the report. dashboard.html in the same folder is a static page that reads those files itself when opened; a machine writes it only when its cc-cost is newer than the one the page came from.

Costs

Each token type has its own rate. For Claude Opus 5:

Tokens $ / million  
Uncached input 5  
Cache write, 5 minutes 6.25 1.25 × input
Cache write, 1 hour 10 2 × input; Claude Code writes this tier
Cache read 0.50 0.1 × input (0.025 × on Claude Fable 5.1)
Output 25  

On top of tokens, web searches cost $10 per 1,000. Fast-mode calls (usage.speed == "fast") use the fast rates, with the cache multipliers applied to them, and appear as <model>-fast.

Claude 4.6 and later models bill a 1M-token context at the standard rate, so there is no long-context surcharge to apply.

The result is what the same tokens would cost on the API at list price. It is not a bill: a subscription isn’t charged per token.

Prices

Prices are read from https://platform.claude.com/docs/en/about-claude/pricing.md, the official page in Markdown, at most once every 24 hours, into pricing.json in the data folder, so every machine and the dashboard price with the same table. The model table and the fast-mode table are parsed; a page that yields fewer than five models is treated as unrecognized rather than half-used. If the page can’t be fetched or parsed, the stored table is used, then the one shipped with the package, and the output says which.

Models retired from the page keep the prices shipped with the package, so old usage stays priced. Today’s prices apply to all history.

Duplicates

The same API call can appear several times:

  • Resume and compaction copy earlier messages into a new transcript file.
  • Streaming writes one line per content block of a message, and output_tokens keeps growing until the last one.

cc-cost identifies a call by its message id and request id and keeps the copy with the most output tokens. Without this, totals come out about twice as high; keeping the first copy instead of the most complete one undercounts output by around 6%.

Days, projects, attribution

  • A day ends at local midnight in the configured time zone.
  • A project is the git repository the session’s working directory belongs to. Sessions often cd into subfolders; they still count for the repository. A worktree counts for its main repository. A folder that has been deleted resolves through its nearest remaining parent; without a repository, the folder name is used.
  • Subagent calls are grouped by subagent type (Explore, general-purpose, …); everything else is main. Skill and MCP attribution come from the fields Claude Code writes on each call.

Accounts

Every Claude Code folder is logged in to one account, recorded in its .claude.json. cc-cost tags each call with a hash of that login’s account and organization ids, so one account adds up across machines and folders, and two accounts on one machine stay apart. Transcripts don’t record the account themselves: a folder’s calls go to the account logged in there when they are scanned. Rate-limit events and 5-hour blocks are per account.

The archive

Claude Code deletes transcripts after cleanupPeriodDays (30 by default; cc-cost reads the setting). cc-cost’s snapshots keep the numbers after that, so history grows past the cleanup window.

A machine’s snapshot is a header, machines/<machine>.json (time zone, accounts, the list of months), and one file per month, machines/<machine>/<YYYY-MM>.json, with that month’s days, sessions and rate-limit events. A month older than the cleanup window never changes again, so its file is written once and a sync writes one or two files.

A new scan replaces a stored day only when that day is inside the cleanup window, where all of its transcripts must still exist. An older day may be only partly on disk: its short sessions deleted, a long session reaching into it still there. Such a day only fills a gap; it never overwrites the stored one. Days no longer on disk are kept as they are.

The condition is running cc-cost on each machine at least once per cleanup period; the daily schedule does.

What it can’t see

  • Cloud sessions. Claude Code on the web runs in Anthropic’s environment and doesn’t write transcripts to your machine. A session teleported to your terminal is counted from then on.
  • Background calls. Calls Claude Code makes by itself, such as titles and summaries (usually Haiku), aren’t in the transcripts. In testing they came to a few cents a month.
  • US-only inference (inference_geo: "us", 1.1 ×): Claude Code transcripts record the field as not_available.
  • Plan limits. Anthropic doesn’t publish them in tokens, so no tool can say which plan would have been enough. The rate-limit hits in your transcripts are the direct signal, and plan shows them; retries within one limit period count once.
  • Repricing on another model (insights, “the same tokens on …”) uses the same token counts. Models with a different tokenizer would count the same text differently, so treat it as a rough comparison.

Accuracy

Every rule on this page (deduplication, cache tiers, fast mode, web searches, day boundaries, the archive merge) has a test in test/. Claude Code’s own per-session cost-state records come out lower; they appear to cover only the current process, which starts over when a session is resumed.