I Could Measure Claude and Codex Usage. I Still Couldn't Honestly Assign It to a Task.

I Could Measure Claude and Codex Usage. I Still Couldn’t Honestly Assign It to a Task.

我可以衡量 Claude 和 Codex 的使用量,但仍无法诚实地将其分配给特定任务。

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. I did not build agent-cost because 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. 一旦你开始将 Claude Code 或 Codex 用于实际工作,单纯的总使用量数字就不再足够了。你想知道是哪项变更消耗了这些资源。我开发 agent-cost 并不是因为我错过了现有的 Token 和成本追踪工具。我了解多智能体报告 CLI、本地仪表板以及 OpenTelemetry 风格的可观测性堆栈。我甚至以前在 Notion 中构建过类似的视图。

The 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. I 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? 当我尝试在操作工作流中使用这类报告时,问题出现了。我需要智能体日志保留在本地机器上。我希望运行时依赖面尽可能小,需要可审计的自定义指标,以及能被其他工具消费的机器可读结果。最重要的是,我需要将“会话衡量”与“任务归因”作为两个独立的声明。我不需要另一个通用仪表板,我需要的是仪表板之下的一个边界,它能回答:这个数字是否有足够的支撑证据进入任务核算?

A measurement layer below the UI. Different tools optimize for different jobs. A broad CLI such as ccusage is useful when coverage across agents matters. Local interfaces such as token-tracker or AgentMeter are 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. Those are not inferior versions of agent-cost. They serve different use cases and trust models. UI 之下的衡量层。不同的工具针对不同的工作进行优化。当需要覆盖多个智能体时,像 ccusage 这样广泛的 CLI 非常有用。像 token-tracker 或 AgentMeter 这样的本地界面更适合对项目、会话、子智能体和工具进行可视化探索。OpenTelemetry 堆栈是集群级指标、日志和追踪的自然选择。这些并不是 agent-cost 的劣质版本,它们服务于不同的用例和信任模型。

The layer I wanted looked like this: local observations -> auditable normalized facts -> explicit pricing status -> caller-selected sessions -> task-attribution policy -> optional dashboard / Notion / spec-lane. 我想要的层级结构如下:本地观察 -> 可审计的标准化事实 -> 明确的定价状态 -> 调用者选择的会话 -> 任务归因策略 -> 可选的仪表板 / Notion / spec-lane。

agent-cost reads 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. That “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. agent-cost 读取 Claude Code 和 Codex CLI 已经在本地写入的日志。它将每个使用事件标准化为一个包含模型、Token 类型、时间戳和计数的事实。在运行时,它不进行任何网络调用,也不声明任何 Python 运行时依赖。其价格目录具有版本号和 SHA-256 摘要,两者都会被带入机器可读的输出中。“零网络”声明特意仅限于运行时行为。从 PyPI 安装仍然意味着需要信任注册表、安装程序、构建后端、Python 运行时和操作系统。该工具还需要访问源日志。这种设计缩小了运行时数据出口和依赖面,但并没有让供应链风险消失。

A session is observable. A task is another claim. There is an attractive shortcut when building task-level cost reports: Measure usage in a time window. Find the issues or branches active during that window. Apportion the total by working time or commit count. This always produces numbers that add up. But the agreement comes from the allocation rule, not from an observation. One 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. 会话是可观察的,而任务是另一种声明。在构建任务级成本报告时,有一个诱人的捷径:衡量时间窗口内的使用量,找出该窗口内活跃的问题或分支,然后按工作时间或提交次数分摊总额。这总能得出加总相符的数字,但这种一致性源于分配规则,而非观察结果。一个会话可能涵盖多个任务,一个任务也可能跨越多个会话。当操作员调查其他问题或审查他人工作时,分支可能保持不变。流逝的时间并不能描述 Prompt 和工具调用的计算权重。

The invariant I wanted was: Session usage is observable. Session-to-task attribution is a separate claim. agent-cost measure accepts only session IDs selected by its caller: 我想要的恒定原则是:会话使用量是可观察的,而会话到任务的归因是独立的声明。agent-cost measure 仅接受由调用者选择的会话 ID:

agent-cost measure \
  --session-id <session-a> \
  --session-id <session-b> \
  --format json

It 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. For example, the spec-lane adapter invokes agent-cost as a subprocess and checks the JSON, the measure/v1 protocol version, the schema, and forbidden personal dimensions. agent-cost does not learn what the task is. The caller that knows the task selects the sessions. If 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. 它不会从分支、Pull Request 或时间戳中推断任务。已经拥有“任务到会话”绑定关系的工作流会传递相应的会话集。例如,spec-lane 适配器将 agent-cost 作为子进程调用,并检查 JSON、measure/v1 协议版本、模式以及禁止的个人维度。agent-cost 不会去了解任务是什么。知道任务的调用者负责选择会话。如果一个会话跨越了多个任务且没有合理的拆分方法,我宁愿让这部分使用量保持“未归因”状态,也不愿制造一个看起来精确的分配结果。“未知”代表证据尚待补充,而不是零。

The same rule applies to prices. agent-cost carries uncertainty instead of smoothing it away. An unknown model is unpriced. A Claude cache write without a TTL breakdown is priced at the cheaper five-minute rate and labeled lower_bound. 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. “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. 同样的规则也适用于价格。agent-cost 保留不确定性,而不是将其抹平。未知的模型即为未定价。没有 TTL 分解的 Claude 缓存写入按较便宜的五分钟费率定价,并标记为 lower_bound。Codex 日志不暴露缓存写入 Token,因此该工具不会虚构零值的缓存写入行。格式错误的事件、不可读的文件以及递减的累积计数器在 data_quality 中保持可见。“故障关闭(Fail closed)”并不意味着每个不完美的输入都会导致命令崩溃,而是意味着不支持的定价或归因不会在下游悄悄变成确认值。

On August 23, 2026, I reran the published coding-agent-cost 0.1.0 package in temporary uvx directories. Its doctor command found the local sources and loaded catalog version 2026-07-29. The explicit unknown-model path still rejected a made-up model: 2026 年 8 月 23 日,我在临时的 uvx 目录中重新运行了已发布的 coding-agent-cost 0.1.0 包。其 doctor 命令找到了本地源并加载了 2026-07-29 版本的目录。明确的未知模型路径仍然拒绝了虚构的模型:

$ uvx --refresh --from coding-agent-cost \
  agent-cost rates show --model model-not-in-catalog
[unpriced] no rate entry for 'model-not-in-catalog'

A numeric zero next to an unpriced row is not a claim that the usage was free. Consumers must inspect pricing_status and unpriced_tokens, then choose a policy: exclude the value from a headline, stop the workflow, or supply a verified catalog. The output field is estimated_cost_usd, 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. 未定价行旁边的数字零并不代表该使用量是免费的。消费者必须检查 pricing_status 和 unpriced_tokens,然后选择策略:从标题中排除该值、停止工作流或提供经过验证的目录。输出字段是 estimated_cost_usd,而不是账单。津贴、合同、积分和批量使用量无法从本地日志中完全恢复。这个数字是附加在观察到的 Token 上的标价估算值。

What the smaller boundary buys. There are intentional limits. agent-cost alone 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. In exchange, each layer has a narrower claim: Local logs support session usage facts. A versioned catalog supports an estimated price. Unsupported prices remain unpriced or lower_bound. The caller owns task binding as separate evidence. Ambiguous usage is not silently apportioned just to complete a total. This is not an argument against dashboards. Use a dashboard when visual exploration is the job. Use OpenTelemetry when fleet observability is the job. 更小边界带来的价值。这里存在刻意的限制。agent-cost 本身不会将一个会话标记为属于某个问题。本地执行并不能消除安装时的供应链风险,也不能消除对本地日志访问权限的信任需求。作为交换,每一层都有更窄的声明:本地日志支持会话使用事实;版本化目录支持估算价格;不支持的价格保持为未定价或 lower_bound;调用者作为独立的证据拥有任务绑定关系。模糊的使用量不会为了凑齐总数而被悄悄分摊。这并不是反对仪表板的论点。当工作是可视化探索时,请使用仪表板;当工作是集群可观测性时,请使用 OpenTelemetry。