Using AgentDock
Usage, cost and budgets
API-equivalent cost per run, model and project, and limits that stop new spend.
AgentDock records the tokens of every LLM request your agents make and prices them, so you can see spend per run, model, project, issue and slot. Budgets then put a limit on that spend and refuse new work when it is used up.
AgentDock does not bill anything and takes no payments. Every dollar figure is API-equivalent cost: what the recorded tokens would cost at public API prices, even when your agents run on a Claude or ChatGPT subscription. It is the one number you can compare across runtimes, models and months. Your actual invoice comes from your provider.
What is recorded
Each LLM request is stored with its model, duration, stop reason and token counts in six buckets. Every token is in exactly one bucket:
| Bucket | Meaning |
|---|---|
input | Uncached input tokens |
output | Output tokens |
cacheRead | Input tokens read from the prompt cache |
cacheWrite5m | Tokens written to the 5-minute cache |
cacheWrite1h | Tokens written to the 1-hour cache |
reasoning | Thinking tokens. These are part of output and never counted twice |
Only metadata is stored: no prompt, response or tool input and output text. See What is stored.
Where the numbers come from
- OpenTelemetry, live. The runner listens for OTLP/HTTP logs on
127.0.0.1:4318and turns eachclaude_code.api_requestrecord into a request as it happens. Connections from anything but loopback are refused. - Transcripts, for everything else. The runner tails Claude Code session transcripts (
projects/**/*.jsonlin each profile's config directory) and backfills what telemetry did not cover. When both report the same request, it is stored once, and the transcript fills the fields telemetry lacks (such as the 5-minute versus 1-hour cache split and reasoning tokens).
Skill runs that AgentDock launches turn telemetry on by themselves. Other sessions are picked up from their transcripts, so they also appear, a little later. To get live numbers from a session you start by hand on a runner machine:
CLAUDE_CODE_ENABLE_TELEMETRY=1 \
OTEL_LOGS_EXPORTER=otlp \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318 \
OTEL_RESOURCE_ATTRIBUTES=agentdock.project=<id>,agentdock.slot=<slot>,agentdock.issue=<n>,agentdock.run=<run> \
claudeThe agentdock.* attributes are optional. Without them, the request is matched to its session by session id, and the session to a project by its working directory.
The runtime's own cost_usd figure is kept for reference but never added up: AgentDock prices tokens itself.
Codex sessions are listed, but their transcripts are not parsed yet, so they carry no tokens and no cost. Mapping Codex telemetry is behind otlp.codexExperimental in runner.json (default false) because its attribute names are not verified. Treat Codex spend as missing from every total and budget.
Prices
Prices live in versioned tables under Admin → Prices.
- Each model price has a case-insensitive regex
matchPatternagainst the model id, a priority, and tiers. A tier can have conditions, for example a long-context price above 200k input tokens. - Version 1 is seeded from Langfuse's public model price file (MIT, with attribution) when the database is set up.
- Editing a price creates a new version; old versions are never changed in place. The newest version is current.
- Cost is computed when a request is stored, with the current version, and saved with the version it used.
- A bucket without its own price falls back: reasoning to output, 1-hour cache writes to 5-minute cache writes, cache writes and reads to input.
The Prices page also has a test calculator for checking a model id and token counts against the table.
Unpriced requests
A request whose model matches no pattern gets no cost. It is shown as unpriced, never as $0, and the Usage page counts how many there are. An admin fixes it by adding the model under Admin → Prices.
Re-pricing
Prices change and models get added after the fact. Admin → Prices → Re-price requests recomputes a date range with a chosen version, in background batches (USAGE_RECOMPUTE_BATCH, default 1000), and rebuilds the hourly rollups. One re-price runs at a time. Afterwards, Admin → Budgets → Recompute budget totals brings budget periods in line.
The Usage screen
Open Usage in the navigation.
- Range:
24h,7d,30dor a custom From / To. - Project: one project or all of yours. Time zone sets how days are grouped.
- Tiles for API-equivalent cost, Requests, Tokens and Unpriced requests over the range.
- A cost-over-time chart, stacked by runtime.
- A breakdown table by Project, Model, Runtime, Issue or Slot.
You see usage only for projects you are a member of. Sessions with no project, such as a person's own claude in an unrelated folder on a runner machine, are admin-only and show as "No project (machine-wide)".
Cost also shows per run in Project → History and per slot in the Fleet slot sheet.
Sessions
Sessions lists every agent session you can see: started, project and slot, runtime, models, turns, requests, tokens (input / output / cache), cost and duration. Filter by project, runtime, model, slot and date.
A session's page is a tree with a waterfall: the session, its turns, and under each turn the LLM requests, tool calls (by name and duration only) and subagent sessions, with time bars and totals per node. It is the place to find which turn or subagent burned the tokens.
Budgets
A budget caps the API-equivalent spend of a project or a user per period. Create one under Admin → Budgets → New budget or in Project → Settings → Budget.
| Field | Values |
|---|---|
| Scope | project or user |
| Period | day, week (starts Monday) or month |
| Timezone | IANA name; default APP_TIMEZONE, else UTC |
| Limit (USD) | In API-equivalent dollars |
| Thresholds (%) | Default 50, 80, 100. 100 is always included |
| When the limit is reached | alert or stop |
There is at most one enabled budget per scope and period. Periods reset by themselves in the budget's timezone.
What counts
- Project spend: every priced request whose session belongs to the project: fleet workers, the orchestrator, skill runs, and sessions people start in the project folder.
- User spend: skill runs the user started, and an orchestrator the user started from the Fleet page. Fleet workers, scheduled runs and webhook-triggered runs count toward the project only, because nobody started them by hand.
- Unpriced requests count as zero and are shown next to the budget as "N unpriced requests".
Thresholds and notifications
Each threshold notifies once per period: budget.threshold below 100%, budget.exceeded at 100%. A project budget notifies the project's operators and admins; a user budget notifies the user and admins. Both go in-app and to Telegram by default. See Notifications.
Stop means no new spend
With action stop, an exceeded budget refuses new work for its scope with 409 budget_exceeded, naming the budget and when it resets:
- new skill runs (manual, scheduled or triggered);
- Start… with
startornexton the Fleet page, and scheduled orchestrator rounds.
It does not kill anything. Running workers and a running orchestrator keep going. Killing a worker mid-edit would leave a half-written branch that the orchestrator later resumes at full cost, and killing the orchestrator would stop merges of work you already paid for. If you want a harder stop, use Stop and Stop slot on the Fleet page. The Fleet page shows a banner while a budget is used up.
Overrides
An admin can lift a stop for the rest of the current period with Override budget: an end time (no later than the period end) and a required reason. Starts are allowed while the override lasts; thresholds still notify. Overrides do not carry into the next period.
Every budget change, enable, disable and override is audited with before and after values.
Who manages budgets
| Budget | Edit | View |
|---|---|---|
| Project | Admins | Operators of the project |
| User | Admins | The user it applies to |