Show my usage and my leaks

Tokens by session, worker and model, the bytes crush kept off the wire, and the habits that waste them.

Prompt#

Show me what this workspace is spending, and where I'm leaking context.

What the Chair does#

Reads the local ledger — no provider call — and prints spend by seat, then the leak telemetry that names the wasteful habit.

MCP calls#

usage_status({ "recent": 10 })
usage_status({ "view": "leaks" })
usage_status({ "view": "governance" })
usage_status({ "view": "workers" })

CLI, for the human-readable version:

orch usage                      # table: by session, by worker, by model
orch usage --format json --limit 10
orch usage --leaks              # rereads, repeated calls, oversized results, silent streaks
orch usage --leaks --format json
orch usage --governance         # conflict_rate / duplicate_rate per session
orch usage --workers            # wall time, status, files, guardrails, tool calls, tokens, cost by session
orch usage --export jsonl       # one gen_ai.*-keyed JSON line per session and per tool row
orch gateway status             # live/cooldown, ring position, rotations per provider

Expected response#

usage_status takes an optional view: summary (default), leaks, governance, workers or perf; an unknown value errors with view must be summary|leaks|governance|workers|perf. Those five are the whole list — the per-tool counters live in the cli_tool_usage table, which view: workers reads; cli_tool_usage is not itself a view.

  • view: summary (or omitted) returns summary, saved_pct, total_bytes_saved, by_session[], by_worker[], by_model[], agents[], counters[]. Every breakdown row is {key, attempts, prompt_tokens, completion_tokens, bytes_saved}. A graph block carries what code_snippet and trace_path returned against the size of the files they stood in for.
  • It also returns by_worker_cli[]: tokens read straight out of a worker CLI's own output — agy and claude's --output-format json result, cursor-agent's own usage block, or copilot's Tokens ↑/↓ summary line — for a CLI that never crosses the gateway at all. Once parsed, these same tokens are folded into summary, agents[], counters[] and by_session[] too — a BYO-auth CLI worker shows up in the headline numbers, not only in by_worker_cli. cli_usage_unavailable[] lists every session that has no parsed row, and why (usage block empty for a known CLI, no parser for this agent/CLI otherwise) — a parser that reads every counter as zero is treated as no row at all, never printed as a measurement.
  • view: leaks returns the same content-free rows as orch usage --leaks, keyed by session (reread_files, repeated_calls, large_results, silent_streaks).
  • view: governance returns {sessions[], pairs[]} — the same conflict/duplicate metrics as orch usage --governance, plus pairwise conflicts.
  • view: workers returns {sessions[], tools[]}: one row per session naming every dimension worker statistics get rolled up by — session_id, agent_id (worker), task_id, project, day, plus status, duration_ms, files_changed, guardrails, tool_calls/tool_errors/tool_time_ms, measured tokens (input_tokens, output_tokens, cache_read_tokens, cache_write_tokens), cost_usd and source (which CLI's log the tokens came from, or "" when none was ever parsed for that session — never shown as zero tokens). tools[] is the per-tool breakdown across every session: session_id, tool_name, call_count, success_count, error_count, total_time_ms — this is how you find which tool ate the budget, counted by the orch MCP server itself for every tools/call it serves, independent of what the calling CLI prints.

Daily budgets#

orch.yaml can cap measured tokens per local day, optional and off unless set:

budget:
  workspace_tokens_per_day: 2000000   # whole project, all seats — 0/unset = unlimited
  seat_tokens_per_day: 500000         # one dispatching agent id — 0/unset = unlimited
  warn_at: 0.8                        # fraction of the cap that adds a note instead of denying (default 0.8)

Both caps sum today's (local day) cli_session_usage — input + output + cache-write tokens — the same measured numbers orch usage --workers prints. A dispatch at or over either cap is denied before the agent ever starts, from both orch dispatch and the dispatch_worker MCP tool:

budget: seat exhausted (used 512000 of 500000 tokens today) — raise budget.* in orch.yaml or wait for the daily reset

Short of the cap but past warn_at, the dispatch still runs and the reply carries a budget_note (MCP) or prints the note before the run (CLI) instead of silently spending past it. orch budget status [--project P] [--format json] prints today's used/cap for the workspace and for every seat that spent tokens today, with no dispatch involved.

Gotchas#

  • It is content-free, so you can paste it to a human. The gateway ledger stores counts, never prompts. orch gateway status is content-free too: no keys, no bodies.
  • Leaks and governance are also over MCP. usage_status({ "view": "leaks" }) and usage_status({ "view": "governance" }) return the same rows as the CLI flags — no shell needed.
  • cache_hits is spend avoided, not spend. A request the gateway answered from its exact-match cache carries X-Orchemax-Cache: hit and is not counted as an upstream attempt. Read saved and spent as two columns, never as one net number.
  • The cache is off by default. gateway.cache.ttl_sec is 0 unless you set it, and streaming is never cached — so cache_hits: 0 usually means "not enabled", not "never hit".
  • Only traffic through the gateway is counted in summary/by_session/ by_worker/by_model. A preset on agents.auth.<preset>: account — Claude Code on its own plan login, codex and cursor by default — routes no model traffic here, so it shows attempts but not provider tokens. by_worker_cli[] is how those same BYO-auth workers still show measured tokens: read from the CLI's own log instead of the gateway.
  • by_worker_cli numbers are as precise as the CLI that printed them. agy, claude and cursor-agent report exact counts; copilot's terminal summary is rounded to one decimal on a "k" suffix (168.1k → 168100), so treat it as approximate, never as an exact count. A rounded measurement is still a measurement, not a claim.
  • token_coverage.status is measured, partial or unavailable, never a guess. measured once every session with a known CLI has a non-zero usage row; partial while some do and some don't — token_coverage.unmeasured[] names which sessions and why; unavailable when nothing has ever been measured at all (no gateway attempt, no transcript hook, no parsed CLI log).
  • recent (MCP) and --limit (CLI) are the same idea: attach the N most recent attempts. Leave it out for the aggregate only.
  • by_worker_cli/workers now carry cache_write_tokens next to cache_read_tokens. claude's --output-format json already printed cache_creation_input_tokens; it is now parsed and stored, not discarded. agy and copilot do not report a cache-write figure, so their rows keep it at 0 — not measured, not estimated.
  • orch usage --export jsonl is stdlib-only, no OTel dependency. One JSON line per session (orch.source: "session") and one per session/tool pair (orch.source: "tool"), keyed gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, gen_ai.usage.cache_read.input_tokens, gen_ai.usage.cache_write.input_tokens, gen_ai.tool.name, gen_ai.agent.name, orch.session, orch.project, orch.cli, orch.source — every key present on every line, numbers only from what was actually measured. Any OTLP-HTTP/JSONL collector ingests it as-is.
  • What the leak columns mean: rereading a file you already read, calling the same tool with the same arguments, returning results too big to be useful, and long silent streaks. Each one has a cheaper move in Stop reading whole files.