Skip to content

alpertarhan/pi-tracker

Repository files navigation

pi-tracker

Model usage analytics for pi

Track token & cost usage by model, project, and session — daily / weekly / monthly / 6-monthly / yearly — in an interactive TUI dashboard. Optional budgets fire a warning when a threshold is crossed.

CI License: MIT PRs welcome


What it does

pi-tracker is a pi extension that turns every assistant turn into a record and gives you a live, drill-down analytics view:

  • Capture — every finalized assistant message (message_end) is logged with its token breakdown and cost.
  • Pivot — group by model, project, or session, across 6 time windows.
  • Drill down — pick a model to see which projects use it, then which sessions, then back up. A breadcrumb keeps your bearings.
  • Budgets — set token/cost limits per scope & period; get warned at a threshold and again when exceeded.
  • Back-fill — import your full pi session history on day one so you start with real data, not an empty log.

The dashboard

pi-tracker — Model usage
window: All Time  •  37 model(s)  •  filter: —

  Model                       usage                 tokens         cost       turns
  ──────────────────────────────────────────────────────────────────────────────────
▶ anthropic/claude-opus-4-8   ████████████████████  1,844,364,365  $2388.42   6155
  openai-codex/gpt-5.5        ██░░░░░░░░░░░░░░░░░░  1,212,486,248  $2096.32   10475
  zai-anthropic/glm-5.2       ████████████████████  14,798,725,266 n/a        4621
  ──────────────────────────────────────────────────────────────────────────────────
  Total                                              17,855,575,879 $4484.74   21251

[1-6] window  [d] dimension  [enter] drill in  [u] back  [↑↓] move  [q] close

n/a = that provider didn't return pricing (e.g. a model without published costs), not $0.

Install

pi-tracker is a pi package. Install it with pi directly:

pi install npm:pi-tracker

Or, from source (for development):

git clone git@github.com:alpertarhan/pi-tracker.git
cd pi-tracker && npm install
ln -s "$(pwd)" ~/.pi/agent/extensions/pi-tracker

Restart pi (or /reload) and run /analytics. Then back-fill your history:

/analytics import

That scans ~/.pi/agent/sessions/ and recovers all past usage (idempotent — safe to re-run).

Commands

/analytics [today|week|month|6months|year|all]

Opens the interactive dashboard. Keys:

Key Action
16 switch window (today / week / month / 6mo / year / all)
d cycle grouping dimension (model / session / project)
move cursor (auto-scrolls)
enter drill into the cursor row — pivot to the next dimension
u / backspace pop the last filter (go back up a level)
q / esc close

/analytics import

Back-fill analytics from pi session history. Idempotent.

/budget

View configured budgets. Add new ones two ways:

  • Interactive (TUI): /budget add — SelectList flow.
  • Args: /budget add <scope> <period> <metric> <max> [warn]
scope:  global | session | project   (project uses the current cwd)
period: day | week | month | year
metric: cost | tot | in | out
max:    positive number (USD if metric=cost, else tokens)
warn:   fraction 0..1, default 0.8

How it works

  • Data source — the message_end event is the only place token usage appears (event.message.usage). after_provider_response has only HTTP status.
  • Storage — append-only JSONL. O(1) write, zero dependencies, crash-safe. An in-memory accumulator (rebuilt once per session, updated incrementally) keeps per-message budget checks O(budgets) instead of O(log).
  • Cost awareness — each record tracks whether the provider returned pricing (costKnown). A model row shows n/a when none of its turns had pricing, and $ as soon as any does.
~/.pi/agent/analytics/
├── usage.jsonl   append-only raw log (one record per assistant message)
├── budgets.json  budget limit config (optional)
└── warned.jsonl  append-only dedup keys for fired warnings (resets per period)

Architecture

Clean, layered, dependency-injected — dependencies point inward only:

src/
  domain/        pure rules — ZERO dependencies (no fs, no pi)
    types.ts       data contracts (UsageRecord, BudgetLimit, …)
    time.ts        periodKey / windowStartMs / isoWeekKey
    aggregate.ts   aggregate / sumRows / dimensionKey
    budget.ts      budgetKey / statusForLimit / recordMatchesLimit
    enums.ts       DIMENSIONS / WINDOWS
    format.ts      fmtNum / fmtCost / fmtBar / padRight
    session-parser.ts  parse pi session history → UsageRecords
  storage/       infrastructure — implements the ports
    ports.ts       UsageStore + ConfigStore interfaces (total, never throw)
    jsonl-store.ts concrete JSONL/file adapter (real fs)
    memory-store.ts in-memory fake (tests)
  app/
    accumulator.ts in-memory read-side cache (takes UsageStore)
  ui/
    dashboard.ts   pure view — data injected, NO I/O during render, drill-down
    budget-add.ts  interactive /budget add flow (SelectList)
pi-tracker.ts     composition root — wires pi events to the layers (DI seam)
index.ts          re-exports factory for pi's dir-based discovery

There's a check:layers guard that enforces this in CI.

Why this shape: the domain layer has no deps, so it's unit-tested directly; storage is exercised through ports with an in-memory fake (no disk); the view never touches storage during render; every storage method is total (never throws) so a disk fault can't crash pi.

Development

npm install
npm test                # unit tests (pure domain + store fake)
npm run typecheck       # typecheck (strict + unused checks)
npm run check:layers    # architectural layer guard
npm run smoke           # runtime smoke (DI + capture + render)
npm run ci              # all of the above (what CI runs)

See CONTRIBUTING.md for the full guide.

Community

Contributions are very welcome! 🎉

Please note this project has a Code of Conduct. By participating you agree to abide by its terms.

License

MIT © Alper Tarhan

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors