$ claude-code-session-tracker

Local · open source · zero dependencies

Get more out of every Claude Code session.

Four terminals, and you lose time to all of them: one session sat blocked on a question while you watched another think. Claude Code already writes every session to ~/.claude — this reads it and puts them all on one page, with their status and their token spend.

Across the top: how much of your five-hour window and your week is gone, and where each lands at this rate. A second page says where the last month of tokens actually went.

npx claude-code-session-tracker

Then open the printed http://127.0.0.1:3099.

0stars
1.1Kdownloads / month
v0.6.0latest

Node 20 or newer · macOS, Linux, and Windows

Preview

The page it opens

Both limits across the top, what the week went on under them, running sessions below, and a panel for whichever row you open. Invented data.

http://127.0.0.1:3099

Claude Code

Sessions

SessionsHistorySettings
LiveAutoLightDark
Filter by project, title, prompt, branch…

Session limit 14:30 → 19:30

Resets 19:30 · 2h 41m left

46%
Used
1.9M
Projected
4.1M

Against your heaviest five-hour window in 7 days — 4.1M.

Weekly limit 18 Aug → 25 Aug

Resets Mon 25 Aug, 03:00 · 2d 10h left

59%
Used
31.4M
Projected
47.3M

Every model, against your heaviest week in 28 days — 52.9M.

Where it goes 2 findings

Last 7 days

Long sessions
3.1M

3 sessions ended several times larger than the 128K this machine usually reaches. Every turn after that re-reads the whole window.

acme-web · 214 turns · 62.4K → 604.1Kbilling-api · 168 turns · 58.1K → 511.7K

Standing context
1.6M

Sessions open holding 74.3K — the system prompt, tools, skills and memory files, paid before anything is asked.

38 sessions

Ranked by what each accounts for, in the tokens a limit counts. A finding appears only where the range runs heavier than this machine's own middle.

Active 3

ProjectSessionStatusModelTokens (in/out/total)Uptime
acme-web~/code/acme-webRework the checkout flow279ed6aebusyopus-5182.4K / 12.9K / 195.3K1h 24m
billing-api~/code/billing-apiPaginate the invoices endpointb41c7d02waitinginput neededsonnet-596.2K / 7.4K / 103.6K18m 42s
design-system~/code/design-systemTidy the button variants5f2a91c4idlesonnet-541.8K / 3.1K / 44.9K3h 06m

Recent 5

RangeAll timeSortMost recent
ProjectSessionModelLast activeTokens (in/out/total)
acme-web~/code/acme-webFix the flaky checkout testit only fails on CI, never on my machineopus-512m ago214.7K / 15.3K / 230.0K
mobile-app~/code/mobile-appRetry the offline write queueflush the queued writes once the connection is backsonnet-52h ago158.9K / 11.2K / 170.1K
docs-site~/code/docs-siteAdd dark mode to the docsauto, light and dark, and no flash on first paintsonnet-55h ago88.4K / 6.1K / 94.5K
billing-api~/code/billing-apiRotate the webhook secretmove it to the secret store and re-sign the callbackshaiku-4-5yesterday23.1K / 1.9K / 25.0K
acme-web~/code/acme-webWindows CI: separators in the path testthe path assertions only hold on posixopus-53d ago61.2K / 4.4K / 65.6K

50 of 794 on disk

Read-only. Bound to loopback. Nothing leaves this machine.

Invented projects and prompts. On your machine the list refreshes every 2 seconds, the limit cards every 15, and the colour on a token total is its share of that model’s context window. Where it goes opens shut, and stays off entirely on a week with nothing unusual in it. Swipe a table to see the rest of it.

Open any row

The panel is the rest of the session: what it spent, how much of the model’s window is still free, when it started, and how much of the elapsed time was actually worked. It carries the first and last prompt, a resume command you can copy, and a button that reveals the transcript in your file manager.

Under that, the two readings a total cannot give. Static context itemises what the window was already holding before you asked anything — which CLAUDE.md, the skill listing, the deferred tools, the agents, the MCP instructions — because that block is paid again on every turn, and it is the one part of the window you can actually go and shorten. What this session cost is that multiplication done out loud: the window an average turn held, times however many turns there were.

Every figure comes from the transcript Claude Code already wrote. Nothing is estimated, and a number the transcript does not carry is left out rather than guessed at — bar the static rows, which are priced from the text each block put in the window and say so.

acme-web

Rework the checkout flow

busy

Tokens

Input
182,411
Output
12,907
Total
195,318
Cache read
4,182,660
Cache write
311,204

Context window

Static (system + tools)
41.2K
Conversation
154.1K
Free
804.7K

19% of 1M tokens · opus-5

Static context

  1. ~/code/acme-web/CLAUDE.md18,214 · 44%
  2. Skills (32)9,431 · 23%
  3. Deferred tools (86)5,102 · 12%
  4. Agents (11)3,608 · 9%
  5. MCP instructions2,417 · 6%
  6. Everything else2,435 · 6%

41,207 tokens before the first turn ran, estimated from the text each block put in the window.

What this session cost

Its 38 turns read 4.2M back out of cache between them. Those reads bill at a fraction of the rest, so they sit outside the totals above.

The window an average turn held
110.1K
Of it, static — read back every turn
41.2K
Subagents, billed here but not shown
2

Session

Model
opus-5
Started
14:12
Last active
just now
Elapsed
1h 24m
Working time
38m 09s

Limits

How much of each window is left

Claude Code bills against two windows: five hours, and seven days. Neither is written to your disk, so both are measured off the transcripts.

  1. Measured, not read

    Neither quota is written to disk. The five-hour window is chained off turn timestamps and floored to the half hour; the week is pinned to the reset Claude Code cached. If Claude has refused a turn, its own reset time wins.

  2. Used is what you were billed for

    Input, output and newly-cached tokens, across every project and every subagent. Cache reads are shown apart — they cost a fraction as much and would swamp the rest fifty to one.

  3. Projected looks forward

    Where the window lands by its reset at the rate it has kept. It stays hidden until a fifth of the window has gone, since an early rate is noise.

  4. A yardstick, not a quota

    The bar is a share of your heaviest closed window — 7 days back for the five-hour card, 28 for the weekly one. Past it the bar reads full and the percentage keeps counting.

Transcripts are append-only, so files untouched since the cutoff are skipped on mtime and the rest are cached per version. On the development machine, 901 files and 1 GB come to ~1.3s cold and ~7ms warm. The page reads every 15 seconds and ticks the countdown itself in between.

Alerts

Told before you hit a limit

A desktop notification when a window is headed past your heaviest one. One switch per limit, both off until you turn them on.

http://127.0.0.1:3099/settings

Claude Code

Settings

SessionsHistorySettings

Notifications

A desktop notification when a window is headed past your heaviest one — then quiet for as long as you say.

Session limitAgainst your heaviest window in the last 7 days.
At most one every1 hour
Weekly limitAgainst your heaviest week in the last 28 days. Needs a reset Claude has reported.
At most one every4 hours
  • One at a time. Nothing is sent again inside the interval.
  • Only while a dashboard tab is open. The tab can be buried, but nothing runs in the background.
  • Kept in this browser. Nothing leaves the machine.
Drawn with one limit on and one off — the pair of states anyone reading a pair of switches is actually asking about.
127.0.0.1 · now

Session limit

At this pace, it won't last the five-hour window — it resets at 19:30.

The whole of it. The projection and what it is measured against stay on the card; what comes out here is the reset, because that is the part there is something to do about.

Hear about a limit before you reach it

A desktop notification when a window is on course to run past your heaviest one — even with this tab behind your editor.

Not nowOpen notifications
Shown once, when there is first a limit to show. Not now brings it back a fortnight later, once, and never again after that.
  1. One line, when the projection crosses

    The same fact the card already shows in colour, addressed to whoever is not looking at the card. It carries the reset time, because that is the half you can act on.

  2. A switch each, both start off

    Settings is the third tab, with one switch per limit. Turning one on is what asks the browser for permission — nothing asks on load. If the browser is blocking the page, the switches come back off and say so.

  3. Then quiet for as long as you say

    It speaks once, then holds its tongue: an hour for the five-hour window, four for the week. Crossing the line again inside that interval is the same interruption twice, so it is not sent.

  4. Offered once, kept in this browser

    A sheet offers these the first time there is a limit to show. Not now means not now — it returns once, a fortnight later, and that is the last of it. Settings live in this browser, like the theme.

Nothing runs in the background: the page notices on the same 15-second read the cards already make, so a tab has to be open. And a week with no reset from Claude has nothing to project into, so it never speaks.

History

Where the tokens actually went

A page at /history for the weeks behind the cards: by day, by hour, by project and by model. Same sweep as the limit cards, so it costs almost nothing.

http://127.0.0.1:3099/history?range=30d

Claude Code

History

SessionsHistorySettings
RangeLast 30 daysRefresh

25 Jul – 23 Aug · 30 days

Billed
41,812,904
Cache reads
2,012,517,338
Turns
10,211
Projects
5
Models
3
Busiest day
12 Aug · 2.9M

Spend per day 26 active

Billed tokens per local day. A mark under a bar is a turn Claude refused.

Hour of day

Every half hour of the range, over one week. Darker is heavier.

Projects 5

Ranked by billed tokens. Pick one to narrow everything above.

ProjectTurnsBilledCache readsShare
acme-web~/code/acme-web4,18218.4M902.6M
44%
billing-api~/code/billing-api2,1409.1M431.7M
22%
mobile-app~/code/mobile-app1,8846.7M318.2M
16%
design-system~/code/design-system1,1024.3M205.9M
10%
docs-site~/code/docs-site9033.3M154.1M
8%

Models 3

Every model that answered in this range.

ModelTurnsBilledCache readsShare
opus-56,20427.6M1.3B
66%
sonnet-53,41112.1M620.4M
29%
haiku-4-55962.1M92.1M
5%

Read at 21:14

Invented repositories again, and the same ones as the dashboard above, so the two mocks read as one machine. Swipe the grid and the tables to see the rest of them.
  1. Spend per day, quiet days included

    A bar for every local day in the range, quiet days included. Heights are linear, so one heavy day flattens the rest. A mark under a bar is a day Claude refused a turn.

  2. Hour of day, a month folded onto one week

    Every half hour of the range laid over one week, darker where it is heavier. Tells you what the daily bars cannot: whether the window opens at nine in the morning or eleven at night.

  3. Every project and model, ranked by what it billed

    Cache reads held apart, as on the limit cards. Pick a project and the summary, both charts and the model list narrow to it; pick it again to let go.

  4. The range and the project live in the URL

    `?range=7d&project=…`, so reload, bookmark and Back all work. Ranges are whole local days, capped at 90.

No read of its own: the page reuses the sweep the limit cards already make. A 7-day page is ~450ms cold and ~15ms warm, and the cache is shared, so whichever you open second is the cheap one. Nothing here polls — Refresh is how you ask for another read.

A project whose directory has moved or been deleted cannot be resolved from the folder name Claude Code stores, so the page shows the plainest reading of it — and says so rather than passing a guess off as fact.

What you get

Everything you need to keep sessions moving

Both limits, live status, token usage, a month of history, and enough per-session detail to pick the one worth going back to.

  • Both limits, at the top

    How much of your five-hour and weekly windows you have spent, when they reset, and where they land at this rate. Subagents included.

  • A heads-up before you hit one

    A desktop notification when a window is headed past your heaviest one. One switch per limit, both off until you turn them on.

  • Where the tokens went

    A second page: spend per day, per half hour, and per project. Pick a project and the whole page narrows to it.

  • What the spend was made of

    Oversized sessions, standing context, a lopsided model mix — measured against your own machine's middle, so an ordinary week says nothing.

  • Active sessions, verified twice

    Every running session is checked against the OS, so a row that says working really is one to wait on.

  • Recent sessions, every project

    Title, first and last prompt, model, and branch — enough to find the one worth resuming. Filter by day or a range of your own.

  • A panel per session

    Message and tool-call counts, tokens, elapsed against working time, subagents, a copyable resume command, and the transcript.

  • The standing cost, itemised

    What the fixed half of a session's window went on — CLAUDE.md, skills, deferred tools, agents, MCP — priced block by block.

  • Token usage you can sort by

    Tokens per session, coloured by share of the context window, so you see what is about to compact. Ranked across the whole window.

  • Scriptable output

    A --json flag prints the same payload the page uses. The HTTP API behind it is open too.

  • Fully keyboard driven

    Filter, move between sessions, open and close the panel. A check takes seconds.

  • No dependencies, no install scripts

    Nothing to install, nothing to configure, and the same behaviour under npm, pnpm, yarn, and bun.

  • Local by construction

    Binds to loopback, refuses non-loopback hosts, makes no outbound calls, and never writes to your Claude directory.

Quickstart

Run it with any package manager

Four runners need no install at all. Homebrew is there if you would rather have it on your PATH.

npx claude-code-session-tracker
  1. Run it

    No install step. The command downloads, starts a local server, and opens your browser.

  2. Open the printed address

    Served at http://127.0.0.1:3099. If the port is taken it steps forward and prints what it bound.

  3. Watch your sessions

    The list refreshes every 2 seconds. Click any row for the full read.

Command line

Options

Every flag the CLI takes, and every key the page answers to.

FlagDescriptionDefault
-p, --port <number>Port to listen on, stepping forward up to 20 times if taken3099
--host <address>Address to bind. Anything but loopback drops the guard, and the CLI says so127.0.0.1
--no-openDo not open a browser
--jsonPrint the session list as JSON and exit
-n, --limit <number>How many sessions to list. Running sessions always show50
--claude-dir <path>Override the Claude data directory~/.claude
-h, --helpShow usage
-v, --versionShow the version

On the page

Click any row for the full read. Everything has a key.

  • /Jump to the filter
  • Move between sessions, across both tables
  • HomeEndFirst and last session
  • Open the selected session
  • EscClose the panel, or clear the filter

Scripting

An HTTP API, and JSON on stdout

The same server the page talks to, so anything it does you can do with curl.

MethodRoute
GET/api/sessions?limit=N

The session list. `limit` matches --limit, and running sessions are always included.

GET/api/sessions?since=&until=

The same list, narrowed by last-written time. Epoch ms; `since` inclusive, `until` exclusive.

GET/api/sessions?sort=

`recent` (default), `tokens-desc`, or `tokens-asc`. Ranks across the whole window, not just the page.

GET/api/sessions/:id

One session with counts, tokens, models, activeMs, awaySummary, and notes.

GET/api/limits

Both limits, as `session` (five hours) and `weekly` (seven days). Each carries the window in progress, the heaviest closed one, and `lastLimited`.

GET/api/usage/history?since=&until=&project=

A sparse half-hour series, plus every project and model in the range ranked by billed tokens. Defaults to 30 days; spans over 90 are narrowed, and `range` in the reply is what was read.

GET/api/usage/advice

The findings behind the `Where it goes` panel as measurements, not sentences. Same params as the history route; defaults to 7 days.

GET/api/health

Status, version, the Node it runs on, the resolved Claude directory, and per-source status.

POST/api/sessions/:id/reveal

Shows that transcript in your file manager. Requires a loopback Origin.

--json prints the same payload the page uses, then exits.

npx claude-code-session-tracker --json | jq '.sessions[] | .project.name'
{
  "sessions": [
    {
      "id": "279ed6ae-49fd-4234-a74e-145f5535341c",
      "source": "claude-code",
      "status": "busy",              // busy · waiting · idle · ended
      "project": { "name": "…", "path": "…", "gitBranch": "main" },
      "title": "Disable dependabot", // Claude's own title, when it wrote one
      "firstPrompt": "…",
      "lastPrompt": "…",
      "model": "claude-sonnet-5",
      "version": "2.1.235",
      "startedAt": 1787142489923,
      "lastActiveAt": 1787142700231,
      "transcriptPath": "…/279ed6ae….jsonl",
      "sizeBytes": 136133,
      "live": { "pid": 4129, "kind": "interactive", "entrypoint": "cli" }
    }
  ],
  "total": 794,
  "generatedAt": 1787142701002
}

Privacy

It never leaves your machine

Transcripts hold your prompts, your paths, and sometimes your secrets. That is why the defaults are what they are.

  • Never writes to your Claude directory

    It reads what Claude Code already put on disk, opens nothing for writing, and creates nothing.

  • Loopback only

    Binds to 127.0.0.1 and refuses any request whose Host is not loopback, so no website can point your browser at it.

  • No outbound calls

    No telemetry, no update check, no analytics. Nothing leaves the machine.

  • No dependencies, no install scripts

    Nothing third-party runs on your machine, at install time or after.

What it reads

Everything comes from what Claude Code already writes to disk.

PathUsed for
~/.claude/sessions/<pid>.jsonRunning sessions and their live status
<session cwd>/.git/HEADThe branch a running session is on
~/.claude/projects/**/*.jsonlSession history — titles, prompts, models, branch
~/.claude/projects/*/*/subagents/agent-*.jsonlSubagent turns, for the limit windows they bill to
~/.claude.jsonThe weekly reset, from Claude Code's cached usage readout — the only place that clock is written down

FAQ

Questions, and the honest answers

Who made this

Yusuf Demirci

Yusuf Demirci builds developer tools at Nefarius Apps, and wrote claude-code-session-tracker after losing track of one too many Claude Code sessions across four terminals.

One command, and you stop guessing which session needs you.

Node 20 or newer · macOS, Linux, and Windows. MIT licensed.

npx claude-code-session-tracker