Files
time/time/ledger/README.md
teahubxyzandClaude Opus 5.5 ec043b2985
ci / test (push) Successful in 36s
Adaptive budget: pace spend to each capacity pool (re-cut of #167 onto main) (#174)
Adaptive budget: pace spend to each capacity pool (#174, re-cut of #167)

The worker's #82 change (sonnet via Time): budget_check(route) paces each call to its capacity pool in
time/pools.json (expiring credit spread over the days left, refilling windows, or TIME_DAILY_USD without a pool);
the monthly cap stays hard. pools.json is read through the API once per run, since every workflow checks out only
.github/time. Ships empty: nothing changes until it is filled in. Closes #82.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
2026-10-19 01:10:09 +00:00

2.4 KiB

Spend ledger

Time keeps a record of what it spends on models. This folder holds it.

  • One file per month: time/ledger/<YYYY-MM>.jsonl, for example 2026-10.jsonl.
  • One JSON line per model call. Fields:
    • at: when the call was made, ISO 8601 in UTC (2026-10-14T09:30:00Z).
    • model: the model that was called.
    • in: input (prompt) tokens.
    • out: output (completion) tokens.
    • pool: the provider the call booked to (anthropic, venice); time/pools.json maps it to a capacity pool.
    • usd: the cost in US dollars, or null if the seat has no price (unpriced seats).

Example line:

{"at":"2026-10-14T09:30:00Z","model":"some-model","in":1200,"out":350,"usd":0.0123}

Who writes and reads it

  • Written by Time itself. At the end of each run, Time appends that run's calls to the current month's file in one ledger: commit.
  • Read before every model call. Whichever workflow is about to call a model (heartbeat, mentions, venture loop, Astra) adds up usd for today and for the month and refuses the call if either total has reached its cap (TIME_DAILY_USD, TIME_MONTHLY_USD). A null counts as zero.

When a cap trips

Time stops calling models. The next time the heartbeat has a card to run, it opens one issue labelled andon (never a second while that one is open). A monthly cap also switches TIME_MODE to dry-run, or says in the issue that it couldn't, until a human raises the cap. A daily cap clears itself at midnight UTC. Close the issue once it is handled.

Don't edit it by hand

Humans should never edit these files. The caps rely on them being exact, and Time only ever appends. A hand edit can hide spend or break the next append.

Pools (time/pools.json)

The operator keeps one entry per capacity pool; a route with no entry is paced by TIME_DAILY_USD. Time reads the file through the API once per run. Fields: name, kind, routes, and by kind:

  • expiring: balance_usd (as of as_of, a date), resets_at (the date the credit lapses). Allows (balance - spent since as_of) / days to resets_at x TIME_PACE a day.
  • window: window_usd, resets_at as weekly:mon or hours:5. Allows window_usd per window.
  • balance: balance_usd. Allows TIME_DAILY_USD a day.
[{"name": "anthropic-credits", "kind": "expiring", "balance_usd": 30, "as_of": "2026-10-19", "resets_at": "2026-10-29", "routes": ["anthropic"]}]