coding-agent-cost 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. coding_agent_cost-0.1.0/LICENSE +21 -0
  2. coding_agent_cost-0.1.0/PKG-INFO +247 -0
  3. coding_agent_cost-0.1.0/README.md +224 -0
  4. coding_agent_cost-0.1.0/agent_cost/__init__.py +9 -0
  5. coding_agent_cost-0.1.0/agent_cost/aggregate.py +201 -0
  6. coding_agent_cost-0.1.0/agent_cost/cli.py +393 -0
  7. coding_agent_cost-0.1.0/agent_cost/config.py +67 -0
  8. coding_agent_cost-0.1.0/agent_cost/facts.py +93 -0
  9. coding_agent_cost-0.1.0/agent_cost/rates.json +490 -0
  10. coding_agent_cost-0.1.0/agent_cost/rates.py +280 -0
  11. coding_agent_cost-0.1.0/agent_cost/readers/__init__.py +26 -0
  12. coding_agent_cost-0.1.0/agent_cost/readers/claude.py +177 -0
  13. coding_agent_cost-0.1.0/agent_cost/readers/codex.py +368 -0
  14. coding_agent_cost-0.1.0/agent_cost/renderers.py +90 -0
  15. coding_agent_cost-0.1.0/coding_agent_cost.egg-info/PKG-INFO +247 -0
  16. coding_agent_cost-0.1.0/coding_agent_cost.egg-info/SOURCES.txt +26 -0
  17. coding_agent_cost-0.1.0/coding_agent_cost.egg-info/dependency_links.txt +1 -0
  18. coding_agent_cost-0.1.0/coding_agent_cost.egg-info/entry_points.txt +2 -0
  19. coding_agent_cost-0.1.0/coding_agent_cost.egg-info/top_level.txt +1 -0
  20. coding_agent_cost-0.1.0/pyproject.toml +40 -0
  21. coding_agent_cost-0.1.0/setup.cfg +4 -0
  22. coding_agent_cost-0.1.0/tests/test_aggregate.py +223 -0
  23. coding_agent_cost-0.1.0/tests/test_cli.py +744 -0
  24. coding_agent_cost-0.1.0/tests/test_facts.py +77 -0
  25. coding_agent_cost-0.1.0/tests/test_measure_v1_contract.py +405 -0
  26. coding_agent_cost-0.1.0/tests/test_rates.py +323 -0
  27. coding_agent_cost-0.1.0/tests/test_reader_claude.py +299 -0
  28. coding_agent_cost-0.1.0/tests/test_reader_codex.py +466 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 shiki-yusuke
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,247 @@
1
+ Metadata-Version: 2.4
2
+ Name: coding-agent-cost
3
+ Version: 0.1.0
4
+ Summary: Estimate AI coding agent (Claude Code / Codex CLI) token usage and cost from local logs
5
+ Author: shiki-yusuke
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/shiki-yusuke/agent-cost
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development :: Build Tools
18
+ Classifier: Topic :: Utilities
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Dynamic: license-file
23
+
24
+ # agent-cost
25
+
26
+ > PyPI distribution: [`coding-agent-cost`](https://pypi.org/project/coding-agent-cost/) — the
27
+ > command (`agent-cost`) and import name (`agent_cost`) are unchanged. The name `agent-cost`
28
+ > itself is blocked by PyPI's name-similarity rule against `agentcost`, an unrelated project
29
+ > by a different author; this tool is not affiliated with it.
30
+
31
+ Estimate how many tokens Claude Code and Codex CLI actually used, and roughly
32
+ what that cost, by reading the local logs those tools already write to your
33
+ machine.
34
+
35
+ ## Quick start
36
+
37
+ ```bash
38
+ pip install coding-agent-cost # or, from a checkout: pip install -e .
39
+ agent-cost doctor # sanity-check log locations and the rate catalog
40
+ agent-cost report
41
+ ```
42
+
43
+ `agent-cost report` scans `~/.claude/projects/**/*.jsonl` and
44
+ `~/.codex/state_5.sqlite` (+ its rollout files), turns every token-usage
45
+ event into a canonical "fact" (one model, one token kind, one timestamp,
46
+ one count), prices each fact against a bundled rate catalog, and prints an
47
+ aggregated table:
48
+
49
+ ```
50
+ agent-cost report --since 2026-06-01 --until 2026-07-01 --format table
51
+ agent-cost report --group-by month,agent --format csv
52
+ agent-cost report --format json > usage.json
53
+ agent-cost export --agent claude --out facts.jsonl # raw canonical facts
54
+ ```
55
+
56
+ Useful flags: `--since`/`--until` (half-open window; date-only values are
57
+ interpreted in `--timezone`, default UTC), `--agent claude,codex`,
58
+ `--group-by month,agent,model,token-kind`, `--rates PATH` (use a different
59
+ catalog entirely, see below), `--exclude-archived` (Codex threads).
60
+
61
+ If another program wants to parse agent-cost's output for one or more
62
+ specific session ids, see `agent-cost measure` below rather than
63
+ scraping `report`.
64
+
65
+ ## What this measures, and what it doesn't
66
+
67
+ agent-cost only reads data that is already on disk. It never talks to the
68
+ network, never calls `gh`, and never resolves branches or PRs.
69
+
70
+ - **Claude Code**: every `assistant` message's `usage` block is one billing
71
+ event, attributed to the exact model on that event (a session that
72
+ switches models mid-conversation is not folded into one "primary model").
73
+ When Anthropic's prompt-cache TTL breakdown (5-minute vs 1-hour writes) is
74
+ present in the log, it's used; otherwise the cache-write tokens are priced
75
+ at the 5-minute rate as an explicit **lower bound** and flagged
76
+ `lower_bound` rather than guessed at the (more expensive) 1-hour rate.
77
+ - **Codex CLI**: rollout files record a *cumulative* token count after each
78
+ turn; agent-cost turns that into per-turn deltas. Codex does not expose a
79
+ separate cache-write signal at all, so cache writes are never reported for
80
+ Codex (not zero -- simply not observable, and left out of the row rather
81
+ than implied). Codex's `output` fact is `output_tokens` alone: cross-checking
82
+ real rollout files confirms `total_tokens == input_tokens + output_tokens`
83
+ in every sample, which means `reasoning_output_tokens` is a breakdown of
84
+ output tokens already counted, not an additional charge -- adding it in
85
+ would double it.
86
+ - **Anthropic prices are standard (non-batch) API list prices.** The Batch
87
+ API is roughly 50% cheaper, but agent-cost's logs carry no signal for
88
+ whether a request went through Batch, so all Claude usage is priced at
89
+ standard rates; this overstates cost for anyone using Batch.
90
+ - **Cost is always an estimate.** The output field is `estimated_cost_usd`,
91
+ never `cost_usd`: it is a list-price calculation from token counts, not a
92
+ bill. For Codex, whose provider bills in credits, the row also carries a
93
+ `credits` figure; `credits × usd_per_credit` is an illustrative USD
94
+ conversion, not what you were actually charged (enterprise allowances, overage rules, and
95
+ fast-mode multipliers with unknown values are exactly why the raw credits
96
+ number is kept alongside the USD estimate rather than only the USD).
97
+ - An unrecognized model, or a token kind a model's rate period doesn't
98
+ define, is reported as `unpriced` with `estimated_cost_usd: null`-like
99
+ zero and the tokens broken out in `unpriced_tokens` -- agent-cost never
100
+ invents a price for something it doesn't have a rate for.
101
+ - Corrupted log lines, files that vanish mid-read, and Codex cumulative
102
+ counters that go backwards (e.g. after a session reset) are all counted
103
+ in the report's `data_quality` block instead of being silently dropped or
104
+ clamped to zero.
105
+ - **Known catalog gaps**, tracked in `agent_cost/rates.json`'s `notes`:
106
+ `claude-opus-5`'s launch date could not be confirmed from an authoritative
107
+ source, so its rate period's `effective_from` is a placeholder. `gpt-5.6`
108
+ (Sol/Terra/Luna) credits could not be confirmed from the primary source
109
+ (`help.openai.com`'s Codex rate card returns HTTP 403 to automated
110
+ fetches); the values in the catalog come from several independent
111
+ secondary sources that agree with each other and are internally
112
+ consistent with `usd_per_credit`, but are not primary-source-verified --
113
+ re-check them once the rate card is reachable. Update either via a
114
+ custom `--rates` file if you have a confirmed number.
115
+
116
+ ## Updating the rate catalog
117
+
118
+ Prices live in `agent_cost/rates.json`, not in code. It's a historical
119
+ catalog: each model can have several time-bounded rate periods, so a price
120
+ change is recorded as a new period rather than overwriting the old one (see
121
+ `claude-sonnet-5`'s launch-promo period for a worked example). Every catalog
122
+ carries a `catalog_version`, a list of `sources` (the pricing page a rate
123
+ came from), and is validated on load (no duplicate model keys or aliases,
124
+ no negative rates, no overlapping periods for the same model).
125
+
126
+ To use your own catalog instead of the one bundled with the package, pass
127
+ `--rates path/to/rates.json` to `report` or `export` -- this fully replaces
128
+ the bundled catalog, it does not merge with it. Inspect any catalog with:
129
+
130
+ ```bash
131
+ agent-cost rates show # list every model_key
132
+ agent-cost rates show --model gpt-5.5 # one model's rate history
133
+ agent-cost rates validate path/to/rates.json
134
+ ```
135
+
136
+ `agent-cost report`'s JSON output always echoes the catalog's
137
+ `catalog_version` and the sha256 of the exact rates file used, so a report
138
+ can be traced back to the prices that produced it.
139
+
140
+ ## Machine consumption: `agent-cost measure`
141
+
142
+ `report` is for a person reading a table. `measure` is for another program
143
+ calling agent-cost as a subprocess and parsing its stdout -- e.g. a build
144
+ orchestrator attributing cost to a specific unit of work it already knows
145
+ the session id(s) for.
146
+
147
+ ```bash
148
+ agent-cost measure --session-id <id> [--session-id <id> ...] \
149
+ [--since --until --timezone] [--agent claude,codex] [--rates PATH] --format json
150
+ ```
151
+
152
+ - One or more `--session-id` is required (repeat the flag for more than
153
+ one); `measure` never scans "everything," only the sessions you name.
154
+ - `--since`/`--until` accept a date-only value (interpreted in
155
+ `--timezone`), an offset-qualified ISO 8601 datetime (`+00:00`, `+09:00`,
156
+ ...), or the same datetime with a trailing `Z` instead of an offset
157
+ (`2026-07-31T00:00:00Z`, exactly what `Date.toISOString()` in JS emits)
158
+ -- all three are accepted by `report`/`export`/`measure` alike.
159
+ - Exit code is `0` on success -- including when none of the given session
160
+ ids matched any usage at all, which is a valid, representable answer
161
+ (empty totals, `"matched": false` per session), not a failure. Exit code
162
+ `2` means bad input (no `--session-id`, an unparseable `--since`/
163
+ `--until`/`--timezone`, or an invalid `--rates` catalog) -- nothing was
164
+ measured, don't trust any partial output.
165
+ - Output is one JSON object on stdout with a `protocol_version` field
166
+ (currently `"measure/v1"`) a caller should check before trusting the
167
+ shape below. Within a major version, only additive changes (new fields)
168
+ are made; a field being removed or changing meaning bumps the version.
169
+
170
+ ```json
171
+ {
172
+ "protocol_version": "measure/v1",
173
+ "generated_at": "...",
174
+ "window": { "since": "...", "until": null },
175
+ "timezone": "UTC",
176
+ "agent": ["claude", "codex"],
177
+ "rates": { "catalog_version": "2026-07-29", "sha256": "..." },
178
+ "session_ids": ["sess-1", "sess-2"],
179
+ "sessions": {
180
+ "sess-1": { "matched": true, "rows": [ /* same row shape as report --format json */ ], "totals": { "tokens": 12345, "priced_tokens": 12345, "unpriced_tokens": 0, "estimated_cost_usd": 0.42, "credits": 0.0 } },
181
+ "sess-2": { "matched": false, "rows": [], "totals": { "tokens": 0, "priced_tokens": 0, "unpriced_tokens": 0, "estimated_cost_usd": 0.0, "credits": 0.0 } }
182
+ },
183
+ "total": { "rows": [ /* union across every requested session_id */ ], "totals": { "...": "..." } },
184
+ "data_quality": {
185
+ "malformed_events": 0,
186
+ "skipped_files": 0,
187
+ "negative_deltas": 0,
188
+ "unpriced_tokens": 0,
189
+ "source_quality": { "ok": 41, "first_event_delta": 2 }
190
+ }
191
+ }
192
+ ```
193
+
194
+ Rows are grouped by agent/model/token-kind only -- `measure` never buckets
195
+ by month, since a query is already scoped to specific sessions. `total` is
196
+ the union of every requested `session_id` (not a global report), so it's
197
+ the number to attribute to whatever unit of work those sessions represent.
198
+ `data_quality.unpriced_tokens` and `.source_quality` are scoped to the
199
+ requested sessions; `.malformed_events`/`.skipped_files`/`.negative_deltas`
200
+ describe the health of the underlying log read within `--since`/`--until`
201
+ and are not attributable to one session.
202
+
203
+ ## Privacy
204
+
205
+ agent-cost makes zero network calls. `agent-cost export`'s JSONL never
206
+ includes absolute file paths, rollout paths, prompt/message content, or git
207
+ branch names -- only the fields needed to reproduce a cost estimate:
208
+ `occurred_at_utc`, `agent`, `session_id`, `model_raw`, `model_key`,
209
+ `token_kind`, `tokens`, `mode`, and `source_quality` (a fixed-vocabulary
210
+ caveat about how that one fact was derived, e.g. `"ok"` or Codex's
211
+ `"first_event_delta"` -- never null).
212
+
213
+ ## License
214
+
215
+ MIT. See [LICENSE](LICENSE).
216
+
217
+ ---
218
+
219
+ ## 日本語サマリ
220
+
221
+ `agent-cost` は Claude Code / Codex CLI がローカルに残すログ(`~/.claude/projects/**/*.jsonl`
222
+ と `~/.codex/state_5.sqlite` + rollout ファイル)だけを読み、トークン使用量とおおよそのコストを
223
+ 見積もる CLI です。ネットワークアクセスは一切行いません。
224
+
225
+ - 集計の最小単位は「1 イベント = 1 モデル × 1 token 種別」の fact であり、session 単位でモデルを
226
+ 丸めません。Claude の prompt cache は TTL 内訳(5分/1時間)が取れればそれを使い、取れない場合は
227
+ 5分単価で **下限推計**(`lower_bound`)として明示します。Codex の cache write は観測不能なため
228
+ 出力しません(0 とは区別)。
229
+ - 出力フィールドは `estimated_cost_usd`(推計であることを明示)。Codex は `credits` も併記します。
230
+ 未知のモデル・単価表にない token 種別は `unpriced` として扱い、憶測の価格を出しません。
231
+ - 単価表 (`agent_cost/rates.json`) は履歴型カタログで、値上げは新しい期間として追加します。
232
+ `--rates PATH` で別カタログに完全差し替えできます。
233
+ - `agent-cost measure --session-id ID [--session-id ID ...] --format json` は他プログラムから
234
+ subprocess で叩くための機械可読な契約です(`protocol_version: "measure/v1"`)。指定した
235
+ session_id が1件も見つからなくても終了コードは0(空集計として表現)、`--session-id` 未指定など
236
+ の入力エラーのみ終了コード2です。
237
+ - 破損したログ行、読めなくなったファイル、Codex の累積カウンタが逆行するケースなどは、すべて
238
+ `data_quality` に件数として記録し、黙って丸めたり捨てたりしません。
239
+ - Codex の `output` は `output_tokens` のみです。実 rollout データを突合した結果
240
+ `total_tokens == input_tokens + output_tokens` が常に成立することを確認しており、
241
+ `reasoning_output_tokens` は output の内訳(二重計上してはいけない)と判断しています。
242
+ - Anthropic の単価は標準(非 Batch)API 価格です。Batch API は約50%安いですが、ログからは
243
+ Batch 利用かどうか判別できないため、常に標準単価で推計します(Batch 利用者には過大推計)。
244
+ - `claude-opus-5` のローンチ日は根拠を確認できず `effective_from` はプレースホルダです。
245
+ `gpt-5.6`(sol/terra/luna)は一次情報(help.openai.com の rate card)が 403 で取得できなかったため、
246
+ 相互に整合する複数の二次情報源の値を採用しています(一次情報での裏取りは未完了、詳細は
247
+ `rates.json` の `notes`)。
@@ -0,0 +1,224 @@
1
+ # agent-cost
2
+
3
+ > PyPI distribution: [`coding-agent-cost`](https://pypi.org/project/coding-agent-cost/) — the
4
+ > command (`agent-cost`) and import name (`agent_cost`) are unchanged. The name `agent-cost`
5
+ > itself is blocked by PyPI's name-similarity rule against `agentcost`, an unrelated project
6
+ > by a different author; this tool is not affiliated with it.
7
+
8
+ Estimate how many tokens Claude Code and Codex CLI actually used, and roughly
9
+ what that cost, by reading the local logs those tools already write to your
10
+ machine.
11
+
12
+ ## Quick start
13
+
14
+ ```bash
15
+ pip install coding-agent-cost # or, from a checkout: pip install -e .
16
+ agent-cost doctor # sanity-check log locations and the rate catalog
17
+ agent-cost report
18
+ ```
19
+
20
+ `agent-cost report` scans `~/.claude/projects/**/*.jsonl` and
21
+ `~/.codex/state_5.sqlite` (+ its rollout files), turns every token-usage
22
+ event into a canonical "fact" (one model, one token kind, one timestamp,
23
+ one count), prices each fact against a bundled rate catalog, and prints an
24
+ aggregated table:
25
+
26
+ ```
27
+ agent-cost report --since 2026-06-01 --until 2026-07-01 --format table
28
+ agent-cost report --group-by month,agent --format csv
29
+ agent-cost report --format json > usage.json
30
+ agent-cost export --agent claude --out facts.jsonl # raw canonical facts
31
+ ```
32
+
33
+ Useful flags: `--since`/`--until` (half-open window; date-only values are
34
+ interpreted in `--timezone`, default UTC), `--agent claude,codex`,
35
+ `--group-by month,agent,model,token-kind`, `--rates PATH` (use a different
36
+ catalog entirely, see below), `--exclude-archived` (Codex threads).
37
+
38
+ If another program wants to parse agent-cost's output for one or more
39
+ specific session ids, see `agent-cost measure` below rather than
40
+ scraping `report`.
41
+
42
+ ## What this measures, and what it doesn't
43
+
44
+ agent-cost only reads data that is already on disk. It never talks to the
45
+ network, never calls `gh`, and never resolves branches or PRs.
46
+
47
+ - **Claude Code**: every `assistant` message's `usage` block is one billing
48
+ event, attributed to the exact model on that event (a session that
49
+ switches models mid-conversation is not folded into one "primary model").
50
+ When Anthropic's prompt-cache TTL breakdown (5-minute vs 1-hour writes) is
51
+ present in the log, it's used; otherwise the cache-write tokens are priced
52
+ at the 5-minute rate as an explicit **lower bound** and flagged
53
+ `lower_bound` rather than guessed at the (more expensive) 1-hour rate.
54
+ - **Codex CLI**: rollout files record a *cumulative* token count after each
55
+ turn; agent-cost turns that into per-turn deltas. Codex does not expose a
56
+ separate cache-write signal at all, so cache writes are never reported for
57
+ Codex (not zero -- simply not observable, and left out of the row rather
58
+ than implied). Codex's `output` fact is `output_tokens` alone: cross-checking
59
+ real rollout files confirms `total_tokens == input_tokens + output_tokens`
60
+ in every sample, which means `reasoning_output_tokens` is a breakdown of
61
+ output tokens already counted, not an additional charge -- adding it in
62
+ would double it.
63
+ - **Anthropic prices are standard (non-batch) API list prices.** The Batch
64
+ API is roughly 50% cheaper, but agent-cost's logs carry no signal for
65
+ whether a request went through Batch, so all Claude usage is priced at
66
+ standard rates; this overstates cost for anyone using Batch.
67
+ - **Cost is always an estimate.** The output field is `estimated_cost_usd`,
68
+ never `cost_usd`: it is a list-price calculation from token counts, not a
69
+ bill. For Codex, whose provider bills in credits, the row also carries a
70
+ `credits` figure; `credits × usd_per_credit` is an illustrative USD
71
+ conversion, not what you were actually charged (enterprise allowances, overage rules, and
72
+ fast-mode multipliers with unknown values are exactly why the raw credits
73
+ number is kept alongside the USD estimate rather than only the USD).
74
+ - An unrecognized model, or a token kind a model's rate period doesn't
75
+ define, is reported as `unpriced` with `estimated_cost_usd: null`-like
76
+ zero and the tokens broken out in `unpriced_tokens` -- agent-cost never
77
+ invents a price for something it doesn't have a rate for.
78
+ - Corrupted log lines, files that vanish mid-read, and Codex cumulative
79
+ counters that go backwards (e.g. after a session reset) are all counted
80
+ in the report's `data_quality` block instead of being silently dropped or
81
+ clamped to zero.
82
+ - **Known catalog gaps**, tracked in `agent_cost/rates.json`'s `notes`:
83
+ `claude-opus-5`'s launch date could not be confirmed from an authoritative
84
+ source, so its rate period's `effective_from` is a placeholder. `gpt-5.6`
85
+ (Sol/Terra/Luna) credits could not be confirmed from the primary source
86
+ (`help.openai.com`'s Codex rate card returns HTTP 403 to automated
87
+ fetches); the values in the catalog come from several independent
88
+ secondary sources that agree with each other and are internally
89
+ consistent with `usd_per_credit`, but are not primary-source-verified --
90
+ re-check them once the rate card is reachable. Update either via a
91
+ custom `--rates` file if you have a confirmed number.
92
+
93
+ ## Updating the rate catalog
94
+
95
+ Prices live in `agent_cost/rates.json`, not in code. It's a historical
96
+ catalog: each model can have several time-bounded rate periods, so a price
97
+ change is recorded as a new period rather than overwriting the old one (see
98
+ `claude-sonnet-5`'s launch-promo period for a worked example). Every catalog
99
+ carries a `catalog_version`, a list of `sources` (the pricing page a rate
100
+ came from), and is validated on load (no duplicate model keys or aliases,
101
+ no negative rates, no overlapping periods for the same model).
102
+
103
+ To use your own catalog instead of the one bundled with the package, pass
104
+ `--rates path/to/rates.json` to `report` or `export` -- this fully replaces
105
+ the bundled catalog, it does not merge with it. Inspect any catalog with:
106
+
107
+ ```bash
108
+ agent-cost rates show # list every model_key
109
+ agent-cost rates show --model gpt-5.5 # one model's rate history
110
+ agent-cost rates validate path/to/rates.json
111
+ ```
112
+
113
+ `agent-cost report`'s JSON output always echoes the catalog's
114
+ `catalog_version` and the sha256 of the exact rates file used, so a report
115
+ can be traced back to the prices that produced it.
116
+
117
+ ## Machine consumption: `agent-cost measure`
118
+
119
+ `report` is for a person reading a table. `measure` is for another program
120
+ calling agent-cost as a subprocess and parsing its stdout -- e.g. a build
121
+ orchestrator attributing cost to a specific unit of work it already knows
122
+ the session id(s) for.
123
+
124
+ ```bash
125
+ agent-cost measure --session-id <id> [--session-id <id> ...] \
126
+ [--since --until --timezone] [--agent claude,codex] [--rates PATH] --format json
127
+ ```
128
+
129
+ - One or more `--session-id` is required (repeat the flag for more than
130
+ one); `measure` never scans "everything," only the sessions you name.
131
+ - `--since`/`--until` accept a date-only value (interpreted in
132
+ `--timezone`), an offset-qualified ISO 8601 datetime (`+00:00`, `+09:00`,
133
+ ...), or the same datetime with a trailing `Z` instead of an offset
134
+ (`2026-07-31T00:00:00Z`, exactly what `Date.toISOString()` in JS emits)
135
+ -- all three are accepted by `report`/`export`/`measure` alike.
136
+ - Exit code is `0` on success -- including when none of the given session
137
+ ids matched any usage at all, which is a valid, representable answer
138
+ (empty totals, `"matched": false` per session), not a failure. Exit code
139
+ `2` means bad input (no `--session-id`, an unparseable `--since`/
140
+ `--until`/`--timezone`, or an invalid `--rates` catalog) -- nothing was
141
+ measured, don't trust any partial output.
142
+ - Output is one JSON object on stdout with a `protocol_version` field
143
+ (currently `"measure/v1"`) a caller should check before trusting the
144
+ shape below. Within a major version, only additive changes (new fields)
145
+ are made; a field being removed or changing meaning bumps the version.
146
+
147
+ ```json
148
+ {
149
+ "protocol_version": "measure/v1",
150
+ "generated_at": "...",
151
+ "window": { "since": "...", "until": null },
152
+ "timezone": "UTC",
153
+ "agent": ["claude", "codex"],
154
+ "rates": { "catalog_version": "2026-07-29", "sha256": "..." },
155
+ "session_ids": ["sess-1", "sess-2"],
156
+ "sessions": {
157
+ "sess-1": { "matched": true, "rows": [ /* same row shape as report --format json */ ], "totals": { "tokens": 12345, "priced_tokens": 12345, "unpriced_tokens": 0, "estimated_cost_usd": 0.42, "credits": 0.0 } },
158
+ "sess-2": { "matched": false, "rows": [], "totals": { "tokens": 0, "priced_tokens": 0, "unpriced_tokens": 0, "estimated_cost_usd": 0.0, "credits": 0.0 } }
159
+ },
160
+ "total": { "rows": [ /* union across every requested session_id */ ], "totals": { "...": "..." } },
161
+ "data_quality": {
162
+ "malformed_events": 0,
163
+ "skipped_files": 0,
164
+ "negative_deltas": 0,
165
+ "unpriced_tokens": 0,
166
+ "source_quality": { "ok": 41, "first_event_delta": 2 }
167
+ }
168
+ }
169
+ ```
170
+
171
+ Rows are grouped by agent/model/token-kind only -- `measure` never buckets
172
+ by month, since a query is already scoped to specific sessions. `total` is
173
+ the union of every requested `session_id` (not a global report), so it's
174
+ the number to attribute to whatever unit of work those sessions represent.
175
+ `data_quality.unpriced_tokens` and `.source_quality` are scoped to the
176
+ requested sessions; `.malformed_events`/`.skipped_files`/`.negative_deltas`
177
+ describe the health of the underlying log read within `--since`/`--until`
178
+ and are not attributable to one session.
179
+
180
+ ## Privacy
181
+
182
+ agent-cost makes zero network calls. `agent-cost export`'s JSONL never
183
+ includes absolute file paths, rollout paths, prompt/message content, or git
184
+ branch names -- only the fields needed to reproduce a cost estimate:
185
+ `occurred_at_utc`, `agent`, `session_id`, `model_raw`, `model_key`,
186
+ `token_kind`, `tokens`, `mode`, and `source_quality` (a fixed-vocabulary
187
+ caveat about how that one fact was derived, e.g. `"ok"` or Codex's
188
+ `"first_event_delta"` -- never null).
189
+
190
+ ## License
191
+
192
+ MIT. See [LICENSE](LICENSE).
193
+
194
+ ---
195
+
196
+ ## 日本語サマリ
197
+
198
+ `agent-cost` は Claude Code / Codex CLI がローカルに残すログ(`~/.claude/projects/**/*.jsonl`
199
+ と `~/.codex/state_5.sqlite` + rollout ファイル)だけを読み、トークン使用量とおおよそのコストを
200
+ 見積もる CLI です。ネットワークアクセスは一切行いません。
201
+
202
+ - 集計の最小単位は「1 イベント = 1 モデル × 1 token 種別」の fact であり、session 単位でモデルを
203
+ 丸めません。Claude の prompt cache は TTL 内訳(5分/1時間)が取れればそれを使い、取れない場合は
204
+ 5分単価で **下限推計**(`lower_bound`)として明示します。Codex の cache write は観測不能なため
205
+ 出力しません(0 とは区別)。
206
+ - 出力フィールドは `estimated_cost_usd`(推計であることを明示)。Codex は `credits` も併記します。
207
+ 未知のモデル・単価表にない token 種別は `unpriced` として扱い、憶測の価格を出しません。
208
+ - 単価表 (`agent_cost/rates.json`) は履歴型カタログで、値上げは新しい期間として追加します。
209
+ `--rates PATH` で別カタログに完全差し替えできます。
210
+ - `agent-cost measure --session-id ID [--session-id ID ...] --format json` は他プログラムから
211
+ subprocess で叩くための機械可読な契約です(`protocol_version: "measure/v1"`)。指定した
212
+ session_id が1件も見つからなくても終了コードは0(空集計として表現)、`--session-id` 未指定など
213
+ の入力エラーのみ終了コード2です。
214
+ - 破損したログ行、読めなくなったファイル、Codex の累積カウンタが逆行するケースなどは、すべて
215
+ `data_quality` に件数として記録し、黙って丸めたり捨てたりしません。
216
+ - Codex の `output` は `output_tokens` のみです。実 rollout データを突合した結果
217
+ `total_tokens == input_tokens + output_tokens` が常に成立することを確認しており、
218
+ `reasoning_output_tokens` は output の内訳(二重計上してはいけない)と判断しています。
219
+ - Anthropic の単価は標準(非 Batch)API 価格です。Batch API は約50%安いですが、ログからは
220
+ Batch 利用かどうか判別できないため、常に標準単価で推計します(Batch 利用者には過大推計)。
221
+ - `claude-opus-5` のローンチ日は根拠を確認できず `effective_from` はプレースホルダです。
222
+ `gpt-5.6`(sol/terra/luna)は一次情報(help.openai.com の rate card)が 403 で取得できなかったため、
223
+ 相互に整合する複数の二次情報源の値を採用しています(一次情報での裏取りは未完了、詳細は
224
+ `rates.json` の `notes`)。
@@ -0,0 +1,9 @@
1
+ """agent-cost: estimate AI coding agent token usage and cost from local logs.
2
+
3
+ Reads Claude Code and Codex CLI logs that already exist on disk and turns
4
+ them into per-event "facts" (billing events), then prices those facts
5
+ against a versioned rate catalog. Everything happens locally; there are no
6
+ network calls.
7
+ """
8
+
9
+ __version__ = "0.1.0"