pgx
PGX — Lightweight Postgres for AI agents. Written in Rust. Thousands of isolated databases in one runtime. 🐘
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗TokenBoard is a hosted AI token usage dashboard for Claude Code, Codex, Antigravity, OpenCode, Pi, Grok Build and DeepSeek Harness. A local collector normalizes daily usage snapshots, uploads them to a Cloudflare Workers + D1 backend, and the web app serves private dashboards, leaderboards, public JSON, README SVG cards, and scheduled reports.
TokenBoard never uploads prompts, completions, raw conversation logs, local paths, or plaintext upload tokens.
$0.00 usage.Open the deployed app and visit:
https://<your-tokenboard-domain>/settings/install
Generate an install prompt, paste it into Codex or Claude Code, and let the agent run setup. The
setup flow pairs the device, writes ~/.tokenboard/config.json and the local
~/.tokenboard/device-link.json recovery claim, installs scheduled sync and notifier hooks, then
runs the initial sync unless --skip-initial-sync is used.
The install form passes the browser's IANA timezone from
Intl.DateTimeFormat().resolvedOptions().timeZone; UTC is used only when the browser cannot provide
a valid timezone.
Profiles are private by default. Enable public JSON/SVG and leaderboard participation from
/settings/profile.
GET /api/public/:slug.json
GET /api/public/:slug.svg
README card:
[](https://<your-tokenboard-domain>)
The card editor supports localized labels, light/dark themes, layout variants, custom title/subtitle, metric ordering, hidden metrics, live private preview, and reset-to-defaults. Invalid stored card config falls back to a default card instead of breaking the settings page.
Authenticated users can add webhook bots from /settings/notifications. Each subscription stores an
encrypted webhook URL, optional signing secret, provider, timezone, selected weekdays, and up to four
local send times. New subscriptions default to 18:00 local time.
Before enabling reports, configure a 32-byte base64 encryption key as a Worker secret:
openssl rand -base64 32
pnpm --filter @tokenboard/web exec wrangler secret put WEBHOOK_ENCRYPTION_KEY
Supported webhook hosts:
| Provider | Host |
|---|---|
| WeCom | https://qyapi.weixin.qq.com/cgi-bin/webhook/send?... |
| DingTalk | https://oapi.dingtalk.com/robot/send?... |
| Feishu | https://open.feishu.cn/open-apis/bot/v2/hook/... |
| Lark | https://open.larksuite.com/open-apis/bot/v2/hook/... |
Provider payload behavior:
| Provider | Message shape | CTA behavior |
|---|---|---|
| WeCom | Markdown capped to the WeCom webhook byte budget. | Inline report link, or leaderboard link when report sharing is unavailable. |
| DingTalk | Signed actionCard when a signing secret is configured; the message keeps the TokenBoard keyword for keyword-protected robots. | singleTitle / singleURL button plus a preserved inline fallback link outside truncated text. |
| Feishu / Lark | Interactive Card 2.0 with optional signed webhook body. | Card button uses open_url behavior, with report detail as the preferred target and leaderboard fallback. |
Reports include totals, tokens without cache reads, cache rate, cost, sessions, source split, top models, and a link to that report's aggregate snapshot page when daily report sharing is enabled. Test sends are labeled as previews. Scheduled sends are deduped by subscription, report date, and schedule slot; failures retry up to three attempts before moving to the next slot.
Daily report history stores only aggregate snapshots. Users can disable unauthenticated access for
all report links or revoke a single report link from /settings/notifications. Owners can still view
their own unexpired private or revoked snapshots while signed in. Anonymous /reports/daily/:id
reads require the global sharing switch, an unrevoked report link, and a report date inside the
configured retention window. Retention defaults to 30 days and can be configured with
TOKENBOARD_DAILY_REPORT_HISTORY_DAYS.
Shared report pages reuse the same usage metric cards as the private dashboard and detail pages. The four headline metrics keep the raised card surface, compact number formatting, and responsive four-column, two-column, then single-column layout.
--since accepts YYYYMMDD and YYYY-MM-DD for every source; --since all performs an
explicit full-history backfill.POST /api/v1/ingest/check lets newer collectors skip unchanged snapshots.device_id are stored under the legacy device id.device-link.json is local sensitive recovery state. Reconnect requires explicit
--use-device-link; setup never prints the install claim.origin/HEAD.
Explicit repo refs try branch checkout first, including all-hex branch names, then fall back to raw
ref checkout.CODEX_HOME. When a home path
itself contains a comma, use TOKENBOARD_CODEX_HOMES_JSON with a non-empty JSON array of paths
instead of an ambiguous CODEX_HOME value.costUsd: 0. Web, public, report, and
leaderboard surfaces label those costs as unavailable.costUsd: 0 and every
surface labels the cost as unavailable rather than deriving a figure from a pricing table.Local usage sources:
| Source | Reads |
|---|---|
| OpenCode | ~/.local/share/opencode/opencode.db (XDG_DATA_HOME respected) |
| Pi | ~/.pi/agent/sessions/**/*.jsonl (PI_CODING_AGENT_DIR, PI_CODING_AGENT_SESSION_DIR) |
| Grok Build | ~/.grok/{sessions,archived_sessions}/**/updates.jsonl (GROK_HOME) |
| DeepSeek Harness | ~/.dsh/sessions/**/session.jsonl[.zstd] (DSH_HOME, DSH_SESSION_ROOT) |
Only token counts, model ids and timestamps are read from these stores. For OpenCode the token fields
are projected inside SQLite so the message blob, which also holds prompts and a local path, never
enters the collector. SQLite is read through Node's built-in node:sqlite, so nothing has to be
installed; runtimes without it fall back to a sqlite3 executable, and setting
TOKENBOARD_SQLITE_BIN selects that executable explicitly. Both open the database read-only.
Scanning is bounded: depth-capped, symlinked directories are not followed, and oversized files are
skipped.
Notifier hooks:
| Source | Hook |
|---|---|
| Codex | ~/.codex/config.toml notify |
| Claude Code | ~/.claude/settings.json hooks.SessionEnd |
| Antigravity CLI | ~/.gemini/antigravity-cli/settings.json statusLine.command, explicit opt-in only |
Hooks coalesce pending work by source in ~/.tokenboard/notify.signal.d, start at most one background
notify.mjs dispatcher or reuse a live cooldown trailing process, and skip auto-upgrade. The legacy
~/.tokenboard/notify.signal file is retained only as a visible fallback when atomic queueing fails.
Scheduled, manual, preview, and hook collection share sync.lock; a hook child reuses the lock held
by its coordinator. Signals received during a running collection are retained and coalesced into one
trailing run after the default 15-minute cooldown instead of immediately repeating a full reconciliation.
Set TOKENBOARD_NOTIFY_COOLDOWN_MS to an integer from 60000 through 7200000 to tune this
hook-only window. The hook handler persists its signal before the background notifier validates this
setting; without shared-lock contention, the configured window is the maximum delay after the most
recent successful TokenBoard reconciliation. Lock timeouts
continue to retry after one minute.
A hook trigger landing within 30 minutes of a scheduled sync time (the config file's scheduleTimes)
is skipped: the scheduled run collects the same usage minutes later, and the queued signal is left
for the next hook run to acknowledge.
If a scheduled sync reaches the lock timeout, it records a private deferred state and performs a
bounded in-process retry: at most five attempts with a one-minute delay after each continued lock
contention. The retry never runs checkout upgrade and stops immediately for a real collector failure.
status.mjs reports the retry phase and attempt count without exposing local paths or error details.
For verified append-only Claude Code and Codex JSONL files, hook collection reads only the appended
suffix and reconciles only newly affected dates. A missing cursor file hash or trailing-newline
marker, truncation, or replacement falls back to the full-file path.
Bounded Antigravity collection also retries up to 30 older pending daily-model groups per run, and
only acknowledges groups that were included in the successful upload.
Antigravity CLI token totals are derived only from local SQLite history. Its optional status line
handler writes a bounded, sanitized local diagnostic log and never contributes snapshots or uploads.
After acknowledgement, recent SQLite event identities are retained for incremental reconciliation;
older identities are compacted with a persisted frontier. A bounded scan that encounters an unknown
event at or before that frontier stops and requires --since all. A full-history scan rebuilds the
canonical daily-model snapshot from SQLite rather than adding a retained local aggregate, keeping
replays idempotent without raw conversation identifiers or unbounded cursor state.
Logs:
~/.tokenboard/logs/daily-sync.out.log
~/.tokenboard/logs/daily-sync.err.log
Rotated logs are capped at 1 MiB and kept for 7 days.
Node.js 22.23.4+ or 24.22.1+ is required (the range is ^22.23.4 || ^24.22.1 || >=26.12.1; older releases are missing security fixes for CVE-2026-111497 and the Node TLS hostname bypasses). .npmrc sets engine-strict=true, so an unsupported Node fails the install instead of warning.
pnpm install
pnpm test
pnpm typecheck
pnpm build
node --test skills/tokenboard/scripts/*.test.mjs
Useful collector commands:
node skills/tokenboard/scripts/status.mjs
node skills/tokenboard/scripts/sync.mjs --mode sync --source all --package-manager pnpm
node skills/tokenboard/scripts/uninstall.mjs
node skills/tokenboard/scripts/uninstall.mjs --remove-config
node skills/tokenboard/scripts/uninstall.mjs --all
Package manager overrides:
| Variable | Values |
|---|---|
TOKENBOARD_PACKAGE_MANAGER | pnpm, bun, npm |
TOKENBOARD_CCUSAGE_BIN | custom ccusage path |
TOKENBOARD_FORCE_PACKAGE_RUNNER | 1 to force package-runner execution |
Manual deploy:
pnpm run deploy
The deploy script validates the production Wrangler config, builds the Worker, applies pending remote D1 migrations, verifies the critical production schema, and deploys. Cloudflare Workers Builds and GitHub Actions automatic deployment are intentionally not configured in this repository.
pnpm --filter @tokenboard/web run deploy
Do not deploy with a raw wrangler deploy command when migrations are pending. The guarded helper and
the manual release procedure intentionally apply migrations before changing the Worker version.
Required production secrets:
| Secret | Purpose |
|---|---|
BETTER_AUTH_SECRET | Better Auth session signing |
GITHUB_CLIENT_ID | GitHub OAuth app client id |
GITHUB_CLIENT_SECRET | GitHub OAuth app secret |
WEBHOOK_ENCRYPTION_KEY | 32-byte base64 webhook URL encryption key |
Manual deploy environment:
| Secret | Purpose |
|---|---|
CLOUDFLARE_ACCOUNT_ID | Cloudflare account id |
CLOUDFLARE_API_TOKEN | API token with D1 edit and Worker deploy access |
D1_DATABASE_ID | Production D1 database UUID |
Deployment variables:
| Variable | Default | Notes |
|---|---|---|
TOKENBOARD_WORKER_ROUTE | required | production custom domain host |
BETTER_AUTH_URL | required | canonical https://... origin |
TOKENBOARD_DAILY_REPORT_HISTORY_DAYS | 30 | 1 to 31 |
TOKENBOARD_COLLECTOR_REPO_URL | required | GitHub repository used in generated collector install prompts |
TOKENBOARD_COLLECTOR_REF | required | branch/ref used in generated collector install prompts |
TOKENBOARD_WEBHOOK_LOG_RETENTION_DAYS | 90 | 1 to 365 |
TOKENBOARD_WEBHOOK_CRON_BATCH_SIZE | 5 | 1 to 5 due subscriptions per tick |
TOKENBOARD_USAGE_SUMMARY_BACKFILL_LIMIT | 50 | 1 to 500 summary keys per cron tick |
TOKENBOARD_USAGE_SUMMARY_STRICT | false | set true only after summary backfill completes |
Set TOKENBOARD_COLLECTOR_REPO_URL and TOKENBOARD_COLLECTOR_REF explicitly when the deployed install
prompt must use a different repository or ref.
wrangler.production.example.jsonc is the production template. Copy it to the ignored
apps/web/wrangler.production.jsonc, fill the route, auth origin, and D1 database id, then run
pnpm run deploy.
Production config validation requires:
workers_dev: falseBETTER_AUTH_URL*/15 * * * * notification cron triggerFor production recovery after code was deployed without its D1 migrations, follow
docs/reviews/UPSTREAM-PRODUCTION-RECOVERY-2026-07-16.md.
Cron times are UTC. User-facing report times are evaluated against each subscription's configured timezone.