{"slug": "i-could-measure-claude-and-codex-usage-i-still-couldn-t-honestly-assign-it-to-a", "title": "I Could Measure Claude and Codex Usage. I Still Couldn't Honestly Assign It to a Task.", "summary": "A developer built agent-cost, a tool that measures Claude Code and Codex CLI usage while keeping session measurement and task attribution separate. The tool reads local logs, normalizes usage events into auditable facts, and makes no network calls at runtime. It deliberately avoids inferring tasks from branches or timestamps, leaving unattributed usage as unknown rather than manufacturing precise allocations.", "body_md": "Once you use Claude Code or Codex for real work, a total usage number stops being enough. You want to know which change consumed it.\n\nI did not build `agent-cost`\n\nbecause I had missed the existing token and cost trackers. I knew about multi-agent reporting CLIs, local dashboards, and OpenTelemetry-style observability stacks. I had even built a similar view in Notion before.\n\nThe problem appeared when I tried to use that kind of reporting in an operational workflow. I needed agent logs to stay on the machine. I wanted a small runtime dependency surface, custom metrics I could audit, and a machine-readable result that another tool could consume. Most importantly, I needed session measurement and task attribution to remain two different claims.\n\nI did not need another universal dashboard. I needed a boundary underneath the dashboard that could answer: is this number supported well enough to enter task accounting?\n\nDifferent tools optimize for different jobs. A broad CLI such as `ccusage`\n\nis useful when coverage across agents matters. Local interfaces such as `token-tracker`\n\nor `AgentMeter`\n\nare a better fit for visual exploration of projects, sessions, subagents, and tools. An OpenTelemetry stack is the natural choice for fleet-level metrics, logs, and traces.\n\nThose are not inferior versions of `agent-cost`\n\n. They serve different use cases and trust models.\n\nThe layer I wanted looked like this:\n\n``` php\nlocal observations\n  -> auditable normalized facts\n  -> explicit pricing status\n  -> caller-selected sessions\n  -> task-attribution policy\n  -> optional dashboard / Notion / spec-lane\n```\n\n`agent-cost`\n\nreads logs that Claude Code and Codex CLI have already written locally. It normalizes each usage event into a fact with a model, token kind, timestamp, and count. At runtime it makes no network calls and declares no Python runtime dependencies. Its price catalog has a version and SHA-256 digest, both carried into machine-readable output.\n\nThat “zero-network” claim is deliberately limited to runtime behavior. Installing from PyPI still means trusting a registry, installer, build backend, Python runtime, and operating system. The tool also needs access to the source logs. The design narrows runtime data egress and dependency surface; it does not make the supply chain disappear.\n\nThere is an attractive shortcut when building task-level cost reports:\n\nThis always produces numbers that add up. But the agreement comes from the allocation rule, not from an observation.\n\nOne session can cover several tasks. One task can span several sessions. A branch can stay unchanged while the operator investigates a different issue or reviews someone else's work. Elapsed time does not describe the computational weight of prompts and tool calls.\n\nThe invariant I wanted was:\n\nSession usage is observable. Session-to-task attribution is a separate claim.\n\n`agent-cost measure`\n\naccepts only session IDs selected by its caller:\n\n```\nagent-cost measure \\\n  --session-id <session-a> \\\n  --session-id <session-b> \\\n  --format json\n```\n\nIt does not infer a task from a branch, pull request, or timestamp. A workflow that already owns the task-to-session binding passes the corresponding session set.\n\nFor example, the `spec-lane`\n\nadapter invokes `agent-cost`\n\nas a subprocess and checks the JSON, the `measure/v1`\n\nprotocol version, the schema, and forbidden personal dimensions. `agent-cost`\n\ndoes not learn what the task is. The caller that knows the task selects the sessions.\n\nIf a session crosses tasks and there is no defensible way to split it, I would rather leave that usage unattributed than manufacture a precise-looking allocation. Unknown is pending evidence, not zero.\n\n`agent-cost`\n\ncarries uncertainty instead of smoothing it away.\n\nAn unknown model is `unpriced`\n\n. A Claude cache write without a TTL breakdown is priced at the cheaper five-minute rate and labeled `lower_bound`\n\n. Codex logs do not expose cache-write tokens, so the tool does not invent a zero-valued cache-write row. Malformed events, unreadable files, and decreasing cumulative counters remain visible in `data_quality`\n\n.\n\n“Fail closed” does not mean every imperfect input crashes the command. It means unsupported pricing or attribution does not quietly become a confirmed value downstream.\n\nOn August 23, 2026, I reran the published `coding-agent-cost 0.1.0`\n\npackage in temporary `uvx`\n\ndirectories. Its doctor command found the local sources and loaded catalog version `2026-07-29`\n\n. The explicit unknown-model path still rejected a made-up model:\n\n``` bash\n$ uvx --refresh --from coding-agent-cost \\\n    agent-cost rates show --model model-not-in-catalog\n[unpriced] no rate entry for 'model-not-in-catalog'\n```\n\nA numeric zero next to an unpriced row is not a claim that the usage was free. Consumers must inspect `pricing_status`\n\nand `unpriced_tokens`\n\n, then choose a policy: exclude the value from a headline, stop the workflow, or supply a verified catalog.\n\nThe output field is `estimated_cost_usd`\n\n, not a bill. Allowances, contracts, credits, and batch usage are not fully recoverable from local logs. The number is a list-price estimate attached to observed tokens.\n\nThere are intentional limits. `agent-cost`\n\nalone will not label a session as belonging to an issue. Local execution does not remove installation-time supply-chain risk or the need to trust local log access.\n\nIn exchange, each layer has a narrower claim:\n\n`unpriced`\n\nor `lower_bound`\n\n.This is not an argument against dashboards. Use a dashboard when visual exploration is the job. Use OpenTelemetry when fleet observability is the job. Use a small accounting primitive when you need a subprocess contract and want measurement to remain separate from attribution policy.\n\nKeeping an unknown visible is not a failure to measure. It is how the next layer avoids false confidence.\n\nStart with the 60-second path in [ agent-cost](https://github.com/shiki-yusuke/agent-cost). If you also need a workflow to own task attribution, see\n\n`spec-lane`", "url": "https://wpnews.pro/news/i-could-measure-claude-and-codex-usage-i-still-couldn-t-honestly-assign-it-to-a", "canonical_source": "https://dev.to/shikiyusuke/i-could-measure-claude-and-codex-usage-i-still-couldnt-honestly-assign-it-to-a-task-2ghj", "published_at": "2026-08-22 21:20:35+00:00", "updated_at": "2026-08-22 21:43:18.667200+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "ai-infrastructure"], "entities": ["Claude Code", "Codex", "agent-cost", "ccusage", "token-tracker", "AgentMeter", "OpenTelemetry", "PyPI"], "alternates": {"html": "https://wpnews.pro/news/i-could-measure-claude-and-codex-usage-i-still-couldn-t-honestly-assign-it-to-a", "markdown": "https://wpnews.pro/news/i-could-measure-claude-and-codex-usage-i-still-couldn-t-honestly-assign-it-to-a.md", "text": "https://wpnews.pro/news/i-could-measure-claude-and-codex-usage-i-still-couldn-t-honestly-assign-it-to-a.txt", "jsonld": "https://wpnews.pro/news/i-could-measure-claude-and-codex-usage-i-still-couldn-t-honestly-assign-it-to-a.jsonld"}}