360 Secure SkillHub
360 安全技能中心

TinkerClaw Token Panel

监控 Anthropic、OpenAI、Gemini、Manus 的 token 用量与预算:用户自备凭证存入系统钥匙串,采集器把 token 计数写入本地 0600 SQLite,可选解析会话 transcripts,并经本地 REST API 与浏览器小部件展示用量和预算。

globalcaos
globalcaos
热度 65.47
最近更新 2026-09-17 20:05:20
分类:数据依赖:代码执行 / 联网浏览搜索 / 读写文件 / 第三方 API应用场景:数据处理 / 报告撰写 / 财务 / 自动化脚本

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add token-panel-ultimate
Metadata
name
token-panel-ultimate
version
2.6.2
description
Know exactly where your AI tokens go. Multi-provider tracking, budget alerts, and a local REST API—all in one dashboard. Provider credentials are supplied by you and sealed in the OS keychain, never passed on a command line; it reads no other application's credential store. Transcript parsing, live provider probing, and reading another tool's API-key variables are each opt-in and off by default. Only counts are stored — no prompts, no task titles. See Permissions, Data Flow & Consent.
metadata
{"openclaw":{"permissions":{"network":{"required":true,"scope":"Provider usage endpoints (Anthropic, OpenAI, Google, Manus) plus a REST API bound to 127.0.0.1:8765. Live rate-limit probing sends real billable requests and is off unless you pass --probe. No third-party telemetry."},"file_read":{"required":true,"scope":"Its own keychain entry (or warned owner-only 0600 fallback file); its own SQLite database and usage JSON files; and, ONLY with TOKEN_PANEL_READ_TRANSCRIPTS=1, local session transcripts under ~/.openclaw/agents. It reads no other application's credential store."},"file_write":{"required":true,"scope":"A local SQLite database of token COUNTS and opaque task ids, plus per-provider usage JSON. Created 0600 inside a 0700 directory. No prompts, message content or task titles are written."},"file_delete":{"required":true,"scope":"One path only: its own credential fallback file ~/.openclaw/data/token-panel/credentials, unlinked by --logout when the last provider is removed. The path is validated before deletion (absolute, inside $HOME, a regular file, not a symlink, owned by you, and beside a .token-panel-store marker this tool wrote). Nothing else is ever deleted; the SQLite database is not removed."},"env_read":{"required":true,"scope":"Namespaced TOKEN_PANEL_* variables (credentials TOKEN_PANEL_ANTHROPIC_TOKEN / TOKEN_PANEL_ANTHROPIC_ADMIN_KEY / TOKEN_PANEL_OPENAI_KEY / TOKEN_PANEL_GEMINI_KEY / TOKEN_PANEL_MANUS_KEY, TOKEN_PANEL_API_TOKEN, TOKEN_PANEL_READ_TRANSCRIPTS, TOKEN_PANEL_ALLOW_PROVIDER_ENV). Generic provider variables belonging to other tools (OPENAI_API_KEY, ANTHROPIC_ADMIN_API_KEY, GEMINI_API_KEY, MANUS_API_KEY) are read ONLY with TOKEN_PANEL_ALLOW_PROVIDER_ENV=1. No .env files are scraped."},"process_exec":{"required":true,"scope":"The OS keychain helpers only: `secret-tool` (Linux) for store/lookup/clear, and `security` (macOS) for lookup/delete, each run by absolute path from /usr/bin or /bin — $PATH is never searched. Secrets are never passed as command-line arguments — macOS writes go through Security.framework, Linux writes go over stdin."},"credentials":{"required":true,"scope":"First-party provider credentials supplied by you, stored under token-panel-ultimate in the OS keychain, one slot per credential kind: `anthropic` (a Claude usage token from `claude setup-token`, sent only to the Anthropic OAuth usage endpoint), `anthropic-admin` (an Admin API key, sent only to the Admin usage API), `openai`, `gemini` (sent in the x-goog-api-key header, never in a URL), `manus`. It never reads Claude Code, OpenClaw, browser, or other application credential stores. `--logout PROVIDER` clears every local store and prints the provider's server-side revoke URL."}},"owner":"kn7623hrcwt6rg73a67xw3wyx580asdw","category":"monitoring","tags":["tokens","usage","budget","anthropic","openai","gemini","manus","dashboard"],"license":"MIT","notes":{"security":"Runs a REST API bound to 127.0.0.1:8765. Its GET endpoints are unauthenticated and report your spend, so do not expose the port; every POST additionally requires X-Token-Panel-Token and is closed entirely unless TOKEN_PANEL_API_TOKEN is set. SQLite database is local, 0600 in a 0700 directory, and holds counts and opaque ids only; the database, its directory and every usage JSON refuse to be written through a symlink, and all four usage fetchers share one owner-only writer instead of four drifted copies (two of which used to inherit the ambient umask). Credentials are ones you supply, sealed in the OS keychain; the no-keychain fallback file refuses symlinks and is replaced atomically. POST bodies accept identifier-shaped strings only, and the browser widget HTML-escapes every value it renders. The systemd unit is a --user unit: it runs as you, never as root, and carries no hardcoded username."}}}

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 anthropic reads 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 supports anthropic-admin, openai, gemini and manus. The keychain helper is run from /usr/bin or /bin by 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 the x-goog-api-key header, not in a URL, and is redacted from error text. The Claude fetcher sends its own User-Agent, not Claude Code's. On macOS the write goes through Security.framework rather than security add-generic-password -w, precisely because that CLI form would place your key in this process's argv. --logout PROVIDER clears 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 set TOKEN_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.py and gemini-usage-fetch.py can send a 1-token request per model — billable, visible in your account activity. Off by default: without --probe they 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-Token to match TOKEN_PANEL_API_TOKEN, and returns 403 for everything when that variable is unset.
  • It deletes exactly one file, and checks before it does. --logout unlinks 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-store marker 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-admin credential 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