Token Panel Ultimate
One of dozens of skills and plugins in TinkerClaw — a self-improving OpenClaw fork that's been running 24/7 for months.
One dashboard for every token you spend. Anthropic, Gemini, OpenAI, Manus—tracked, stored, and queryable before the bill arrives.
Part of TinkerClaw — real-time token tracking, self-improving crons, persistent cognitive memory. This is one piece of that stack; the repo has dozens more.
👉 https://github.com/globalcaos/tinkerclaw
Clone it. Fork it. Break it. Make it yours.
⚠️ Permissions, Data Flow & Consent — read before installing
What it does that a "dashboard" does not imply:
- It uses only credentials you supply to Token Panel itself.
python3 secretstore.py --login anthropicreads the key from stdin and seals it in the OS keychain — never in a shell argument, so it cannot be picked up from your history or from another process reading command lines. The same command supportsanthropic-admin,openai,geminiandmanus. The keychain helper is run from/usr/binor/binby absolute path, never looked up on$PATH. - Each credential goes only where it belongs. The Claude usage token (
anthropic) and an Anthropic Admin API key (anthropic-admin) live in separate slots and are never sent to each other's endpoint. The Gemini key travels in thex-goog-api-keyheader, not in a URL, and is redacted from error text. The Claude fetcher sends its ownUser-Agent, not Claude Code's. On macOS the write goes through Security.framework rather thansecurity add-generic-password -w, precisely because that CLI form would place your key in this process's argv.--logout PROVIDERclears every local store and prints the provider's server-side revoke URL, because deleting a local copy is not revocation. - It reads no other application's credential store. Not Claude Code's, not OpenClaw's, not a browser's. Versions up to 2.5.1 could borrow Claude Code's OAuth token behind an opt-in environment variable; 2.6.0 removes that path entirely rather than gating it — a token issued to another application does not become this tool's to spend just because you set a variable. With no credential of its own, the Claude fetcher fails and tells you how to mint one.
- It will not quietly use an API key you exported for something else.
TOKEN_PANEL_*variables are ours and are always honoured. Generic ones —OPENAI_API_KEY,ANTHROPIC_ADMIN_API_KEY,GEMINI_API_KEY,MANUS_API_KEY— belong to other tools and are read only if you setTOKEN_PANEL_ALLOW_PROVIDER_ENV=1. - It can parse your session transcripts, which contain your prompts and replies in full.
Opt-in and off by default: nothing is read unless
TOKEN_PANEL_READ_TRANSCRIPTS=1, checked both by the collector and by the parser. Only token counts are extracted; message text is never written to the database or returned by the API. - Live rate-limit checks cost you money, so you have to ask for them. OpenAI and Google
publish remaining capacity only in responses to real requests, so
chatgpt-usage-fetch.pyandgemini-usage-fetch.pycan send a 1-token request per model — billable, visible in your account activity. Off by default: without--probethey make no network call at all and report the documented caps. - It serves a REST API, and it is not read-only. GET endpoints are unauthenticated and report
your spend and quota — bind to localhost and do not expose the port. Every POST additionally
requires
X-Token-Panel-Tokento matchTOKEN_PANEL_API_TOKEN, and returns 403 for everything when that variable is unset. - It deletes exactly one file, and checks before it does.
--logoutunlinks its own credential fallback file when the last provider is removed. That path must be absolute, inside$HOME, a regular file, not a symlink, owned by you, and sitting beside a.token-panel-storemarker this tool wrote itself — otherwise it refuses. Your database is never deleted.
What it stores: counts and identifiers. Provider, model, token totals, cost, credit totals, opaque task ids, statuses, timestamps. No prompts, no message content, no task titles. Earlier versions kept a 200-character slice of each Manus task prompt and wrote task titles into the usage JSON; 2.6.0 stops collecting both, and on first connect it blanks any prompt text a previous version already stored.
What it does NOT do: no credential reuse, no browser-token extraction, no silent secrets
scraping, no .env reads, no message content in the database, no telemetry, no third-party
endpoint. If no OS keychain exists, the CLI warns on every use before falling back to an
owner-only 0600 file inside a 0700 directory; that file and its directory must not be
symlinks, and it is rewritten atomically. Database and usage files are created 0600
inside a 0700 directory rather than inheriting an ambient umask. The local API allows CORS only
from localhost dashboard origins, not *.
The widget treats its data as text. Plan names, model ids and counts come from provider
responses, so every value is HTML-escaped or coerced to a number before it reaches the page, and
the userscript requests no GM_* grants and no file:// access. The API accepts only
identifier-shaped strings and non-negative counts on POST, and compares the mutate token in
constant time.
Diagnostics are off by default. The browser widget logs nothing unless you set
localStorage.BP_DEBUG = "1" — including error paths, which can carry request URLs and response
bodies. Console output is readable by anything sharing the page.
It runs as you, not as root. The systemd unit is a --user unit with no User= line and no
machine's username baked in.
Dependencies are pinned above known-vulnerable releases. The floor for fastapi is
0.109.1; the previous >=0.100.0 permitted a release affected by CVE-2024-24762.
Why This Exists
You've checked your Anthropic console, squinted at the OpenAI dashboard, opened a Gemini tab, and still weren't sure where last Tuesday's $14 went. Token Panel Ultimate puts all four providers in one place so the answer is always one query away.
What It Does
- Multi-Provider Tracking — Anthropic, Gemini, OpenAI, and Manus in a single SQLite database
- Budget Alerts — Set monthly limits per provider. Get warned before you overspend, not after
- REST API — Query usage programmatically on port 8765. Plug it into your own scripts or dashboards
- Transcript Parsing — Extracts token counts from OpenClaw session transcripts, opt-in via
TOKEN_PANEL_READ_TRANSCRIPTS=1 - Zero Dependencies — SQLite storage. No Postgres, no Redis, no cloud account required
- Runs as a Daemon — Systemd service keeps it alive in the background
Quick Start
pip install -r requirements.txt
# Give the dashboard a credential of its own (read from stdin, sealed in the keychain)
claude setup-token | python3 secretstore.py --login anthropic # scripts/claude-usage-fetch.py
python3 secretstore.py --login anthropic-admin # collector: Admin usage API (optional)
python3 secretstore.py --status
python3 api.py # http://127.0.0.1:8765
Remove a credential at any time — this clears every local store and prints the provider's revoke URL:
python3 secretstore.py --logout anthropic
Architecture
OpenClaw Plugin → Budget Collector API → SQLite DB (0600)
(GET only) ↓
Transcripts (opt-in) / Provider APIs / Manus Tracker
API Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /status | none | Overall budget status |
| GET | /budgets | none | Current budget limits |
| GET | /summary/monthly | none | Monthly usage summary |
| GET | /summary/daily/{provider} | none | Daily breakdown |
| POST | /budgets | token | Set or update budget limits |
| POST | /usage | token | Record a usage event |
| POST | /manus/task | token | Record a task (id, credits, status) |
token = X-Token-Panel-Token must match TOKEN_PANEL_API_TOKEN; with that variable unset,
every POST returns 403.
Changelog
- 2.6.2 — widget HTML-escapes all rendered values (fixes markup injection from provider data) and drops unused GM/file grants; Gemini key moved from URL to header with error redaction; separate
anthropic/anthropic-admincredential slots; keychain helpers run from fixed system paths, not$PATH; fallback credential file refuses symlinks and writes atomically; API token compared in constant time and POST inputs validated; Claude fetcher no longer sends a Claude Code User-Agent.
Clone it. Fork it. Break it. Make it yours.
👉 Explore the full project: github.com/globalcaos/tinkerclaw
