tallyline 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.
- tallyline-0.1.0/.github/workflows/ci.yml +24 -0
- tallyline-0.1.0/.github/workflows/release.yml +49 -0
- tallyline-0.1.0/.github/workflows/update-prices.yml +37 -0
- tallyline-0.1.0/.gitignore +8 -0
- tallyline-0.1.0/LICENSE +21 -0
- tallyline-0.1.0/PKG-INFO +129 -0
- tallyline-0.1.0/README.ja.md +110 -0
- tallyline-0.1.0/README.md +112 -0
- tallyline-0.1.0/assets/screenshot.png +0 -0
- tallyline-0.1.0/pyproject.toml +41 -0
- tallyline-0.1.0/scripts/update_prices.py +30 -0
- tallyline-0.1.0/src/tallyline/__init__.py +4 -0
- tallyline-0.1.0/src/tallyline/__main__.py +3 -0
- tallyline-0.1.0/src/tallyline/_version.py +24 -0
- tallyline-0.1.0/src/tallyline/cli.py +147 -0
- tallyline-0.1.0/src/tallyline/config.py +28 -0
- tallyline-0.1.0/src/tallyline/paths.py +24 -0
- tallyline-0.1.0/src/tallyline/prices.json +142 -0
- tallyline-0.1.0/src/tallyline/pricing.py +108 -0
- tallyline-0.1.0/src/tallyline/render.py +177 -0
- tallyline-0.1.0/src/tallyline/store.py +211 -0
- tallyline-0.1.0/src/tallyline/update.py +86 -0
- tallyline-0.1.0/tests/conftest.py +29 -0
- tallyline-0.1.0/tests/test_cli.py +83 -0
- tallyline-0.1.0/tests/test_pricing.py +71 -0
- tallyline-0.1.0/tests/test_render.py +194 -0
- tallyline-0.1.0/tests/test_store.py +137 -0
- tallyline-0.1.0/tests/test_update.py +60 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
strategy:
|
|
11
|
+
fail-fast: false
|
|
12
|
+
matrix:
|
|
13
|
+
os: [ubuntu-latest, macos-latest]
|
|
14
|
+
python: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
15
|
+
runs-on: ${{ matrix.os }}
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
with:
|
|
19
|
+
fetch-depth: 0
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python }}
|
|
23
|
+
- run: pip install -e . pytest
|
|
24
|
+
- run: pytest -q
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Publishes to PyPI via trusted publishing (no API token stored in the repo).
|
|
4
|
+
# - Pushing a tag like v0.2.0 releases that version. The first release is always made
|
|
5
|
+
# this way.
|
|
6
|
+
# - A merge to main that changes prices.json releases the next patch version, but only
|
|
7
|
+
# once a first release exists; before that it does nothing.
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
tags: ["v*"]
|
|
11
|
+
branches: [main]
|
|
12
|
+
paths: ["src/tallyline/prices.json"]
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
release:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
environment: pypi
|
|
19
|
+
permissions:
|
|
20
|
+
contents: write
|
|
21
|
+
id-token: write
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 0
|
|
26
|
+
- name: Tag next patch version
|
|
27
|
+
id: version
|
|
28
|
+
if: github.ref_type == 'branch'
|
|
29
|
+
run: |
|
|
30
|
+
last=$(git describe --tags --abbrev=0 --match 'v*' 2>/dev/null || true)
|
|
31
|
+
if [ -z "$last" ]; then
|
|
32
|
+
echo "No release yet; push a tag like v0.1.0 to make the first one."
|
|
33
|
+
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
IFS=. read -r major minor patch <<< "${last#v}"
|
|
37
|
+
next="v${major}.${minor}.$((patch + 1))"
|
|
38
|
+
git tag "$next"
|
|
39
|
+
git push origin "$next"
|
|
40
|
+
- uses: actions/setup-python@v5
|
|
41
|
+
if: steps.version.outputs.skip != 'true'
|
|
42
|
+
with:
|
|
43
|
+
python-version: "3.13"
|
|
44
|
+
- if: steps.version.outputs.skip != 'true'
|
|
45
|
+
run: pip install build pytest && pip install -e . && pytest -q
|
|
46
|
+
- if: steps.version.outputs.skip != 'true'
|
|
47
|
+
run: python -m build
|
|
48
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
49
|
+
if: steps.version.outputs.skip != 'true'
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Update prices
|
|
2
|
+
|
|
3
|
+
# Checks Anthropic's pricing page daily and opens a pull request when the bundled
|
|
4
|
+
# price table changes. Merging that PR triggers an automatic patch release.
|
|
5
|
+
on:
|
|
6
|
+
schedule:
|
|
7
|
+
- cron: "17 3 * * *"
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: write
|
|
12
|
+
pull-requests: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
update:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.13"
|
|
24
|
+
- run: python scripts/update_prices.py
|
|
25
|
+
# PRs opened with GITHUB_TOKEN don't trigger other workflows, so test here.
|
|
26
|
+
- run: pip install -e . pytest && pytest -q
|
|
27
|
+
- uses: peter-evans/create-pull-request@v7
|
|
28
|
+
with:
|
|
29
|
+
branch: update-prices
|
|
30
|
+
commit-message: Update model prices from Anthropic pricing page
|
|
31
|
+
title: Update model prices
|
|
32
|
+
body: |
|
|
33
|
+
Automated update of `src/tallyline/prices.json` from
|
|
34
|
+
https://platform.claude.com/docs/en/about-claude/pricing
|
|
35
|
+
|
|
36
|
+
Review the diff against the pricing page. Merging releases a new patch version.
|
|
37
|
+
add-paths: src/tallyline/prices.json
|
tallyline-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nhinata
|
|
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.
|
tallyline-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: tallyline
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Claude Code status line that tallies your token usage and API-equivalent cost by day, month and year
|
|
5
|
+
Project-URL: Repository, https://github.com/nhinata/tallyline
|
|
6
|
+
Author: nhinata
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: claude-code,cost,statusline,tokens,usage
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Operating System :: MacOS
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Utilities
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# tallyline
|
|
19
|
+
|
|
20
|
+
A Claude Code status line that **tallies your token usage and API-equivalent cost by day, month and year**, across every session.
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
Pro/Max plan: [Opus 5.5] │ ctx 12% │ Oct 22.1M tok (≈$14.92) │ 5h 23% 7d 41%
|
|
26
|
+
API billing: [Opus 5.5] │ ctx 12% 6.6M tok (≈$3.85) │ Oct 22.1M tok (≈$14.92)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Segments widen in scope from left to right: this session (cyan), all sessions on this machine (yellow), your whole account (magenta).
|
|
30
|
+
|
|
31
|
+
[日本語版 README](README.ja.md)
|
|
32
|
+
|
|
33
|
+
## Why
|
|
34
|
+
|
|
35
|
+
Claude Code's status line only knows about the current session. tallyline keeps a running ledger of every session on your machine, so you can answer "how much have I used this month?" at a glance. On a Pro/Max plan, the API-equivalent cost tells you what your usage would have cost on the pay-as-you-go API.
|
|
36
|
+
|
|
37
|
+
- **Fast**: after the first scan it parses only newly appended transcript bytes. A render takes about 25 ms.
|
|
38
|
+
- **Local only**: apart from a once-a-day update check that asks PyPI for the latest version number, tallyline makes no network requests. It never sends your conversations or usage data anywhere. Turn the check off with `tallyline config update-check off` or `NO_UPDATE_NOTIFIER=1`.
|
|
39
|
+
- **No dependencies**: it uses only the Python standard library (Python 3.9+).
|
|
40
|
+
- **Accurate**: it removes duplicate transcript lines written while a response streams. Without that, a naive sum roughly doubles your usage.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pipx install tallyline # or: uv tool install tallyline
|
|
46
|
+
tallyline init # adds the statusLine entry to ~/.claude/settings.json
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Restart Claude Code. `init` backs up `settings.json` to `settings.json.bak`. It refuses to replace an existing status line unless you pass `--force`.
|
|
50
|
+
|
|
51
|
+
## What it shows
|
|
52
|
+
|
|
53
|
+
| Segment | Scope | Meaning |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `[Opus 5.5]` | — | Current model |
|
|
56
|
+
| `ctx 12%` | this session | How full the context window is right now. It drops after `/clear` or `/compact` |
|
|
57
|
+
| `5h 23% 7d 41%` | your account | Pro/Max only: usage of your 5-hour and 7-day rate limits, counted across all devices and apps. A window that has reset shows `0%` |
|
|
58
|
+
| `6.6M tok (≈$3.85)` | this session | API billing only: tokens used so far in this session, subagents included |
|
|
59
|
+
| `Oct 22.1M tok (≈$14.92)` | all sessions on this machine | Total for the period (`today`, the month, or the year) |
|
|
60
|
+
|
|
61
|
+
A `*` after the period, as in `2026*`, means tallyline's records start partway through that period, so the total is incomplete. This is normal right after installing: Claude Code keeps only recent transcripts (see Caveats).
|
|
62
|
+
|
|
63
|
+
tallyline picks between rate limits and session usage automatically. Claude Code sends rate limits only to Pro/Max subscribers, and for them the per-session cost has little meaning.
|
|
64
|
+
|
|
65
|
+
Claude Code sends rate limits only after a session's first response, so tallyline remembers the latest values seen in any session. A new session shows them right away, and every session shows the newest value seen on this machine. Usage on claude.ai or other devices appears after your next response, so treat the figures as "at least".
|
|
66
|
+
|
|
67
|
+
Every turn re-reads the whole context, so cumulative tokens grow much faster than `ctx`. Most of them are cache reads.
|
|
68
|
+
|
|
69
|
+
Token totals include input, output, cache writes and cache reads. Cache reads are cheap, so the `≈$` cost is the better gauge of how heavily you are using Claude. The cost is an API-equivalent estimate at list prices.
|
|
70
|
+
|
|
71
|
+
## Configuration
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
tallyline config range month # today | month | year | all
|
|
75
|
+
tallyline config cost off # hide cost figures
|
|
76
|
+
tallyline config color off # plain text (NO_COLOR is honored too)
|
|
77
|
+
tallyline config update-check off # no daily version check (or set NO_UPDATE_NOTIFIER=1)
|
|
78
|
+
tallyline config # show current settings
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Settings live in `~/.config/tallyline/config.json`. The cache lives in `~/.cache/tallyline/usage.db`. `tallyline rebuild` re-scans every transcript. It keeps the history of transcripts that Claude Code has already deleted.
|
|
82
|
+
|
|
83
|
+
### Prices
|
|
84
|
+
|
|
85
|
+
Prices come from a table bundled with each release, generated from [Anthropic's pricing page](https://platform.claude.com/docs/en/about-claude/pricing). A scheduled GitHub Actions job checks that page daily and opens a pull request when prices change. Costs are computed when the status line renders, so a price update also applies to past usage.
|
|
86
|
+
|
|
87
|
+
If a model is missing from the table, its cost shows as `+?`. To fill in a price without waiting for a release, add it to `config.json`. Prices are USD per million tokens:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"prices": {
|
|
92
|
+
"claude-new-model": {
|
|
93
|
+
"input": 3, "cache_write_5m": 3.75, "cache_write_1h": 6,
|
|
94
|
+
"cache_read": 0.3, "output": 15
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Fast mode requests are multiplied by each model's `fast_multiplier`.
|
|
101
|
+
|
|
102
|
+
## Caveats
|
|
103
|
+
|
|
104
|
+
- The cost is an estimate at list prices, not a bill. On Pro/Max plans you pay your plan price.
|
|
105
|
+
- tallyline only sees what Claude Code writes to transcripts. Some background requests are never recorded there, so totals can come out lower than `/cost`. In one auto mode session, tallyline counted about 15% less than `/cost` (likely the permission checks auto mode runs). Tokens and cost come from the same transcripts, so the two always match each other.
|
|
106
|
+
- Claude Code deletes old transcripts after `cleanupPeriodDays` (30 by default). tallyline keeps whatever it has already ingested, but it can't count transcripts that were deleted before you installed it.
|
|
107
|
+
- Transcript files are an internal Claude Code format and may change.
|
|
108
|
+
- If you switch between several Claude accounts on one machine, their rate limit records can mix.
|
|
109
|
+
- Not affiliated with or endorsed by Anthropic.
|
|
110
|
+
|
|
111
|
+
## Updating
|
|
112
|
+
|
|
113
|
+
When a newer release is out, the status line ends with `↑ 0.2.0`. Run:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
pipx upgrade tallyline # or: uv tool upgrade tallyline
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
New releases also carry the latest model prices.
|
|
120
|
+
|
|
121
|
+
## Uninstall
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
tallyline uninstall && pipx uninstall tallyline
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# tallyline
|
|
2
|
+
|
|
3
|
+
Claude Code の**全セッションのトークン使用量と API 換算の金額を、日・月・年ごとに集計して表示する**ステータスラインです。
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Pro / Max プラン: [Opus 5.5] │ ctx 12% │ Oct 22.1M tok (≈$14.92) │ 5h 23% 7d 41%
|
|
9
|
+
API 従量課金: [Opus 5.5] │ ctx 12% 6.6M tok (≈$3.85) │ Oct 22.1M tok (≈$14.92)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
左から右へ、範囲が広がる順に並んでいます。このセッション(水色)、このマシンの全セッション(黄色)、アカウント全体(紫)です。
|
|
13
|
+
|
|
14
|
+
## 特徴
|
|
15
|
+
|
|
16
|
+
Claude Code 標準のステータスラインに渡されるのは、今のセッションの情報だけです。tallyline はこのマシンの全セッションを記録し続けるので、「今月どれだけ使ったか」をひと目で確認できます。Pro / Max プランの人は、API 換算の金額を見れば、従量課金の API だったらいくらかかっていたかが分かります。
|
|
17
|
+
|
|
18
|
+
- **速い**:最初の1回以降は、ログに新しく追記された分だけを読みます。表示にかかる時間は約 25ms です。
|
|
19
|
+
- **ローカルで完結**:1日1回の更新確認(PyPI に最新版の番号を問い合わせるだけ)を除いて、外部とは一切通信しません。会話の内容や使用量などのデータを送ることはありません。更新確認は `tallyline config update-check off` か、環境変数 `NO_UPDATE_NOTIFIER=1` で止められます。
|
|
20
|
+
- **依存なし**:Python 3.9 以上の標準機能だけで動きます。
|
|
21
|
+
- **正確**:応答の途中経過として重複して記録された行を除外します。単純に合計すると、使用量が約2倍に膨らみます。
|
|
22
|
+
|
|
23
|
+
## インストール
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pipx install tallyline # または: uv tool install tallyline
|
|
27
|
+
tallyline init # ~/.claude/settings.json に statusLine を追加
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
追加したら Claude Code を再起動してください。`init` は実行前に `settings.json.bak` としてバックアップを作ります。すでに別のステータスラインが設定されている場合は置き換えません。置き換えたいときは `--force` を付けてください。
|
|
31
|
+
|
|
32
|
+
## 表示内容
|
|
33
|
+
|
|
34
|
+
| 表示 | 範囲 | 意味 |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `[Opus 5.5]` | — | 使用中のモデル |
|
|
37
|
+
| `ctx 12%` | このセッション | 今この瞬間のコンテキスト(会話)の埋まり具合。`/clear` や `/compact` で下がる |
|
|
38
|
+
| `5h 23% 7d 41%` | アカウント全体 | Pro / Max プランのみ:5時間・7日間の利用上限に対する使用率(すべての端末・アプリでの利用を含む)。リセットされた枠は `0%` と表示 |
|
|
39
|
+
| `6.6M tok (≈$3.85)` | このセッション | API 従量課金のみ:このセッションで使った累計トークン数(サブエージェント分を含む) |
|
|
40
|
+
| `Oct 22.1M tok (≈$14.92)` | このマシンの全セッション | 期間(`today`・当月・当年)内の合計 |
|
|
41
|
+
|
|
42
|
+
`2026*` のように期間の後ろに `*` が付いている場合は、記録がその期間の途中からしかなく、合計が不完全であることを表します。インストール直後はこの状態になるのが普通です。Claude Code は最近のログしか残していないためです(「注意事項」を参照)。
|
|
43
|
+
|
|
44
|
+
利用上限とセッションの使用量のどちらを出すかは、自動で切り替わります。Claude Code は利用上限の情報を Pro / Max の利用者にだけ渡します。また、定額プランではセッション単位の金額にあまり意味がありません。
|
|
45
|
+
|
|
46
|
+
Claude Code が利用上限の情報を渡すのは、各セッションで最初の応答を受け取った後です。そのため tallyline は、どのセッションで受け取った値も、最新のものを記録しておきます。これにより、新しいセッションでもすぐに利用上限が表示され、どのセッションでもこのマシンで受け取った最新の値が表示されます。claude.ai や他の端末での利用は次の応答で反映されるので、表示は「少なくともこの値」と考えてください。
|
|
47
|
+
|
|
48
|
+
Claude は返答のたびにコンテキスト全体を読み直すため、累計トークン数は `ctx` よりずっと速く増えます。その大部分はキャッシュ読み込みです。
|
|
49
|
+
|
|
50
|
+
トークン数は、入力・出力・キャッシュ作成・キャッシュ読み込みの合計です。キャッシュ読み込みは単価が安いため、どれだけ使い込んでいるかは `≈$` の金額の方が実態に近く表れます。この金額は、定価で計算した API 換算の推定値です。
|
|
51
|
+
|
|
52
|
+
## 設定
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
tallyline config range month # today / month / year / all
|
|
56
|
+
tallyline config cost off # 金額を非表示にする
|
|
57
|
+
tallyline config color off # 色なしで表示(環境変数 NO_COLOR にも対応)
|
|
58
|
+
tallyline config update-check off # 1日1回の更新確認を止める(環境変数 NO_UPDATE_NOTIFIER=1 でも可)
|
|
59
|
+
tallyline config # 現在の設定を表示
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
設定は `~/.config/tallyline/config.json` に、集計の記録は `~/.cache/tallyline/usage.db` に保存されます。`tallyline rebuild` を実行すると、全ログを読み直します。Claude Code がすでに削除したログの分の記録は、消えずに残ります。
|
|
63
|
+
|
|
64
|
+
### 単価
|
|
65
|
+
|
|
66
|
+
単価は、[Anthropic の公式料金ページ](https://platform.claude.com/docs/en/about-claude/pricing)から生成した単価表を、各リリースに同梱しています。GitHub Actions が毎日このページを確認し、料金が変わっていればプルリクエストを自動で作ります。金額は表示のたびに計算するので、単価表が更新されると過去の使用分にも新しい単価が反映されます。
|
|
67
|
+
|
|
68
|
+
単価表にないモデルの金額は `+?` と表示されます。リリースを待たずに単価を追加したい場合は、`config.json` に書き足してください(単位は 100万トークンあたりの米ドル)。
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"prices": {
|
|
73
|
+
"claude-new-model": {
|
|
74
|
+
"input": 3, "cache_write_5m": 3.75, "cache_write_1h": 6,
|
|
75
|
+
"cache_read": 0.3, "output": 15
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Fast モードで処理されたリクエストは、モデルごとの `fast_multiplier` を掛けて計算します。
|
|
82
|
+
|
|
83
|
+
## 注意事項
|
|
84
|
+
|
|
85
|
+
- 表示される金額は定価での推定で、実際の請求額ではありません。Pro / Max プランで実際に支払うのはプランの料金です。
|
|
86
|
+
- tallyline が数えられるのは、Claude Code がログに書き出した分だけです。裏側で行われるやり取りの一部はログに記録されないため、合計が `/cost` より少なく出ることがあります。自動モードのセッションで比べたところ、`/cost` より約15%少なくなりました(自動モードの許可判定が原因とみられます)。トークン数と金額は同じログから計算しているので、この2つは常に食い違いません。
|
|
87
|
+
- Claude Code は古いログを `cleanupPeriodDays`(初期設定は30日)で削除します。tallyline は一度取り込んだ分を保持し続けますが、インストール前に削除されたログの分は集計できません。
|
|
88
|
+
- ログファイルは Claude Code の内部形式なので、将来変わる可能性があります。
|
|
89
|
+
- 1台のマシンで複数の Claude アカウントを切り替えて使うと、アカウント間で利用上限の記録が混ざることがあります。
|
|
90
|
+
- Anthropic の公式ツールではありません。
|
|
91
|
+
|
|
92
|
+
## 更新
|
|
93
|
+
|
|
94
|
+
新しい版が出ると、ステータスラインの末尾に `↑ 0.2.0` のように表示されます。次のコマンドで更新してください。
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pipx upgrade tallyline # または: uv tool upgrade tallyline
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
新しい版には、最新のモデル単価も含まれています。
|
|
101
|
+
|
|
102
|
+
## アンインストール
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
tallyline uninstall && pipx uninstall tallyline
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## ライセンス
|
|
109
|
+
|
|
110
|
+
MIT
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# tallyline
|
|
2
|
+
|
|
3
|
+
A Claude Code status line that **tallies your token usage and API-equivalent cost by day, month and year**, across every session.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Pro/Max plan: [Opus 5.5] │ ctx 12% │ Oct 22.1M tok (≈$14.92) │ 5h 23% 7d 41%
|
|
9
|
+
API billing: [Opus 5.5] │ ctx 12% 6.6M tok (≈$3.85) │ Oct 22.1M tok (≈$14.92)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Segments widen in scope from left to right: this session (cyan), all sessions on this machine (yellow), your whole account (magenta).
|
|
13
|
+
|
|
14
|
+
[日本語版 README](README.ja.md)
|
|
15
|
+
|
|
16
|
+
## Why
|
|
17
|
+
|
|
18
|
+
Claude Code's status line only knows about the current session. tallyline keeps a running ledger of every session on your machine, so you can answer "how much have I used this month?" at a glance. On a Pro/Max plan, the API-equivalent cost tells you what your usage would have cost on the pay-as-you-go API.
|
|
19
|
+
|
|
20
|
+
- **Fast**: after the first scan it parses only newly appended transcript bytes. A render takes about 25 ms.
|
|
21
|
+
- **Local only**: apart from a once-a-day update check that asks PyPI for the latest version number, tallyline makes no network requests. It never sends your conversations or usage data anywhere. Turn the check off with `tallyline config update-check off` or `NO_UPDATE_NOTIFIER=1`.
|
|
22
|
+
- **No dependencies**: it uses only the Python standard library (Python 3.9+).
|
|
23
|
+
- **Accurate**: it removes duplicate transcript lines written while a response streams. Without that, a naive sum roughly doubles your usage.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pipx install tallyline # or: uv tool install tallyline
|
|
29
|
+
tallyline init # adds the statusLine entry to ~/.claude/settings.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Restart Claude Code. `init` backs up `settings.json` to `settings.json.bak`. It refuses to replace an existing status line unless you pass `--force`.
|
|
33
|
+
|
|
34
|
+
## What it shows
|
|
35
|
+
|
|
36
|
+
| Segment | Scope | Meaning |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `[Opus 5.5]` | — | Current model |
|
|
39
|
+
| `ctx 12%` | this session | How full the context window is right now. It drops after `/clear` or `/compact` |
|
|
40
|
+
| `5h 23% 7d 41%` | your account | Pro/Max only: usage of your 5-hour and 7-day rate limits, counted across all devices and apps. A window that has reset shows `0%` |
|
|
41
|
+
| `6.6M tok (≈$3.85)` | this session | API billing only: tokens used so far in this session, subagents included |
|
|
42
|
+
| `Oct 22.1M tok (≈$14.92)` | all sessions on this machine | Total for the period (`today`, the month, or the year) |
|
|
43
|
+
|
|
44
|
+
A `*` after the period, as in `2026*`, means tallyline's records start partway through that period, so the total is incomplete. This is normal right after installing: Claude Code keeps only recent transcripts (see Caveats).
|
|
45
|
+
|
|
46
|
+
tallyline picks between rate limits and session usage automatically. Claude Code sends rate limits only to Pro/Max subscribers, and for them the per-session cost has little meaning.
|
|
47
|
+
|
|
48
|
+
Claude Code sends rate limits only after a session's first response, so tallyline remembers the latest values seen in any session. A new session shows them right away, and every session shows the newest value seen on this machine. Usage on claude.ai or other devices appears after your next response, so treat the figures as "at least".
|
|
49
|
+
|
|
50
|
+
Every turn re-reads the whole context, so cumulative tokens grow much faster than `ctx`. Most of them are cache reads.
|
|
51
|
+
|
|
52
|
+
Token totals include input, output, cache writes and cache reads. Cache reads are cheap, so the `≈$` cost is the better gauge of how heavily you are using Claude. The cost is an API-equivalent estimate at list prices.
|
|
53
|
+
|
|
54
|
+
## Configuration
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
tallyline config range month # today | month | year | all
|
|
58
|
+
tallyline config cost off # hide cost figures
|
|
59
|
+
tallyline config color off # plain text (NO_COLOR is honored too)
|
|
60
|
+
tallyline config update-check off # no daily version check (or set NO_UPDATE_NOTIFIER=1)
|
|
61
|
+
tallyline config # show current settings
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Settings live in `~/.config/tallyline/config.json`. The cache lives in `~/.cache/tallyline/usage.db`. `tallyline rebuild` re-scans every transcript. It keeps the history of transcripts that Claude Code has already deleted.
|
|
65
|
+
|
|
66
|
+
### Prices
|
|
67
|
+
|
|
68
|
+
Prices come from a table bundled with each release, generated from [Anthropic's pricing page](https://platform.claude.com/docs/en/about-claude/pricing). A scheduled GitHub Actions job checks that page daily and opens a pull request when prices change. Costs are computed when the status line renders, so a price update also applies to past usage.
|
|
69
|
+
|
|
70
|
+
If a model is missing from the table, its cost shows as `+?`. To fill in a price without waiting for a release, add it to `config.json`. Prices are USD per million tokens:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"prices": {
|
|
75
|
+
"claude-new-model": {
|
|
76
|
+
"input": 3, "cache_write_5m": 3.75, "cache_write_1h": 6,
|
|
77
|
+
"cache_read": 0.3, "output": 15
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Fast mode requests are multiplied by each model's `fast_multiplier`.
|
|
84
|
+
|
|
85
|
+
## Caveats
|
|
86
|
+
|
|
87
|
+
- The cost is an estimate at list prices, not a bill. On Pro/Max plans you pay your plan price.
|
|
88
|
+
- tallyline only sees what Claude Code writes to transcripts. Some background requests are never recorded there, so totals can come out lower than `/cost`. In one auto mode session, tallyline counted about 15% less than `/cost` (likely the permission checks auto mode runs). Tokens and cost come from the same transcripts, so the two always match each other.
|
|
89
|
+
- Claude Code deletes old transcripts after `cleanupPeriodDays` (30 by default). tallyline keeps whatever it has already ingested, but it can't count transcripts that were deleted before you installed it.
|
|
90
|
+
- Transcript files are an internal Claude Code format and may change.
|
|
91
|
+
- If you switch between several Claude accounts on one machine, their rate limit records can mix.
|
|
92
|
+
- Not affiliated with or endorsed by Anthropic.
|
|
93
|
+
|
|
94
|
+
## Updating
|
|
95
|
+
|
|
96
|
+
When a newer release is out, the status line ends with `↑ 0.2.0`. Run:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pipx upgrade tallyline # or: uv tool upgrade tallyline
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
New releases also carry the latest model prices.
|
|
103
|
+
|
|
104
|
+
## Uninstall
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
tallyline uninstall && pipx uninstall tallyline
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT
|
|
Binary file
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tallyline"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Claude Code status line that tallies your token usage and API-equivalent cost by day, month and year"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
authors = [{ name = "nhinata" }]
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
requires-python = ">=3.9"
|
|
14
|
+
dependencies = []
|
|
15
|
+
keywords = ["claude-code", "statusline", "tokens", "usage", "cost"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Operating System :: MacOS",
|
|
19
|
+
"Operating System :: POSIX :: Linux",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Topic :: Utilities",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Repository = "https://github.com/nhinata/tallyline"
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
tallyline = "tallyline.cli:main"
|
|
29
|
+
|
|
30
|
+
[tool.hatch.version]
|
|
31
|
+
source = "vcs"
|
|
32
|
+
fallback-version = "0.0.0"
|
|
33
|
+
|
|
34
|
+
[tool.hatch.build.hooks.vcs]
|
|
35
|
+
version-file = "src/tallyline/_version.py"
|
|
36
|
+
|
|
37
|
+
[tool.hatch.build.targets.wheel]
|
|
38
|
+
packages = ["src/tallyline"]
|
|
39
|
+
|
|
40
|
+
[tool.pytest.ini_options]
|
|
41
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Regenerate src/tallyline/prices.json from Anthropic's official pricing page.
|
|
2
|
+
|
|
3
|
+
Run by the update-prices GitHub Actions workflow; exits non-zero if parsing fails
|
|
4
|
+
so a broken page layout never ships an empty table.
|
|
5
|
+
"""
|
|
6
|
+
import json
|
|
7
|
+
import sys
|
|
8
|
+
import urllib.request
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
|
12
|
+
from tallyline.pricing import parse_pricing_page # noqa: E402
|
|
13
|
+
|
|
14
|
+
SOURCE = "https://platform.claude.com/docs/en/about-claude/pricing.md"
|
|
15
|
+
OUT = Path(__file__).resolve().parents[1] / "src" / "tallyline" / "prices.json"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def main():
|
|
19
|
+
req = urllib.request.Request(SOURCE, headers={"User-Agent": "tallyline-price-updater"})
|
|
20
|
+
with urllib.request.urlopen(req, timeout=30) as r:
|
|
21
|
+
markdown = r.read().decode("utf-8")
|
|
22
|
+
models = parse_pricing_page(markdown)
|
|
23
|
+
data = {"source": SOURCE, "unit": "USD per million tokens",
|
|
24
|
+
"models": dict(sorted(models.items()))}
|
|
25
|
+
OUT.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
|
|
26
|
+
print(f"wrote {len(models)} models to {OUT}")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == "__main__":
|
|
30
|
+
main()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.1.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|