Add token usage tracking and punch stats command (Phase 4a)#21
Conversation
- Add per-model and per-fighter usage breakdown queries to punch-memory - Add MeteringEngine methods for period-based breakdown queries - Add GET /api/stats and GET /api/stats/fighters/:id API endpoints - Add `punch stats` CLI command with period and fighter filtering - Formatted table output with token counts, costs, and request counts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d18288f3f4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return 1; | ||
| } | ||
|
|
||
| let base_url = match daemon_url(None) { |
There was a problem hiding this comment.
Honor --config when resolving stats daemon URL
punch stats ignores the global config override because it hardcodes daemon_url(None), so the command always reads ~/.punch/config.toml even when the user passed --config <path>. In environments where the daemon is started from a non-default config (different api_listen), punch stats will incorrectly report that the daemon is not running or query the wrong instance.
Useful? React with 👍 / 👎.
| let fighter_name = fighters | ||
| .iter() | ||
| .find(|(fid, _, _)| *fid == fighter_id) | ||
| .map(|(_, m, _)| m.name.clone()) | ||
| .unwrap_or_else(|| "unknown".to_string()); |
There was a problem hiding this comment.
Return 404 when fighter stats target is unknown
The fighter stats handler silently substitutes "unknown" when the fighter ID is not present in the ring and still returns 200, which makes invalid IDs look like valid fighters with zero usage. This is especially misleading when --fighter is given as a UUID (it bypasses name resolution and hits this path directly), so callers cannot reliably distinguish typo/nonexistent IDs from real data.
Useful? React with 👍 / 👎.
Summary
GET /api/statsandGET /api/stats/fighters/:idAPI endpoints returning token counts, costs, and per-model/per-fighter breakdownspunch statsCLI command with--period(hour/day/month) and--fighter(name or ID) flagsExample output
Test plan
punch statsshows correct dataGenerated with Claude Code