# claude-code-session-tracker

> Get more out of every Claude Code session.

A local dashboard for every Claude Code session on your machine: which one is waiting on you, which is still working, what each is spending, and how much of your five-hour and weekly limits is left. A second page shows where the last month of tokens went, by day, hour and project. It reads what Claude Code already writes to disk, plus the same usage readout /usage shows — no dependencies, no writes.

```sh
npx claude-code-session-tracker
```

Then open the printed `http://127.0.0.1:3099`. Node 20 or newer · macOS, Linux, and Windows. MIT licensed.

- Source: https://github.com/meyusufdemirci/claude-code-session-tracker
- npm: https://www.npmjs.com/package/claude-code-session-tracker
- Homebrew tap: https://github.com/meyusufdemirci/homebrew-tap
- Website: https://ccst.nefarius.co/

## Demo

[Claude Code Session Tracker Walkthrough](https://www.youtube.com/watch?v=RHrFZ8GrHSg) (0:32) — A 32-second walkthrough of the tracker: live sessions, usage limits, alerts and token history.

## Limits: how much of each window is left

Two windows, **five hours** and **seven days**. Each card shows how full it is and **when it runs out** at your current pace.

1. **The same percentage /usage shows** — Anthropic's **own reading** of each limit, the same number /usage shows.
2. **Used is what you were billed for** — Input, output and new cache tokens, **across every project and subagent**. Cache reads are shown apart.
3. **At this pace, it runs out at…** — Based on your recent pace, the card says **when the window runs out** — or where it will stand at reset.
4. **Two ticks on the bar** — **Red** is time elapsed, **blue** is where you'll land. Fill past the red tick means you're **spending too fast**, and the bar turns red.

Offline or without a fresh reading, the bar falls back to **your heaviest past window** — and says so.

## Alerts: told before you hit a limit

A **desktop notification** before a window runs out. **Off by default.**

1. **Off until you turn it on** — Nothing asks for permission **until you flip a switch**.
2. **Once, then quiet** — **One per interval**: an hour for the session, four for the week.
3. **Offered once** — Suggested **once** when a limit first appears.

A week with no reset from Claude **stays silent**.

## History: where the tokens actually went

A second page with your tokens **by day, hour, project and model** — plus your year at a glance, a report to export, and a picture to share.

1. **Spend per day, week or month** — A bar per day, quiet days included — or **folded into weeks or months** for a long range. A mark under a bar is **a day Claude refused a turn**.
2. **Hour of day, a month folded onto one week** — A month folded onto one week — **when your window actually opens**.
3. **Your year, day by day** — A calendar year as a grid, **shaded against your own busiest days**. Step back a year with ‹ ›.
4. **Every project and model, ranked by what it billed** — Ranked **by billed tokens**, with the full path under each project. Pick one to narrow everything to it.
5. **Export a report** — Any range as a **PDF or an .xlsx** — daily, weekly or monthly, one project or all. **Written in the browser**, sent nowhere.
6. **Share your year** — The year grid as an image, with **a post for X or LinkedIn** ready to paste it into. Nothing is posted for you.

**Reuses the limit cards' read**, so it costs almost nothing. Nothing polls — click Refresh. **Bookmarkable**: range, grouping, year and project live in the URL. Ranges reach back **a year and a week**.

## Features

- **Both limits, at the top** — Your **five-hour and weekly** usage, when they reset, and **when they run out**.
- **A heads-up before you hit one** — A **desktop notification** when a window is on course to run out. Off until you turn it on.
- **Where the tokens went** — Spend **per day, per half hour, per project**, and a whole year as a grid. Pick a project to narrow the page.
- **Reports and a year to share** — Export any range as a **PDF or .xlsx**. Share your year as **an image for X or LinkedIn**.
- **What the spend was made of** — Oversized sessions, standing context, model mix — **only when something is unusual**.
- **Active sessions, verified twice** — Checked against the OS, so **working means working**.
- **Recent sessions, every project** — Title, prompts, model and branch — **find the one worth resuming**.
- **A panel per session** — Counts, tokens, working time, subagents, and a **copyable resume command**.
- **The standing cost, itemised** — What fills the window up front — CLAUDE.md, skills, tools, MCP — **priced block by block**.
- **Open at login** — **autostart on** adds it to your login items. The page is **waiting when you sit down**.
- **Token usage you can sort by** — Coloured by context share, so you see **what's about to compact**.
- **Scriptable output** — **--json** prints the page's payload. The **HTTP API** is open too.
- **Fully keyboard driven** — Filter, move, open and close — **all from the keyboard**.
- **No dependencies, no install scripts** — **Nothing to install or configure.** Works the same on npm, pnpm, yarn and bun.
- **Local by construction** — **Loopback only**, never writes to your Claude directory. One outbound call, off with --offline.

## Quickstart

**No install needed.** Or use Homebrew to keep it on your PATH.

### npm

```sh
npx claude-code-session-tracker
```

### pnpm

```sh
pnpm dlx claude-code-session-tracker
```

### yarn

```sh
yarn dlx claude-code-session-tracker
```

### bun

```sh
bunx claude-code-session-tracker
```

### Homebrew

```sh
brew install meyusufdemirci/tap/claude-code-session-tracker
claude-code-session-tracker
```

On your PATH, updated with **brew upgrade**. Brings its own Node.

1. **Run it** — **No install step.** It starts a local server and opens your browser.
2. **Open the printed address** — Served at **http://127.0.0.1:3099**.
3. **Watch your sessions** — Refreshes **every 2 seconds**. Click a row for details.

## Start at login

**One command** adds it to your login items. Another takes it out.

### macOS

```sh
brew install meyusufdemirci/tap/claude-code-session-tracker
claude-code-session-tracker autostart on
```

Added as a **Login Item**, listed in System Settings → General → Login Items.

### Windows

```sh
npm install -g claude-code-session-tracker
claude-code-session-tracker autostart on
```

Added as a **Startup app**, listed in Settings → Apps → Startup.

1. **Install it once** — A login item needs a copy that **stays on disk**, so npx won't do here.
2. **Turn it on** — **One command**, no admin rights. It starts the tracker right away, too.
3. **Log in** — The dashboard opens at **http://127.0.0.1:3099** every time.

To stop: `claude-code-session-tracker autostart off`

## Command line options

| Flag | Description | Default |
| --- | --- | --- |
| `-p, --port <number>` | Port to listen on, stepping forward up to 20 times if taken | 3099 |
| `--host <address>` | Address to bind. Anything but loopback drops the guard, and the CLI says so | 127.0.0.1 |
| `--no-open` | Do not open a browser |  |
| `--json` | Print the session list as JSON and exit |  |
| `-n, --limit <number>` | How many sessions to list. Running sessions always show | 50 |
| `--claude-dir <path>` | Override the Claude data directory | ~/.claude |
| `--offline` | Never ask Anthropic's server for the usage limits; the cards fall back to Claude Code's cached readout or an estimate |  |
| `autostart on` | Start at login and open the page, on macOS and Windows. Starts it now, too |  |
| `autostart off` | Stop starting at login |  |
| `autostart status` | Say whether it starts at login |  |
| `-h, --help` | Show usage |  |
| `-v, --version` | Show the version |  |

### Keyboard shortcuts

| Keys | Action |
| --- | --- |
| `/` | Jump to the filter |
| `↑` `↓` | Move between sessions, across both tables |
| `Home` `End` | First and last session |
| `↵` | Open the selected session |
| `Esc` | Close the panel, or clear the filter |

## HTTP API

Anything the page does, **you can do with curl**.

| Method | Path | Description |
| --- | --- | --- |
| 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, Anthropic's percentage as `reported`, the heaviest closed window, and `lastLimited`. |
| GET | `/api/usage/history?since=&until=&project=&perProject=` | A sparse half-hour series, plus every project and model in the range ranked by billed tokens. Defaults to 30 days; spans over a year and a week (371 days) are narrowed, and `range` in the reply is what was read. `perProject=1` adds each project's own series. |
| 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. |

Sample response from `--json` and `/api/sessions`:

```jsonc
{
  "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

Read-only, **loopback-only**, and **no telemetry**.

- **Never writes to your Claude directory** — It **only reads** what Claude Code already wrote.
- **Loopback only** — Binds to **127.0.0.1** and rejects other hosts, so **no website can reach it**.
- **One outbound call, and --offline** — Only Claude Code's usage endpoint. **No telemetry, no analytics.**
- **No dependencies, no install scripts** — **Nothing third-party** runs on your machine.

### What it reads

| Path | Used for |
| --- | --- |
| `~/.claude/sessions/<pid>.json` | Running sessions and their live status |
| `<session cwd>/.git/HEAD` | The branch a running session is on |
| `~/.claude/projects/**/*.jsonl` | Session history — titles, prompts, models, branch |
| `~/.claude/projects/*/*/subagents/agent-*.jsonl` | Subagent turns, for the limit windows they bill to |
| `~/.claude.json` | The usage readout Claude Code caches — how full each limit is, and when it resets |
| `Keychain · ~/.claude/.credentials.json` | The token Claude Code is signed in with, to ask for the same readout /usage shows. Skipped with --offline |

## FAQ

### What do I need to run it?

**Node 20+** and Claude Code run at least once — or Homebrew, which brings its own Node. macOS, Linux and Windows.

### Are the limit cards my real quota?

**Yes** — it's Anthropic's own percentage, the same as /usage. Offline, it falls back to your heaviest past window and says so.

### Does it send anything over the network?

**One call** to Claude Code's usage endpoint, at most every five minutes. **No telemetry.** --offline turns it off. Exports are written in the browser, and Share only opens X's or LinkedIn's compose page when you click it.

### The limit cards are not there.

They appear once there's something to measure. If not, curl /api/limits — **a 404 means upgrade**.

### I turned notifications on and nothing has arrived.

Alerts fire **only when a window is on course to run out**. An ordinary afternoon never gets there.

### Can it start when my computer does?

Yes, on macOS and Windows. Install it with Homebrew or **npm install -g**, then run **autostart on**. **autostart off** removes it.

### Does it notify me when the dashboard is closed?

No. **A tab has to be open** — behind your editor is fine. **autostart on** opens one every time you log in.

### The history page does not update on its own.

**By design.** Click Refresh for a new read.

### How far back can the history page go?

A custom range reaches back **a year and a week**. The year grid steps back a calendar year at a time, as far as 2025.

### There is no Where it goes panel on my dashboard.

Your last 7 days were **ordinary**. The panel only shows when something stands out.

### Nothing is listed. What now?

Open **http://127.0.0.1:3099/api/health** to see which directory was searched. Fix it with CLAUDE_CONFIG_DIR or --claude-dir.

### A session I just started is missing.

It appears once Claude Code writes **its first record** — within 2 seconds after that.

### A session shows as idle while it is clearly working.

Status comes from **~/.claude/sessions/**. If that file is stale, so is the row.

### The port is already taken.

It **steps forward automatically** and prints the address. Use --port to choose (default 3099).

### Can I use it on a remote machine?

**Forward the port over SSH**: ssh -L 3099:127.0.0.1:3099 you@the-machine.

### Do I need to install anything?

**No.** Run it with npx, pnpm dlx, yarn dlx or bunx. Or: brew install meyusufdemirci/tap/claude-code-session-tracker.

### Is it free?

**Yes** — MIT licensed and open source.

## Author

Yusuf Demirci ([@meyusufdemirci](https://github.com/meyusufdemirci)) builds developer tools at [Nefarius Apps](https://nefarius.co).
