coding-agent-cost 0.4.0__tar.gz → 0.5.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 (39) hide show
  1. {coding_agent_cost-0.4.0/coding_agent_cost.egg-info → coding_agent_cost-0.5.0}/PKG-INFO +112 -1
  2. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/README.md +111 -0
  3. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/agent_cost/__init__.py +1 -1
  4. coding_agent_cost-0.5.0/agent_cost/billing_plan.py +654 -0
  5. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/agent_cost/cli.py +80 -2
  6. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/agent_cost/renderers.py +60 -0
  7. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0/coding_agent_cost.egg-info}/PKG-INFO +112 -1
  8. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/coding_agent_cost.egg-info/SOURCES.txt +2 -0
  9. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/pyproject.toml +1 -1
  10. coding_agent_cost-0.5.0/tests/test_billing_plan.py +1360 -0
  11. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_cli.py +359 -1
  12. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_version_consistency.py +8 -8
  13. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/LICENSE +0 -0
  14. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/agent_cost/aggregate.py +0 -0
  15. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/agent_cost/config.py +0 -0
  16. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/agent_cost/facts.py +0 -0
  17. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/agent_cost/rates.json +0 -0
  18. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/agent_cost/rates.py +0 -0
  19. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/agent_cost/readers/__init__.py +0 -0
  20. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/agent_cost/readers/claude.py +0 -0
  21. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/agent_cost/readers/codex.py +0 -0
  22. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/coding_agent_cost.egg-info/dependency_links.txt +0 -0
  23. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/coding_agent_cost.egg-info/entry_points.txt +0 -0
  24. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/coding_agent_cost.egg-info/top_level.txt +0 -0
  25. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/setup.cfg +0 -0
  26. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_aggregate.py +0 -0
  27. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_astra_pricing.py +0 -0
  28. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_e0a_fable_5_1_and_sonnet_5_correction.py +0 -0
  29. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_e0a_review3_hardening.py +0 -0
  30. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_facts.py +0 -0
  31. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_haiku_5_5_rates.py +0 -0
  32. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_measure_v1_contract.py +0 -0
  33. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_opus_5_5_rates.py +0 -0
  34. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_rates.py +0 -0
  35. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_reader_claude.py +0 -0
  36. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_reader_codex.py +0 -0
  37. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_reader_dedup.py +0 -0
  38. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_reader_output_lower_bound.py +0 -0
  39. {coding_agent_cost-0.4.0 → coding_agent_cost-0.5.0}/tests/test_sonnet_5_5_rates.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coding-agent-cost
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Estimate AI coding agent (Claude Code / Codex CLI) token usage and cost from local logs
5
5
  Author: shiki-yusuke
6
6
  License: MIT
@@ -200,6 +200,114 @@ If another program wants to parse agent-cost's output for one or more
200
200
  specific session ids, see `agent-cost measure` below rather than
201
201
  scraping `report`.
202
202
 
203
+ ## Internal billing plan (optional, confidential)
204
+
205
+ Some organizations bill Claude seats internally with their own rules -- a
206
+ fixed subscription per billing window, a usage allowance measured in
207
+ list-price dollars, and a discounted rate above it. `report --billing-plan
208
+ PATH` applies such a plan to the Claude usage agent-cost already prices at
209
+ the public catalog. Nothing changes without the flag, and there is no
210
+ default path or environment variable that turns it on.
211
+
212
+ ```bash
213
+ agent-cost report --billing-plan ~/private/billing-plan.json \
214
+ --since 2030-01-01T00:00:00+00:00 --until 2030-02-01T00:00:00+00:00 --format json
215
+ ```
216
+
217
+ A plan (`plan_schema_version` `"1"`; every value below is made up):
218
+
219
+ ```json
220
+ {
221
+ "plan_schema_version": "1",
222
+ "plan_id": "bp-example",
223
+ "nonce": "0123456789abcdef0123456789abcdef",
224
+ "applies_to": {"agent": "claude", "scope": "seat"},
225
+ "basis": "agent-cost-list-price",
226
+ "periods": [
227
+ {"period_id": "p1", "effective_from": "2030-01-01T00:00:00+00:00",
228
+ "window_subscription_usd": "3", "allowance_usd": null, "overage": null},
229
+ {"period_id": "p2", "effective_from": "2030-01-11T00:00:00+00:00",
230
+ "window_subscription_usd": "10", "allowance_usd": "50",
231
+ "overage": {"type": "charge_multiplier", "value": "0.5"}},
232
+ {"period_id": "end", "effective_from": "2030-02-01T00:00:00+00:00", "terminates": true}
233
+ ]
234
+ }
235
+ ```
236
+
237
+ - `periods` is a list of finite billing windows: window *i* is
238
+ `[effective_from_i, effective_from_{i+1})`, and the last entry must be
239
+ `{period_id, effective_from, terminates: true}` so that no window is
240
+ open-ended. Write one window per billing month (or per contract change).
241
+ `effective_from` needs a UTC offset and no sub-second part.
242
+ - `window_subscription_usd` is the fixed amount billed for that window, as
243
+ you write it -- agent-cost never prorates it.
244
+ - `allowance_usd` is the window's usage allowance in list-price dollars.
245
+ `null` means the window has no overage concept at all (it is not a zero
246
+ allowance), and then `overage` must be `null` too.
247
+ - `overage` prices `max(0, list_cost - allowance)`:
248
+ `{"type": "charge_multiplier", "value": "0.5"}` charges overage × value
249
+ (`0 <= value <= 1`), and `{"type": "block_discount", "block_usd": "5",
250
+ "discount_usd": "1"}` charges overage minus `floor(overage / block_usd) ×
251
+ discount_usd` (`0 < discount_usd <= block_usd`).
252
+ - Amounts are decimal strings only (no JSON numbers), at most 28
253
+ significant digits. `plan_id` is `[A-Za-z0-9_-]{1,32}`, `period_id`
254
+ `[A-Za-z0-9_-]{1,16}`, `nonce` 32 lowercase hex characters (e.g.
255
+ `python3 -c 'import secrets; print(secrets.token_hex(16))'`). Unknown or
256
+ duplicate keys are errors. v1 only accepts `scope: "seat"`: an allowance
257
+ shared by a department or org cannot be computed from one person's logs.
258
+
259
+ The JSON output gains an `internal_billing` block (existing keys are
260
+ unchanged), and the table gains a section headed `Internal billing
261
+ (CONFIDENTIAL -- do not share)`. For each window that intersects
262
+ `[since, until)` it shows `list_cost_usd` (Claude facts in the window,
263
+ priced at the packaged catalog), `allowance_usd`, `overage_usd`,
264
+ `overage_cost_usd`, `window_subscription_usd`, `internal_cost_usd` --
265
+ all as 4-decimal strings -- and four separate status fields:
266
+
267
+ - `query_coverage`: `full` when `--since`/`--until` cover the whole
268
+ window, otherwise `partial`. It says nothing about whether the logs
269
+ themselves are complete (deleted transcripts, other machines, API or web
270
+ usage are never seen; see `data_quality` at the top level as well).
271
+ - `window_state`: `closed` once the window has ended (`until <=
272
+ generated_at`), otherwise `open`.
273
+ - `list_cost_pricing`: `priced`, `lower_bound` (some facts were unpriced
274
+ or only priced as a lower bound, or an output fact's tokens are only a
275
+ lower bound -- `source_quality: "output_lower_bound"`) or
276
+ `no_usage_observed`.
277
+ - `internal_cost_certainty`: `estimate` only when the window is fully
278
+ queried, closed and `priced`. Otherwise `lower_bound` for windows with no
279
+ overage or `charge_multiplier` (more usage can only raise the amount), and
280
+ `indeterminate` for `block_discount` (more usage can cross a block
281
+ boundary and lower it). This describes what can be derived from the
282
+ observed list cost -- it is not a statement that the number matches an
283
+ actual invoice.
284
+
285
+ `window_subscription_usd` in each row is the plan's input echoed back, not
286
+ an amount allocated to your query. `internal_cost_usd` is the cost of the
287
+ whole billing window computed from the usage visible in this report -- it
288
+ is not the cost of the `[since, until)` range, so do not sum windows to get
289
+ one. `plan_coverage: partial` with `uncovered` ranges flags the parts of
290
+ `[since, until)` that no window covers (before the first window or after
291
+ `terminates`); usage there is not billed.
292
+
293
+ `measure` has no billing plan option on purpose: a per-session internal
294
+ cost would mean allocating a window-level charge across sessions.
295
+ `--billing-plan` cannot be combined with `--rates` (the basis must be the
296
+ packaged public catalog), `--format csv`, an `--agent` list without
297
+ `claude`, or a missing `--since`/`--until`; any of those, an unreadable or
298
+ invalid plan, or a calculation that would need rounding exits 2 with
299
+ nothing on stdout. `AGENT_COST_NOW` (an ISO 8601 instant with a UTC offset)
300
+ pins `generated_at`, and with it `window_state`, for reproducible runs.
301
+
302
+ **Keep the plan and its output private.** The plan must be a regular file
303
+ owned by you with mode `0600` (or stricter), reached without any symlink in
304
+ its path (on macOS `/tmp` and `/var` are symlinks -- keep it under your
305
+ home directory), and not inside a git repository or worktree. Error messages
306
+ never print plan values or the path. Output produced with the plan is
307
+ confidential: agent-cost has no redaction, so mind your terminal scrollback,
308
+ shell history, and the permissions of any file you redirect it to, and keep
309
+ it out of shared logs, CI, artifacts and ledgers.
310
+
203
311
  ## What this measures, and what it doesn't
204
312
 
205
313
  agent-cost only reads data that is already on disk. It never talks to the
@@ -479,6 +587,9 @@ MIT. See [LICENSE](LICENSE).
479
587
  subprocess で叩くための機械可読な契約です(`protocol_version: "measure/v1"`)。指定した
480
588
  session_id が1件も見つからなくても終了コードは0(空集計として表現)、`--session-id` 未指定など
481
589
  の入力エラーのみ終了コード2です。
590
+ - `report --billing-plan PATH`(任意・機密)は、ローカルの課金プラン(窓ごとの定額・利用枠・超過規則)を
591
+ 公開単価で集計した Claude の list_cost に当てて `internal_billing` を出します。フラグ無しの出力は不変です。
592
+ - plan ファイルは 0600・symlink 不可・git repo 外に置き、出力は機密成果物として扱います(`measure` には按分になるため無し)。
482
593
  - 破損したログ行、読めなくなったファイル、Codex の累積カウンタが逆行するケースなどは、すべて
483
594
  `data_quality` に件数として記録し、黙って丸めたり捨てたりしません。
484
595
  - Codex の `output` は `output_tokens` のみです。実 rollout データを突合した結果
@@ -174,6 +174,114 @@ If another program wants to parse agent-cost's output for one or more
174
174
  specific session ids, see `agent-cost measure` below rather than
175
175
  scraping `report`.
176
176
 
177
+ ## Internal billing plan (optional, confidential)
178
+
179
+ Some organizations bill Claude seats internally with their own rules -- a
180
+ fixed subscription per billing window, a usage allowance measured in
181
+ list-price dollars, and a discounted rate above it. `report --billing-plan
182
+ PATH` applies such a plan to the Claude usage agent-cost already prices at
183
+ the public catalog. Nothing changes without the flag, and there is no
184
+ default path or environment variable that turns it on.
185
+
186
+ ```bash
187
+ agent-cost report --billing-plan ~/private/billing-plan.json \
188
+ --since 2030-01-01T00:00:00+00:00 --until 2030-02-01T00:00:00+00:00 --format json
189
+ ```
190
+
191
+ A plan (`plan_schema_version` `"1"`; every value below is made up):
192
+
193
+ ```json
194
+ {
195
+ "plan_schema_version": "1",
196
+ "plan_id": "bp-example",
197
+ "nonce": "0123456789abcdef0123456789abcdef",
198
+ "applies_to": {"agent": "claude", "scope": "seat"},
199
+ "basis": "agent-cost-list-price",
200
+ "periods": [
201
+ {"period_id": "p1", "effective_from": "2030-01-01T00:00:00+00:00",
202
+ "window_subscription_usd": "3", "allowance_usd": null, "overage": null},
203
+ {"period_id": "p2", "effective_from": "2030-01-11T00:00:00+00:00",
204
+ "window_subscription_usd": "10", "allowance_usd": "50",
205
+ "overage": {"type": "charge_multiplier", "value": "0.5"}},
206
+ {"period_id": "end", "effective_from": "2030-02-01T00:00:00+00:00", "terminates": true}
207
+ ]
208
+ }
209
+ ```
210
+
211
+ - `periods` is a list of finite billing windows: window *i* is
212
+ `[effective_from_i, effective_from_{i+1})`, and the last entry must be
213
+ `{period_id, effective_from, terminates: true}` so that no window is
214
+ open-ended. Write one window per billing month (or per contract change).
215
+ `effective_from` needs a UTC offset and no sub-second part.
216
+ - `window_subscription_usd` is the fixed amount billed for that window, as
217
+ you write it -- agent-cost never prorates it.
218
+ - `allowance_usd` is the window's usage allowance in list-price dollars.
219
+ `null` means the window has no overage concept at all (it is not a zero
220
+ allowance), and then `overage` must be `null` too.
221
+ - `overage` prices `max(0, list_cost - allowance)`:
222
+ `{"type": "charge_multiplier", "value": "0.5"}` charges overage × value
223
+ (`0 <= value <= 1`), and `{"type": "block_discount", "block_usd": "5",
224
+ "discount_usd": "1"}` charges overage minus `floor(overage / block_usd) ×
225
+ discount_usd` (`0 < discount_usd <= block_usd`).
226
+ - Amounts are decimal strings only (no JSON numbers), at most 28
227
+ significant digits. `plan_id` is `[A-Za-z0-9_-]{1,32}`, `period_id`
228
+ `[A-Za-z0-9_-]{1,16}`, `nonce` 32 lowercase hex characters (e.g.
229
+ `python3 -c 'import secrets; print(secrets.token_hex(16))'`). Unknown or
230
+ duplicate keys are errors. v1 only accepts `scope: "seat"`: an allowance
231
+ shared by a department or org cannot be computed from one person's logs.
232
+
233
+ The JSON output gains an `internal_billing` block (existing keys are
234
+ unchanged), and the table gains a section headed `Internal billing
235
+ (CONFIDENTIAL -- do not share)`. For each window that intersects
236
+ `[since, until)` it shows `list_cost_usd` (Claude facts in the window,
237
+ priced at the packaged catalog), `allowance_usd`, `overage_usd`,
238
+ `overage_cost_usd`, `window_subscription_usd`, `internal_cost_usd` --
239
+ all as 4-decimal strings -- and four separate status fields:
240
+
241
+ - `query_coverage`: `full` when `--since`/`--until` cover the whole
242
+ window, otherwise `partial`. It says nothing about whether the logs
243
+ themselves are complete (deleted transcripts, other machines, API or web
244
+ usage are never seen; see `data_quality` at the top level as well).
245
+ - `window_state`: `closed` once the window has ended (`until <=
246
+ generated_at`), otherwise `open`.
247
+ - `list_cost_pricing`: `priced`, `lower_bound` (some facts were unpriced
248
+ or only priced as a lower bound, or an output fact's tokens are only a
249
+ lower bound -- `source_quality: "output_lower_bound"`) or
250
+ `no_usage_observed`.
251
+ - `internal_cost_certainty`: `estimate` only when the window is fully
252
+ queried, closed and `priced`. Otherwise `lower_bound` for windows with no
253
+ overage or `charge_multiplier` (more usage can only raise the amount), and
254
+ `indeterminate` for `block_discount` (more usage can cross a block
255
+ boundary and lower it). This describes what can be derived from the
256
+ observed list cost -- it is not a statement that the number matches an
257
+ actual invoice.
258
+
259
+ `window_subscription_usd` in each row is the plan's input echoed back, not
260
+ an amount allocated to your query. `internal_cost_usd` is the cost of the
261
+ whole billing window computed from the usage visible in this report -- it
262
+ is not the cost of the `[since, until)` range, so do not sum windows to get
263
+ one. `plan_coverage: partial` with `uncovered` ranges flags the parts of
264
+ `[since, until)` that no window covers (before the first window or after
265
+ `terminates`); usage there is not billed.
266
+
267
+ `measure` has no billing plan option on purpose: a per-session internal
268
+ cost would mean allocating a window-level charge across sessions.
269
+ `--billing-plan` cannot be combined with `--rates` (the basis must be the
270
+ packaged public catalog), `--format csv`, an `--agent` list without
271
+ `claude`, or a missing `--since`/`--until`; any of those, an unreadable or
272
+ invalid plan, or a calculation that would need rounding exits 2 with
273
+ nothing on stdout. `AGENT_COST_NOW` (an ISO 8601 instant with a UTC offset)
274
+ pins `generated_at`, and with it `window_state`, for reproducible runs.
275
+
276
+ **Keep the plan and its output private.** The plan must be a regular file
277
+ owned by you with mode `0600` (or stricter), reached without any symlink in
278
+ its path (on macOS `/tmp` and `/var` are symlinks -- keep it under your
279
+ home directory), and not inside a git repository or worktree. Error messages
280
+ never print plan values or the path. Output produced with the plan is
281
+ confidential: agent-cost has no redaction, so mind your terminal scrollback,
282
+ shell history, and the permissions of any file you redirect it to, and keep
283
+ it out of shared logs, CI, artifacts and ledgers.
284
+
177
285
  ## What this measures, and what it doesn't
178
286
 
179
287
  agent-cost only reads data that is already on disk. It never talks to the
@@ -453,6 +561,9 @@ MIT. See [LICENSE](LICENSE).
453
561
  subprocess で叩くための機械可読な契約です(`protocol_version: "measure/v1"`)。指定した
454
562
  session_id が1件も見つからなくても終了コードは0(空集計として表現)、`--session-id` 未指定など
455
563
  の入力エラーのみ終了コード2です。
564
+ - `report --billing-plan PATH`(任意・機密)は、ローカルの課金プラン(窓ごとの定額・利用枠・超過規則)を
565
+ 公開単価で集計した Claude の list_cost に当てて `internal_billing` を出します。フラグ無しの出力は不変です。
566
+ - plan ファイルは 0600・symlink 不可・git repo 外に置き、出力は機密成果物として扱います(`measure` には按分になるため無し)。
456
567
  - 破損したログ行、読めなくなったファイル、Codex の累積カウンタが逆行するケースなどは、すべて
457
568
  `data_quality` に件数として記録し、黙って丸めたり捨てたりしません。
458
569
  - Codex の `output` は `output_tokens` のみです。実 rollout データを突合した結果
@@ -6,4 +6,4 @@ against a versioned rate catalog. Everything happens locally; there are no
6
6
  network calls.
7
7
  """
8
8
 
9
- __version__ = "0.4.0"
9
+ __version__ = "0.5.0"