Skip to content

Write usage to a ledger other programs can read - #7

Merged
stawan15 merged 1 commit into
mainfrom
feat/usage-ledger
Nov 1, 2026
Merged

stawan15 merged 1 commit into
mainfrom
feat/usage-ledger

Conversation

@stawan15

@stawan15 stawan15 commented Nov 1, 2026

Copy link
Copy Markdown
Owner

Cost and tokens were counted in memory and nowhere else: e.cost was added up per response and shown in the sidebar, then lost when the app exited. Nothing outside a running teveus could report what a session cost, so a menu bar monitor, a script or a spreadsheet had nothing to read.

Each billed response now appends one JSON line to ~/.config/teveus/usage.jsonl:

{"time":"2026-11-01T05:04:17.798825Z","id":"20261101050417.798825000-api-abc","session":"api-abc","provider":"anthropic","model":"claude-sonnet-5","project":"app","cwd":"/Users/me/app","input":12,"output":340,"cacheRead":29570,"cacheWrite":9140,"cost":0.0342,"subagent":false}
  • Append-only, so a reader can follow it live without re-reading a whole file.
  • In the config directory, so TEVEUS_CONFIG moves it with everything else.
  • Write errors are swallowed on purpose: the ledger is for reporting, and a read-only config directory must not fail a conversation.
  • History compaction is recorded too. It is a billed request like any other and was previously counted in e.cost but invisible everywhere else.

UsageRecord in internal/agent/usage.go is a contract now that another program reads it, so usage_test.go pins the field names and the shape rather than only the arithmetic.

Why this shape

Field names are lowerCamelCase to match what JSON consumers expect, and model keeps teveus's provider/model-id form while provider is split out beside it. A consumer that needs a bare model id can take the last path segment; one that wants the router can read provider.

Verification

  • go build ./..., go vet, gofmt clean; full go test ./... passes.
  • Round-tripped end to end: generated a real ledger from the engine and parsed it back.

The reader side is the claude-monitor menu bar app, which shipped this in Claude-Usage-Monitor v0.1.2. It shows nothing for older teveus, which writes no ledger.

Cost and tokens were counted in memory and nowhere else: e.cost was added
up per response and shown in the sidebar, then lost when the app exited.
Nothing outside a running teveus could report what a session cost, so a
monitor, a script or a spreadsheet had nothing to read.

Each billed response now appends one JSON line to
~/.config/teveus/usage.jsonl with the model, the project, the four token
counts and the provider's own cost when it reports one. It is append-only
so a reader can follow it live, and it lands in the config directory, so
TEVEUS_CONFIG moves it along with everything else.

History compaction is recorded too. It is a billed request like any other
and was previously counted in e.cost but invisible everywhere else.

Write errors are swallowed on purpose: the ledger is for reporting, and a
read-only config directory must not fail a conversation.
@stawan15
stawan15 merged commit 1a70b63 into main Nov 1, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant