TTDash is a local-first dashboard and CLI for toktrack usage data. It runs entirely on your machine, turns raw usage exports into charts and operational summaries, and keeps your stored data, settings, and imports on local disk instead of a hosted backend.
TTDash is built around the usage data provided by toktrack. Thanks to mag123c for creating and maintaining the data source this dashboard builds on.
Claude Code cleans up old sessions after 30 days by default. If you want long-term cost history in toktrack and TTDash, raise or effectively disable that cleanup in ~/.claude/settings.json:
{
"cleanupPeriodDays": 9999999999
}- Local-first by default: no cloud backend, no remote database, no analytics
- Fast to try:
npxandbunxwork without a global install - Built for daily usage review, cost tracking, and model/provider breakdowns
- Works with
toktrackexports and legacyccusageJSON - Can auto-import local
toktrackdata and run in the background
Deeper cost and model analysis:
Settings, local backups, and saved defaults:
Requirements:
- Node.js
20+ - A modern browser on the same machine
- Typst CLI only if you want PDF export
Run TTDash directly from the npm registry:
npx --yes @roastcodes/ttdash@latestOr with Bun:
bunx @roastcodes/ttdash@latestSmoke-check the published CLI without starting the dashboard:
npx --yes @roastcodes/ttdash@latest --help
bunx @roastcodes/ttdash@latest --helpFor a persistent global install:
npm install -g @roastcodes/ttdash
ttdashbun add -g @roastcodes/ttdash
ttdashStart the app:
ttdashTTDash starts a local server, opens the dashboard in your browser, and automatically retries on the next free port if 3000 is already in use.
Then either:
- Click
Auto-Importto load localtoktrackdata - Upload a
toktrackJSON file manually - Upload a legacy
ccusageexport - Open
Settingsto export or import local backups
The auto-import path prefers:
- local
toktrack bunxwith the exacttoktrackpackage spec pinned by this TTDash releasenpx --yeswith the exacttoktrackpackage spec pinned by this TTDash release
Quick examples:
Run on a specific port:
ttdash --port 3010Disable browser auto-open:
ttdash --no-openImport local data immediately on startup:
ttdash --auto-loadStart in the background:
ttdash --backgroundStop a running background instance:
ttdash stopCombine flags when needed:
ttdash --background --port 3010 --auto-load
ttdash --background --no-openEnvironment-variable equivalents:
PORT=3010 ttdash
NO_OPEN_BROWSER=1 ttdash
HOST=127.0.0.1 ttdashUsage:
ttdash [options]
ttdash stopOptions:
| Option | Description |
|---|---|
-p, --port <port> |
Set the start port |
-h, --help |
Show CLI help |
-no, --no-open |
Disable browser auto-open |
-al, --auto-load |
Run local auto-import immediately on startup |
-b, --background |
Start TTDash as a background process |
Commands:
| Command | Description |
|---|---|
ttdash stop |
Stop one or more running background instances. If multiple instances are running, TTDash prompts for which one to stop. |
Environment variables:
| Variable | Description |
|---|---|
PORT |
Override the start port |
NO_OPEN_BROWSER=1 |
Disable browser auto-open |
HOST |
Override the bind host |
TTDASH_ALLOW_REMOTE=1 |
Explicitly allow binding to a non-loopback host |
TTDASH_REMOTE_TOKEN=<long-random-token> |
Required for non-loopback binds; use at least 24 chars |
Binding to a non-loopback host such as 0.0.0.0 exposes the local dashboard API to your network, including destructive routes for local data and settings resets. TTDash refuses that bind unless you set both TTDASH_ALLOW_REMOTE=1 and a TTDASH_REMOTE_TOKEN with at least 24 characters. Only use remote token access over a trusted LAN, VPN, or SSH tunnel; for any public hostname, put TTDash behind an HTTPS reverse proxy with valid TLS termination before sending the bearer token.
Example:
TTDASH_ALLOW_REMOTE=1 TTDASH_REMOTE_TOKEN=<long-random-token> HOST=0.0.0.0 ttdash
curl -H "Authorization: Bearer $TTDASH_REMOTE_TOKEN" http://127.0.0.1:3000/api/usageWhen calling the server from another device, replace 127.0.0.1 with the server's LAN, VPN, or
SSH-tunneled host. For public hostnames, call an HTTPS reverse proxy URL instead; do not send the
bearer token over public HTTP.
Remote API requests can authenticate with the Authorization: Bearer $TTDASH_REMOTE_TOKEN header or the equivalent X-TTDash-Remote-Token: $TTDASH_REMOTE_TOKEN header.
- Provider and model filtering across OpenAI, Anthropic, Google, and other imported providers
- KPI sections for overall usage, today, and current month
- Cost charts, cumulative projection, forecast, token mix, model mix, heatmap, and weekday analysis
- Drill-down modal for per-day details
- CSV export and PDF export
- Command palette, keyboard shortcuts, and responsive layout
- Settings-backed defaults, section visibility, and local backups
TTDash is designed to stay local:
- No cloud backend
- No remote database
- No third-party fonts, analytics, or runtime tracking
- Imported usage data is stored on your machine
- Settings such as language, theme, provider limits, filters, and layout are stored on your machine
Platform paths:
- macOS:
~/Library/Application Support/TTDash/ - Windows:
%LOCALAPPDATA%\\TTDash\\for data and%APPDATA%\\TTDash\\for settings - Linux:
~/.local/share/ttdash/for data and~/.config/ttdash/for settings
The Settings dialog can export and import:
- app settings backups
- stored usage data backups
Data-backup import is conservative by design:
- missing days are added
- identical days are skipped
- conflicting existing days stay local and are reported instead of being overwritten silently
If you want to fully replace the current dataset with a fresh toktrack JSON, keep using the normal upload action in the header.
Make sure your global package manager bin directory is in PATH.
For Bun:
echo $PATH
ls -la ~/.bun/bin/ttdashTTDash automatically retries on the next port. You can also force one:
PORT=3010 ttdashInstall toktrack locally or ensure bunx / npx can execute it in the same terminal environment where you run ttdash.
PDF export requires the Typst CLI to be installed locally.
macOS:
brew install typstOther platforms:
- install Typst from
https://typst.app/ - make sure
typst --versionworks in the same terminal where you runttdash
Clone the repository and install locally:
macOS / Linux:
sh install.sh
ttdashWindows:
install.bat
ttdashManual source install:
npm install
npm run build
npm install -g .
ttdashOr with Bun:
bun install
bun run build
bun add -g "file:$(pwd)"
ttdashRun the app locally from the repo:
npm install
npm run dev
node server.js- Vite dev server:
http://localhost:5173 - API / production server:
http://localhost:3000
Build the production bundle:
npm run buildnpm run build is the gated build and runs format:check and lint before bundling. If you only want the Vite production bundle, use:
npm run build:appRun the main local gate without Playwright:
npm run verifyFor the full serial CI/release-style local gate, including coverage thresholds and Playwright, use:
npm run verify:fullOn a local machine with enough CPU, the staged parallel fast path gives quicker feedback across the same main test surfaces without the coverage-instrumented pass:
PLAYWRIGHT_TEST_PORT=3016 npm run verify:full:parallelKeep npm run verify:full or npm run test:vitest:coverage in the final validation path whenever
coverage thresholds matter.
If you want to run the steps individually, use:
npm run check:deps
npm run test:architecture
npm run test:unit:coverage
npm run test:e2e:ciTo inspect the slowest suites and test cases after a Vitest run:
npm run test:timingsThe Playwright suite starts an isolated local app per worker under .tmp-playwright/workers/. For
stable Playwright-only validation from another base port, use the CI-style worker cap:
PLAYWRIGHT_TEST_PORT=3016 npm run test:e2e:ciUse npm run test:e2e when you intentionally want the fresh app build plus the default local worker
count.
Refresh the README screenshots:
npm run docs:screenshots- Contributor guide:
CONTRIBUTING.md - Release guide:
RELEASING.md - Architecture rules:
docs/architecture.md - Test architecture:
docs/testing.md - Security policy:
SECURITY.md - Code of conduct:
CODE_OF_CONDUCT.md
GitHub Actions now runs formatting checks, ESLint, tsc --noEmit, unit/integration coverage, the production bundle, packaged-artifact verification, and Playwright smoke tests for pull requests and pushes to main.
MIT. See LICENSE.


