tokc 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.
tokc-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sylvain Mestre
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.
tokc-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,299 @@
1
+ Metadata-Version: 2.4
2
+ Name: tokc
3
+ Version: 0.1.0
4
+ Summary: Measure and shrink the token cost of Claude Code skills.
5
+ Author: Sylvain Mestre
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Shult/token_consumer
8
+ Project-URL: Repository, https://github.com/Shult/token_consumer
9
+ Project-URL: Issues, https://github.com/Shult/token_consumer/issues
10
+ Project-URL: Changelog, https://github.com/Shult/token_consumer/blob/main/CHANGELOG.md
11
+ Keywords: claude,claude-code,skills,tokens,cost,llm
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Provides-Extra: fast
24
+ Requires-Dist: tiktoken>=0.7; extra == "fast"
25
+ Provides-Extra: exact
26
+ Requires-Dist: anthropic>=0.40; extra == "exact"
27
+ Provides-Extra: yaml
28
+ Requires-Dist: pyyaml>=6; extra == "yaml"
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=8; extra == "dev"
31
+ Requires-Dist: tiktoken>=0.7; extra == "dev"
32
+ Requires-Dist: pyyaml>=6; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # tokc — token consumption analyzer for Claude Code skills
36
+
37
+ [![CI](https://github.com/Shult/token_consumer/actions/workflows/ci.yml/badge.svg)](https://github.com/Shult/token_consumer/actions/workflows/ci.yml)
38
+ [![PyPI](https://img.shields.io/pypi/v/tokc.svg)](https://pypi.org/project/tokc/)
39
+ [![Python](https://img.shields.io/pypi/pyversions/tokc.svg)](https://pypi.org/project/tokc/)
40
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
41
+
42
+ Measures what a skill actually costs you, tier by tier, and tells you where to cut.
43
+
44
+ ```
45
+ 29 skill(s) tokenizer: o200k_base x1.180 (default)
46
+
47
+ SKILL T1/sess T2/use T3 ALWAYS-ON TAX $/mo
48
+ ------------------------------------------------------------------------------
49
+ project-artifact 241 5,415 8.5k ████████████████████████ ! $2.99
50
+ receipts 159 4,865 20k ████████████████ ! $2.40
51
+ hook-development 140 4,548 16k ██████████████ $2.20
52
+ ...
53
+ ------------------------------------------------------------------------------
54
+ TOTAL 2,787 99,352 294k $45.65
55
+
56
+ Always-on tax
57
+ 2,787 tokens ride in the system prompt of every request, in every session,
58
+ whether or not any skill fires.
59
+ -> 2.9M billed token-equivalents/month at 200 sessions x 40 requests
60
+
61
+ Listing budget (characters, not tokens)
62
+ ████████████████████████████████████████ 10,577 / 8,000 chars (132%)
63
+ ! 2,577 chars over budget -- 6 skill(s) ship as `- name`, description omitted
64
+ demoted, least-used first: plugin-structure, project-artifact, receipts, ...
65
+ ```
66
+
67
+ ## Why this exists
68
+
69
+ Existing tools estimate skill cost by asking Claude — which costs tokens and gives
70
+ different numbers each run — or by running `tiktoken` over `SKILL.md`, which
71
+ **undercounts Claude by 15-20%** and, worse, reports a single number for something
72
+ that is not a single cost.
73
+
74
+ A skill is loaded in three tiers, billed at wildly different frequencies:
75
+
76
+ | Tier | What | Paid |
77
+ |---|---|---|
78
+ | **T1** | frontmatter `name` + `description` (+ `whenToUse`, which the listing appends) | in the system prompt of **every request, every session** |
79
+ | **T2** | the `SKILL.md` body | once per invocation |
80
+ | **T3** | `references/`, `scripts/`, … | only when Claude actually reads the file |
81
+
82
+ The number that matters is almost never the one people optimize. A 250-token
83
+ description is re-sent on every request of every session — with prompt caching that
84
+ is a **×5.15 multiplier per session** (1.25× cache write, then 0.10× per read).
85
+ A 6,000-token body that fires five times a month costs less than a 150-token
86
+ description that ships 200 times. `tokc` computes both and ranks accordingly.
87
+
88
+ ## Install
89
+
90
+ ```bash
91
+ pip install tokc # or: uvx tokc scan
92
+ ```
93
+
94
+ Zero hard dependencies. Three optional extras, none required:
95
+
96
+ ```bash
97
+ pip install "tokc[fast]" # tiktoken — much better offline counts
98
+ pip install "tokc[exact]" # anthropic — enables `--exact` and `tokc calibrate`
99
+ pip install "tokc[yaml]" # pyyaml — frontmatter edge cases
100
+ ```
101
+
102
+ Without them `tokc` falls back to a pure-python estimator and a minimal YAML
103
+ parser. Python 3.10+, Linux / macOS / Windows.
104
+
105
+ From source:
106
+
107
+ ```bash
108
+ git clone https://github.com/Shult/token_consumer && cd token_consumer
109
+ pip install -e ".[dev]" # tiktoken + pyyaml + pytest
110
+ ```
111
+
112
+ ## What leaves your machine
113
+
114
+ Nothing, unless you ask for it. Worth stating plainly, because `tokc` reads
115
+ files that are more personal than the skills themselves:
116
+
117
+ **What it reads locally.** Your skill directories; `settings.json` for
118
+ `skillOverrides` and listing settings; `~/.claude.json` for the per-skill usage
119
+ counts that drive the listing order; your installed Claude Code build, to read
120
+ its own defaults out of the settings schema. `tokc setup` additionally scans
121
+ transcripts under `~/.claude`. From those it keeps four things and nothing else:
122
+ the session count, distinct `requestId`s, the *names* of invoked skills (from
123
+ `Skill` / `SlashCommand` tool-use blocks) and the recorded `skill_listing`
124
+ attachment. Prompts, responses and tool output are never retained, and what is
125
+ collected never leaves the summary figures written to your config file.
126
+
127
+ **What it sends.** Only `--exact` and `tokc calibrate` open a network
128
+ connection. They post skill text — frontmatter and body — to Anthropic's
129
+ `count_tokens` endpoint, using your own credentials, and get a token count back.
130
+ Every other command, and every default, is fully offline. `--no-config` ignores
131
+ saved answers entirely.
132
+
133
+ **What it writes.** `./.tokc.json` or `~/.claude/tokc.json` (`tokc setup`), a
134
+ baseline at `./.tokc-baseline.json` (`tokc snapshot`), and the HTML file you
135
+ name (`tokc report -o`). Nothing else on disk is modified — `tokc` never edits
136
+ your skills, it only tells you what to cut.
137
+
138
+ Both config files record local paths and usage figures, so keep them out of
139
+ version control:
140
+
141
+ ```gitignore
142
+ .tokc.json
143
+ .tokc-baseline.json
144
+ ```
145
+
146
+ ## Commands
147
+
148
+ ```bash
149
+ tokc setup # detect your harness, measure your usage, save both
150
+ tokc scan # every skill, ranked by always-on tax
151
+ tokc audit <name|path> # one skill: tiers, body heatmap, findings
152
+ tokc budget # simulate the system-prompt listing budget
153
+ tokc snapshot # record a baseline
154
+ tokc diff # what changed since the baseline
155
+ tokc watch <path> # live token counter while you edit
156
+ tokc report -o out.html # self-contained HTML report
157
+ tokc calibrate # measure the offline estimator against the real API
158
+ ```
159
+
160
+ With no path, `tokc` scans the same roots Claude Code does: `~/.claude/skills`,
161
+ `<project>/.claude/skills`, and installed plugin skills.
162
+
163
+ ### `tokc setup` — stop guessing
164
+
165
+ The numbers below only mean something if they match *your* harness and *your*
166
+ usage. `tokc setup` works both out and writes them to `./.tokc.json` (or
167
+ `~/.claude/tokc.json` with `--user`), which every other command then reads.
168
+
169
+ ```bash
170
+ tokc setup # detect, measure, confirm
171
+ tokc setup -y # accept everything detected
172
+ tokc setup --harness other # a harness tokc cannot inspect: ask, don't assume
173
+ ```
174
+
175
+ Four things, in descending order of trust:
176
+
177
+ 1. **A listing your harness actually sent.** Transcripts record the
178
+ `skill_listing` attachment verbatim, so we compare our reconstruction line by
179
+ line against the real thing — and recover the characters spent by skills
180
+ bundled *inside* the harness, which never appear on disk but still eat the
181
+ budget first.
182
+ 2. **The installed build's own settings schema.** `skillListingMaxDescChars` and
183
+ `skillListingBudgetFraction` defaults are read out of the install (the VS Code
184
+ extension's schema, or the CLI binary), not hard-coded — so an upgrade that
185
+ changes them changes `tokc` too.
186
+ 3. **Your transcripts.** Sessions, API requests per session (counted by distinct
187
+ `requestId`, not by message) and per-skill invocations over the last 30 days,
188
+ replacing the 200 / 40 / 20 defaults.
189
+ 4. **You.** For a harness that cannot be probed — Claude Desktop, claude.ai, a
190
+ third-party client — nothing is assumed. `tokc` says it does not know and asks
191
+ whether the harness caps the listing at all.
192
+
193
+ Precedence runs weakest to strongest: probed defaults → `~/.claude/tokc.json` →
194
+ `./.tokc.json` → the live `settings.json` chain → `SLASH_COMMAND_TOOL_CHAR_BUDGET`
195
+ → command-line flags. `--no-config` ignores the saved answers entirely.
196
+
197
+ ### Tuning the cost model
198
+
199
+ Every projection is driven by explicit, overridable assumptions:
200
+
201
+ ```bash
202
+ tokc scan --sessions 400 --requests 60 --invocations 10 --model claude-sonnet-5
203
+ tokc scan --no-cache # price without prompt caching (worst case)
204
+ ```
205
+
206
+ ### Accuracy
207
+
208
+ Three counting backends, picked automatically:
209
+
210
+ 1. **`--exact`** — Anthropic's `count_tokens` endpoint. Exact. Needs credentials
211
+ (`ANTHROPIC_API_KEY`, or an `ant auth login` profile).
212
+ 2. **tiktoken** — `o200k_base` × a calibration factor (default 1.18, the midpoint
213
+ of Anthropic's stated 15-20% undercount). Offline.
214
+ 3. **heuristic** — pure python, no dependencies. Roughly ±10%.
215
+
216
+ `tokc calibrate` measures backend 2 against backend 1 **on your own skills** and
217
+ stores the corrected factor, so subsequent offline runs are accurate for your corpus.
218
+
219
+ ## What it flags
220
+
221
+ Findings carry the tier they belong to and a savings estimate at the right rate —
222
+ a T1 win is multiplied by sessions, a T2 win by invocations.
223
+
224
+ **Tier 1 — the every-session tax**
225
+ - `T1-DESC-MISSING` / `T1-DESC-BLOAT` / `T1-DESC-TRUNCATED` — over
226
+ `skillListingMaxDescChars` the harness cuts mid-sentence and appends an
227
+ ellipsis, silently losing any trigger keywords at the end. The cap applies to
228
+ `description` and `whenToUse` **together**, since the listing shows the pair.
229
+ - `T1-HIDDEN` / `T1-NAME-ONLY` — `skillOverrides` in `settings.json` took this
230
+ skill out of the listing, or left it there without its description. Reported so
231
+ a zero is not mistaken for a saving.
232
+ - `T1-NO-TRIGGER` — nothing says *when* to use the skill, so you pay the tax and
233
+ never get the benefit. (Recognises English and French trigger phrasing.)
234
+ - `T1-FILLER` — "this skill is used to", "in order to", …
235
+
236
+ **Tier 2 — the per-invocation cost**
237
+ - `T2-BODY-LARGE`, `T2-SECTION-HOG` — one section dominating the body is the
238
+ extraction candidate.
239
+ - `T2-CODE-BLOCK`, `T2-BIG-TABLE` — reference material paid on every invocation.
240
+ - `T2-REPEAT` — lines repeated 3+ times (code fences excluded).
241
+ - `T2-HTML-COMMENT` — invisible when rendered, fully billed to the model.
242
+ - `T2-NO-STRUCTURE`, `T2-WHITESPACE`.
243
+
244
+ **Tier 3 — on-demand files**
245
+ - `T3-UNREFERENCED` — a bundled file `SKILL.md` never points at is unreachable.
246
+ - `T3-HUGE` — reading it will force compaction mid-task.
247
+
248
+ ## CI
249
+
250
+ ```bash
251
+ tokc budget --strict # exit 1 if the listing overflows and skills get dropped
252
+ tokc audit my-skill --strict # exit 1 on any HIGH finding
253
+ tokc diff --strict # exit 1 if the always-on tax grew
254
+ tokc scan --json # machine-readable
255
+ ```
256
+
257
+ ## How the listing budget actually works
258
+
259
+ Worth stating precisely, because it is easy to get wrong in three ways at once:
260
+
261
+ 1. **The budget is a character count, not a token count.** It is derived from the
262
+ context window — `window(tokens) × charsPerToken × fraction`, so
263
+ `200 000 × 4 × 0.01 = 8 000` by default — but what it caps is the *length of
264
+ the assembled listing text*. A model the harness does not recognise converts at
265
+ 3 chars/token instead of 4, and the budget shrinks to 6 000.
266
+ 2. **Nothing is dropped.** An entry that does not fit ships as `- name` with no
267
+ description. The skill stays listed and stays invocable by name; what it loses
268
+ is the text the model selects on.
269
+ 3. **The order is neither arbitrary nor "largest first".** Entries are ranked by
270
+ `usageCount × max(0.5^(days_since_use / 7), 0.1)` — recorded in
271
+ `~/.claude.json` — and the best-ranked keep their descriptions, taken greedily,
272
+ so a small entry can still fit after a large one was refused. Skills bundled
273
+ inside the harness are exempt and consume the budget before any of yours.
274
+
275
+ `tokc` reproduces all three, reads the real usage ranking, and `tokc setup`
276
+ checks the result against a listing your harness genuinely sent.
277
+
278
+ ## Caveats
279
+
280
+ - The **T1 multiplier** assumes 40 requests/session and a 5-minute cache TTL.
281
+ Override with `--requests`, or let `tokc setup` measure it; use `--no-cache` for
282
+ the uncached worst case.
283
+ - **T3 is excluded from projections.** Reference files load unpredictably, and
284
+ counting them would penalise exactly the progressive-disclosure structure this
285
+ tool tells you to adopt. They are reported, not projected.
286
+ - **Skills bundled in the harness are invisible on disk.** Without `tokc setup`
287
+ the budget simulation ignores them and is optimistic by a few thousand
288
+ characters. Setup recovers the figure from a real listing.
289
+ - **Only Claude Code is modelled.** The CLI and the VS Code extension share one
290
+ binary and one set of rules, read from the install. Claude Desktop, claude.ai
291
+ and third-party clients assemble the system prompt elsewhere; `tokc` will not
292
+ pretend to know their policy, and `tokc setup --harness other` asks instead.
293
+ - Offline counts are estimates until you run `tokc calibrate`.
294
+
295
+ ## Tests
296
+
297
+ ```bash
298
+ python -m pytest -q # 37 tests
299
+ ```
tokc-0.1.0/README.md ADDED
@@ -0,0 +1,265 @@
1
+ # tokc — token consumption analyzer for Claude Code skills
2
+
3
+ [![CI](https://github.com/Shult/token_consumer/actions/workflows/ci.yml/badge.svg)](https://github.com/Shult/token_consumer/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/tokc.svg)](https://pypi.org/project/tokc/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/tokc.svg)](https://pypi.org/project/tokc/)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
+
8
+ Measures what a skill actually costs you, tier by tier, and tells you where to cut.
9
+
10
+ ```
11
+ 29 skill(s) tokenizer: o200k_base x1.180 (default)
12
+
13
+ SKILL T1/sess T2/use T3 ALWAYS-ON TAX $/mo
14
+ ------------------------------------------------------------------------------
15
+ project-artifact 241 5,415 8.5k ████████████████████████ ! $2.99
16
+ receipts 159 4,865 20k ████████████████ ! $2.40
17
+ hook-development 140 4,548 16k ██████████████ $2.20
18
+ ...
19
+ ------------------------------------------------------------------------------
20
+ TOTAL 2,787 99,352 294k $45.65
21
+
22
+ Always-on tax
23
+ 2,787 tokens ride in the system prompt of every request, in every session,
24
+ whether or not any skill fires.
25
+ -> 2.9M billed token-equivalents/month at 200 sessions x 40 requests
26
+
27
+ Listing budget (characters, not tokens)
28
+ ████████████████████████████████████████ 10,577 / 8,000 chars (132%)
29
+ ! 2,577 chars over budget -- 6 skill(s) ship as `- name`, description omitted
30
+ demoted, least-used first: plugin-structure, project-artifact, receipts, ...
31
+ ```
32
+
33
+ ## Why this exists
34
+
35
+ Existing tools estimate skill cost by asking Claude — which costs tokens and gives
36
+ different numbers each run — or by running `tiktoken` over `SKILL.md`, which
37
+ **undercounts Claude by 15-20%** and, worse, reports a single number for something
38
+ that is not a single cost.
39
+
40
+ A skill is loaded in three tiers, billed at wildly different frequencies:
41
+
42
+ | Tier | What | Paid |
43
+ |---|---|---|
44
+ | **T1** | frontmatter `name` + `description` (+ `whenToUse`, which the listing appends) | in the system prompt of **every request, every session** |
45
+ | **T2** | the `SKILL.md` body | once per invocation |
46
+ | **T3** | `references/`, `scripts/`, … | only when Claude actually reads the file |
47
+
48
+ The number that matters is almost never the one people optimize. A 250-token
49
+ description is re-sent on every request of every session — with prompt caching that
50
+ is a **×5.15 multiplier per session** (1.25× cache write, then 0.10× per read).
51
+ A 6,000-token body that fires five times a month costs less than a 150-token
52
+ description that ships 200 times. `tokc` computes both and ranks accordingly.
53
+
54
+ ## Install
55
+
56
+ ```bash
57
+ pip install tokc # or: uvx tokc scan
58
+ ```
59
+
60
+ Zero hard dependencies. Three optional extras, none required:
61
+
62
+ ```bash
63
+ pip install "tokc[fast]" # tiktoken — much better offline counts
64
+ pip install "tokc[exact]" # anthropic — enables `--exact` and `tokc calibrate`
65
+ pip install "tokc[yaml]" # pyyaml — frontmatter edge cases
66
+ ```
67
+
68
+ Without them `tokc` falls back to a pure-python estimator and a minimal YAML
69
+ parser. Python 3.10+, Linux / macOS / Windows.
70
+
71
+ From source:
72
+
73
+ ```bash
74
+ git clone https://github.com/Shult/token_consumer && cd token_consumer
75
+ pip install -e ".[dev]" # tiktoken + pyyaml + pytest
76
+ ```
77
+
78
+ ## What leaves your machine
79
+
80
+ Nothing, unless you ask for it. Worth stating plainly, because `tokc` reads
81
+ files that are more personal than the skills themselves:
82
+
83
+ **What it reads locally.** Your skill directories; `settings.json` for
84
+ `skillOverrides` and listing settings; `~/.claude.json` for the per-skill usage
85
+ counts that drive the listing order; your installed Claude Code build, to read
86
+ its own defaults out of the settings schema. `tokc setup` additionally scans
87
+ transcripts under `~/.claude`. From those it keeps four things and nothing else:
88
+ the session count, distinct `requestId`s, the *names* of invoked skills (from
89
+ `Skill` / `SlashCommand` tool-use blocks) and the recorded `skill_listing`
90
+ attachment. Prompts, responses and tool output are never retained, and what is
91
+ collected never leaves the summary figures written to your config file.
92
+
93
+ **What it sends.** Only `--exact` and `tokc calibrate` open a network
94
+ connection. They post skill text — frontmatter and body — to Anthropic's
95
+ `count_tokens` endpoint, using your own credentials, and get a token count back.
96
+ Every other command, and every default, is fully offline. `--no-config` ignores
97
+ saved answers entirely.
98
+
99
+ **What it writes.** `./.tokc.json` or `~/.claude/tokc.json` (`tokc setup`), a
100
+ baseline at `./.tokc-baseline.json` (`tokc snapshot`), and the HTML file you
101
+ name (`tokc report -o`). Nothing else on disk is modified — `tokc` never edits
102
+ your skills, it only tells you what to cut.
103
+
104
+ Both config files record local paths and usage figures, so keep them out of
105
+ version control:
106
+
107
+ ```gitignore
108
+ .tokc.json
109
+ .tokc-baseline.json
110
+ ```
111
+
112
+ ## Commands
113
+
114
+ ```bash
115
+ tokc setup # detect your harness, measure your usage, save both
116
+ tokc scan # every skill, ranked by always-on tax
117
+ tokc audit <name|path> # one skill: tiers, body heatmap, findings
118
+ tokc budget # simulate the system-prompt listing budget
119
+ tokc snapshot # record a baseline
120
+ tokc diff # what changed since the baseline
121
+ tokc watch <path> # live token counter while you edit
122
+ tokc report -o out.html # self-contained HTML report
123
+ tokc calibrate # measure the offline estimator against the real API
124
+ ```
125
+
126
+ With no path, `tokc` scans the same roots Claude Code does: `~/.claude/skills`,
127
+ `<project>/.claude/skills`, and installed plugin skills.
128
+
129
+ ### `tokc setup` — stop guessing
130
+
131
+ The numbers below only mean something if they match *your* harness and *your*
132
+ usage. `tokc setup` works both out and writes them to `./.tokc.json` (or
133
+ `~/.claude/tokc.json` with `--user`), which every other command then reads.
134
+
135
+ ```bash
136
+ tokc setup # detect, measure, confirm
137
+ tokc setup -y # accept everything detected
138
+ tokc setup --harness other # a harness tokc cannot inspect: ask, don't assume
139
+ ```
140
+
141
+ Four things, in descending order of trust:
142
+
143
+ 1. **A listing your harness actually sent.** Transcripts record the
144
+ `skill_listing` attachment verbatim, so we compare our reconstruction line by
145
+ line against the real thing — and recover the characters spent by skills
146
+ bundled *inside* the harness, which never appear on disk but still eat the
147
+ budget first.
148
+ 2. **The installed build's own settings schema.** `skillListingMaxDescChars` and
149
+ `skillListingBudgetFraction` defaults are read out of the install (the VS Code
150
+ extension's schema, or the CLI binary), not hard-coded — so an upgrade that
151
+ changes them changes `tokc` too.
152
+ 3. **Your transcripts.** Sessions, API requests per session (counted by distinct
153
+ `requestId`, not by message) and per-skill invocations over the last 30 days,
154
+ replacing the 200 / 40 / 20 defaults.
155
+ 4. **You.** For a harness that cannot be probed — Claude Desktop, claude.ai, a
156
+ third-party client — nothing is assumed. `tokc` says it does not know and asks
157
+ whether the harness caps the listing at all.
158
+
159
+ Precedence runs weakest to strongest: probed defaults → `~/.claude/tokc.json` →
160
+ `./.tokc.json` → the live `settings.json` chain → `SLASH_COMMAND_TOOL_CHAR_BUDGET`
161
+ → command-line flags. `--no-config` ignores the saved answers entirely.
162
+
163
+ ### Tuning the cost model
164
+
165
+ Every projection is driven by explicit, overridable assumptions:
166
+
167
+ ```bash
168
+ tokc scan --sessions 400 --requests 60 --invocations 10 --model claude-sonnet-5
169
+ tokc scan --no-cache # price without prompt caching (worst case)
170
+ ```
171
+
172
+ ### Accuracy
173
+
174
+ Three counting backends, picked automatically:
175
+
176
+ 1. **`--exact`** — Anthropic's `count_tokens` endpoint. Exact. Needs credentials
177
+ (`ANTHROPIC_API_KEY`, or an `ant auth login` profile).
178
+ 2. **tiktoken** — `o200k_base` × a calibration factor (default 1.18, the midpoint
179
+ of Anthropic's stated 15-20% undercount). Offline.
180
+ 3. **heuristic** — pure python, no dependencies. Roughly ±10%.
181
+
182
+ `tokc calibrate` measures backend 2 against backend 1 **on your own skills** and
183
+ stores the corrected factor, so subsequent offline runs are accurate for your corpus.
184
+
185
+ ## What it flags
186
+
187
+ Findings carry the tier they belong to and a savings estimate at the right rate —
188
+ a T1 win is multiplied by sessions, a T2 win by invocations.
189
+
190
+ **Tier 1 — the every-session tax**
191
+ - `T1-DESC-MISSING` / `T1-DESC-BLOAT` / `T1-DESC-TRUNCATED` — over
192
+ `skillListingMaxDescChars` the harness cuts mid-sentence and appends an
193
+ ellipsis, silently losing any trigger keywords at the end. The cap applies to
194
+ `description` and `whenToUse` **together**, since the listing shows the pair.
195
+ - `T1-HIDDEN` / `T1-NAME-ONLY` — `skillOverrides` in `settings.json` took this
196
+ skill out of the listing, or left it there without its description. Reported so
197
+ a zero is not mistaken for a saving.
198
+ - `T1-NO-TRIGGER` — nothing says *when* to use the skill, so you pay the tax and
199
+ never get the benefit. (Recognises English and French trigger phrasing.)
200
+ - `T1-FILLER` — "this skill is used to", "in order to", …
201
+
202
+ **Tier 2 — the per-invocation cost**
203
+ - `T2-BODY-LARGE`, `T2-SECTION-HOG` — one section dominating the body is the
204
+ extraction candidate.
205
+ - `T2-CODE-BLOCK`, `T2-BIG-TABLE` — reference material paid on every invocation.
206
+ - `T2-REPEAT` — lines repeated 3+ times (code fences excluded).
207
+ - `T2-HTML-COMMENT` — invisible when rendered, fully billed to the model.
208
+ - `T2-NO-STRUCTURE`, `T2-WHITESPACE`.
209
+
210
+ **Tier 3 — on-demand files**
211
+ - `T3-UNREFERENCED` — a bundled file `SKILL.md` never points at is unreachable.
212
+ - `T3-HUGE` — reading it will force compaction mid-task.
213
+
214
+ ## CI
215
+
216
+ ```bash
217
+ tokc budget --strict # exit 1 if the listing overflows and skills get dropped
218
+ tokc audit my-skill --strict # exit 1 on any HIGH finding
219
+ tokc diff --strict # exit 1 if the always-on tax grew
220
+ tokc scan --json # machine-readable
221
+ ```
222
+
223
+ ## How the listing budget actually works
224
+
225
+ Worth stating precisely, because it is easy to get wrong in three ways at once:
226
+
227
+ 1. **The budget is a character count, not a token count.** It is derived from the
228
+ context window — `window(tokens) × charsPerToken × fraction`, so
229
+ `200 000 × 4 × 0.01 = 8 000` by default — but what it caps is the *length of
230
+ the assembled listing text*. A model the harness does not recognise converts at
231
+ 3 chars/token instead of 4, and the budget shrinks to 6 000.
232
+ 2. **Nothing is dropped.** An entry that does not fit ships as `- name` with no
233
+ description. The skill stays listed and stays invocable by name; what it loses
234
+ is the text the model selects on.
235
+ 3. **The order is neither arbitrary nor "largest first".** Entries are ranked by
236
+ `usageCount × max(0.5^(days_since_use / 7), 0.1)` — recorded in
237
+ `~/.claude.json` — and the best-ranked keep their descriptions, taken greedily,
238
+ so a small entry can still fit after a large one was refused. Skills bundled
239
+ inside the harness are exempt and consume the budget before any of yours.
240
+
241
+ `tokc` reproduces all three, reads the real usage ranking, and `tokc setup`
242
+ checks the result against a listing your harness genuinely sent.
243
+
244
+ ## Caveats
245
+
246
+ - The **T1 multiplier** assumes 40 requests/session and a 5-minute cache TTL.
247
+ Override with `--requests`, or let `tokc setup` measure it; use `--no-cache` for
248
+ the uncached worst case.
249
+ - **T3 is excluded from projections.** Reference files load unpredictably, and
250
+ counting them would penalise exactly the progressive-disclosure structure this
251
+ tool tells you to adopt. They are reported, not projected.
252
+ - **Skills bundled in the harness are invisible on disk.** Without `tokc setup`
253
+ the budget simulation ignores them and is optimistic by a few thousand
254
+ characters. Setup recovers the figure from a real listing.
255
+ - **Only Claude Code is modelled.** The CLI and the VS Code extension share one
256
+ binary and one set of rules, read from the install. Claude Desktop, claude.ai
257
+ and third-party clients assemble the system prompt elsewhere; `tokc` will not
258
+ pretend to know their policy, and `tokc setup --harness other` asks instead.
259
+ - Offline counts are estimates until you run `tokc calibrate`.
260
+
261
+ ## Tests
262
+
263
+ ```bash
264
+ python -m pytest -q # 37 tests
265
+ ```
@@ -0,0 +1,49 @@
1
+ [build-system]
2
+ # 77+ for PEP 639 (`license` as an SPDX string, `license-files`).
3
+ requires = ["setuptools>=77"]
4
+ build-backend = "setuptools.build_meta"
5
+
6
+ [project]
7
+ name = "tokc"
8
+ version = "0.1.0"
9
+ description = "Measure and shrink the token cost of Claude Code skills."
10
+ readme = "README.md"
11
+ requires-python = ">=3.10"
12
+ license = "MIT"
13
+ license-files = ["LICENSE"]
14
+ authors = [{ name = "Sylvain Mestre" }]
15
+ keywords = ["claude", "claude-code", "skills", "tokens", "cost", "llm"]
16
+ classifiers = [
17
+ "Environment :: Console",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Software Development :: Quality Assurance",
25
+ ]
26
+ dependencies = []
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/Shult/token_consumer"
30
+ Repository = "https://github.com/Shult/token_consumer"
31
+ Issues = "https://github.com/Shult/token_consumer/issues"
32
+ Changelog = "https://github.com/Shult/token_consumer/blob/main/CHANGELOG.md"
33
+
34
+ [project.optional-dependencies]
35
+ # tiktoken makes offline counts far better than the pure-python fallback.
36
+ fast = ["tiktoken>=0.7"]
37
+ # anthropic enables `--exact` and `tokc calibrate`.
38
+ exact = ["anthropic>=0.40"]
39
+ yaml = ["pyyaml>=6"]
40
+ dev = ["pytest>=8", "tiktoken>=0.7", "pyyaml>=6"]
41
+
42
+ [project.scripts]
43
+ tokc = "tokc.cli:main"
44
+
45
+ [tool.setuptools]
46
+ packages = ["tokc"]
47
+
48
+ [tool.pytest.ini_options]
49
+ testpaths = ["tests"]
tokc-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+