Personal multi-vendor dashboard for AI coding subscriptions, token quotas, and spend alerts.
Claude · OpenAI Codex · Cursor · LongCat · Windsurf · and plugin-based extensions.
If you use more than one AI coding tool, quota and spend live in different product UIs. Token Monitor pulls them into one local dashboard:
| You care about | What you get |
|---|---|
| Remaining quota | Balance cards with progress meters, grouped by Coding / Token / API Key plans |
| Codex windows | 5h & weekly remaining, next reset, rate-limit cards — from your local Codex CLI login |
| Monthly spend | Dashboard trends, forecast, and vendor breakdown |
| Crossing limits | Rule-based alerts (quota %, spend, expiry, spikes) with cooldowns |
| New vendors | Decorator-registered plugins — implement VendorPlugin.poll() |
Credentials stay local: API keys are masked in responses, Codex OAuth is read in-memory from the CLI auth file and never stored in the database.
- Plugins — each vendor adapter self-registers and polls on a schedule (APScheduler).
- Snapshots — usage is append-only in local SQLite; secrets are masked and never logged.
- Surface — balances, dashboard, Codex status, and alert rules read from those snapshots.
- Python 3.11+ (3.12 recommended)
- Node.js 18+ and npm
git clone <repo-url>
cd TOKEN_MONITOR
make install # backend venv + frontend deps
cp backend/.env.example backend/.env # optional for local defaults
make dev # API :8000 + UI :5173Open http://localhost:5173. On first start the app syncs registered plugins into vendors and polling_configs (idempotent).
Background helpers if you prefer managed processes:
make start && make status # PIDs in .pids/, logs in logs/
make stopPython 3.12 not on PATH? Manual venv
cd backend
python3 -m venv venv && source venv/bin/activate
pip install -e ".[dev]"
cd ../frontend && npm installPorts 8000 / 5173 already in use?
# backend on 8001
cd backend && source venv/bin/activate
uvicorn app.main:app --host 127.0.0.1 --port 8001
# frontend on 5174, proxy → 8001
cd frontend
VITE_PORT=5174 VITE_API_TARGET=http://127.0.0.1:8001 npm run devbackend/.env is optional for local dev (SQLite defaults to ./token_monitor.db). Set vendor keys only for the integrations you poll (ANTHROPIC_API_KEY, OPENAI_API_KEY, CURSOR_API_KEY, WINDSURF_API_KEY). Codex does not need an API key — see below.
API docs while the backend is up: http://127.0.0.1:8000/docs
Codex reads the OAuth session produced by the Codex CLI — no API key is copied into the app:
- Install and log in once (
codex login) so~/.codex/auth.jsonexists (or setCODEX_HOME). - In 套餐管理, add an OpenAI Codex plan. Leave
auth_pathempty for the default path; optionally setaccount_id. - Scheduler polls every 15 minutes; use 立即同步 on the Codex page for a live refresh.
GET /api/codex/status returns the latest poll snapshot (not a live call). reset_at from the API is a Unix timestamp, shown as ISO in the UI.
ChatGPT
whambackend APIs may change. The mapper uses a field white-list and degrades gracefully — a failed poll keeps the last good snapshot and records the error on polling status.
Optional tray app (Apple Silicon, macOS 12+): Tauri host + private authenticated Python sidecar.
- Compact tray panel for quota and polling health; Open Token Monitor opens the full UI.
- Data:
~/Library/Application Support/com.tokenmonitor.desktop; secrets in Keychain; Codex login remains external and read-only.
cd frontend
npm run desktop:build # local DMG (dev)
npm run desktop:build -- --release # signed/notarized (Apple Developer credentials required)Full procedure: macOS desktop operations · data recovery
- Balances — plans by category with consistent cards and usage progress
- Codex page — 5h / weekly remaining, next reset, rate-limit cards with per-card expiry
- Dashboard — monthly spend, forecast, quota status, trends, vendor breakdown
- Plans & vendors — CRUD, vendor-specific fields, generic model / Base URL config
- Usage & alerts — append-only history, CSV export, rule engine with cooldowns
- Plugins —
@register_plugin+VendorPlugin; add a vendor without touching the core loop - Security — masked credentials in API responses; Codex tokens never written to DB or logs; binds to
127.0.0.1by default
| Layer | Choices |
|---|---|
| Backend | Python 3.12, FastAPI, SQLAlchemy async, SQLite (aiosqlite), APScheduler, httpx, tenacity |
| Frontend | React 18, TypeScript, Vite, Tailwind, Recharts, Zustand, React Query |
| Desktop | Tauri 2 + PyInstaller sidecar |
| Tests | pytest + pytest-asyncio · Vitest (frontend unit) |
Project layout
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI + lifespan (DB, plugins, scheduler)
│ │ ├── plugins/ # VendorPlugin adapters + registry
│ │ ├── services/ # bootstrap, alerts, codex auth/mapper
│ │ ├── routers/ # vendors, plans, dashboard, usage, alerts, polling, codex
│ │ ├── models/ · schemas/ · security/ · scheduler/
│ └── tests/
├── frontend/
│ ├── src/pages/ # Dashboard, Balances, Codex, Vendors, Plans, …
│ └── src-tauri/ # macOS tray host
├── scripts/ # start/stop + desktop build helpers
├── docs/ # operations + iteration notes
└── Makefile
- Plan responses mask
api_key_refand sensitiveextra_configkeys (api_key,access_token,refresh_token,id_token,cookie, …). - Codex tokens live only in memory for a poll; reset-credit
descriptionfields that may contain PII are dropped before persistence. - Do not expose the app on a public network without adding authentication first.
cd backend && source venv/bin/activate && pytest
cd frontend && npm run buildMIT