saahityaedams

17 Jul 2025

Claude Code Usage Cost

Poking around in the ~/.claude folder and looking at the files that claude code is saving to the local machine.

➜  .claude pwd
/Users/saahityae/.claude
➜  .claude ls
config          projects        statsig
local           shell-snapshots todos

There’s

  • config -> holds the config related file (eg. which tools are allowed, mcps configured, etc)
  • local -> the actual node CLI app.
  • shell-snapshots -> ?
  • statsig -> something related to https://statsig.com/ . I’m guessing its used for feature gating, A/B testing, product analytics etc (basically some statsig functionality)
  • todos - Basically a bunch of files with the structured text of TODOs that the claude code uses when you’re using it like
{
  "content": "Modify Dockerfile to use UV instead of Poetry",
  "status": "in_progress",
  "priority": "high",
  "id": "1"
},
{
  "content": "Update file copy instructions to handle uv.lock instead of poetry.lock",
  "status": "pending",
  "priority": "medium",
  "id": "2"
}
  • projects -> the most important of these that holds the sessions and interactions with claude code. There’s a bunch of .jsonl each with a session (I think).

In the projects folder, there’s a folder for each project (repo ?) you’re using claude code . There’s a bunch of .jsonl each with a session (I think) in each of these folder. Each line of these .jsonl is something like the below

{
  "parentUuid": "2c94d170-7792-4cdd-804c-1fb50ee88a01",
  "isSidechain": false,
  "userType": "external",
  "cwd": "/Users/saahityae/babbage-insights/service-pmo",
  "sessionId": "d036f5cc-ad9d-4eb6-909f-f9b59d453745",
  "version": "1.0.51",
  "message": {
    "id": "msg_bdrk_01M4KmU61E3CNFcMXzF9injN",
    "type": "message",
    "role": "assistant",
    "model": "claude-3-7-sonnet-20250219",
    "content": [
      {
        "type": "tool_use",
        "id": "toolu_bdrk_01KeXKgCbMy54Qp75KV8dMGy",
        "name": "TodoWrite",
        "input": {
          "todos": [
            {
              "content": "Review changes to metric_tracker_repo.py",
              "status": "completed",
              "priority": "high",
              "id": "1"
            },
            {
              "content": "Review changes to metric_tracker_router.py",
              "status": "completed",
              "priority": "high",
              "id": "2"
            },
            {
              "content": "Review changes to metric_tracker_service.py",
              "status": "completed",
              "priority": "high",
              "id": "3"
            },
            {
              "content": "Check for syntax errors",
              "status": "completed",
              "priority": "medium",
              "id": "4"
            },
            {
              "content": "Provide summary of changes",
              "status": "completed",
              "priority": "medium",
              "id": "5"
            }
          ]
        }
      }
    ],
    "stop_reason": null,
    "stop_sequence": null,
    "usage": {
      "input_tokens": 0,
      "cache_creation_input_tokens": 427,
      "cache_read_input_tokens": 27223,
      "output_tokens": 24
    }
  },
  "type": "assistant",
  "uuid": "ae19f2df-2d88-4160-8b27-cf45aba2a865",
  "timestamp": "2025-07-14T05:02:55.334Z"
}

The important fields I am interested in is usage and model and timestamp to understand my usage. I ran the following (Thank you ChatGPT - o4-mini).

jq -r '
  { model: .message.model, usage: .message.usage }
  | select(.usage != null)
  | "\(.model)\t\(.usage | @json)"
' /Users/saahityae/.claude/projects/*/*.jsonl > usage.txt

I then ran (after confirming that all the logged usage is for claude-3-7-sonnet-20250219 model).

cut -f2 usage.txt \
  | jq -s '
      {
        input_tokens:                     map(.input_tokens                // 0) | add,
        cache_creation_input_tokens:     map(.cache_creation_input_tokens // 0) | add,
        cache_read_input_tokens:         map(.cache_read_input_tokens     // 0) | add,
        output_tokens:                   map(.output_tokens               // 0) | add
      }
    '

To get

{
  "input_tokens": 62882,
  "cache_creation_input_tokens": 4194930,
  "cache_read_input_tokens": 27910727,
  "output_tokens": 69397
}

I ran the following to get the min and max timestamps

jq -s '
  [ .[]
    | select(.message.usage != null)
    | .timestamp
  ]
  | {
      min_timestamp: min,
      max_timestamp: max
    }
' /Users/saahityae/.claude/projects/*/*.jsonl

To get

{
  "min_timestamp": "2025-06-17T04:23:53.757Z",
  "max_timestamp": "2025-07-16T06:31:16.330Z"
}

Which seems like a month of usage data is being retained.

Refering to bedrock pricing (my claude code is pointed at my workplace’s AWS account) at https://aws.amazon.com/bedrock/pricing/ .

Claude 3.7 Sonnet

  • Price per 1,000 input tokens: $0.003
  • Price per 1,000 output tokens: $0.015
  • Price per 1,000 input tokens (cache write): $0.00375
  • Price per 1,000 input tokens (cache read): $0.0003

Which gets us to a grand total of

> 0.003 * 62882 / 1000
[1] 0.188646 # total read tokens cost
> 0.015 * 69397 / 1000
[1] 1.040955 # total write tokens cost
> 0.00375 * 4194930 / 1000
[1] 15.73099 # total cache write tokens cost
> 0.0003 * 27910727 / 1000
[1] 8.373218 # total cache read tokens cost
> 0.188646 + 1.040955 + 15.73099 + 8.373218
[1] 25.33381 # grand total USD
> 25.33381 * 86
[1] 2178.708 # grand total INR

INR 2178.708 OR USD 25.33381