claude-token-saver 3.14.0 → 3.17.0
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.
- package/README.en.md +79 -26
- package/README.md +78 -25
- package/package.json +2 -1
- package/src/commands/install.js +49 -0
- package/src/commands/route-scan.js +4 -2
- package/src/formatters/statusline.js +17 -17
package/README.en.md
CHANGED
|
@@ -1,51 +1,74 @@
|
|
|
1
1
|
[한국어](./README.md) · **English**
|
|
2
2
|
|
|
3
|
-
[](https://www.youtube.com/@DeepPulseKR)
|
|
4
|
-
[](https://www.youtube.com/@DeepPulseEN)
|
|
5
|
-
[](https://rootstudioyaml.github.io/)
|
|
6
3
|
[](https://www.npmjs.com/package/claude-token-saver)
|
|
7
4
|
|
|
8
5
|
# claude-token-saver
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
## 🔀 Routing saved — the reason this tool exists
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+

|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
npm i -g claude-token-saver # postinstall auto-registers the statusline + Skill
|
|
16
|
-
```
|
|
11
|
+
**That figure on the first statusline row is the whole product.** It is money actually saved by moving the easy work your expensive model kept repeating onto cheaper ones — and right beside it is which model that money moved off, and onto what.
|
|
17
12
|
|
|
18
|
-
|
|
13
|
+
It is not an estimate or a marketing number: it comes out of a **ledger**. For every delegated subagent run it records
|
|
19
14
|
|
|
20
|
-
|
|
15
|
+
- **before** — the model that handled this category before the rule existed
|
|
16
|
+
- **after** — the model that actually ran it
|
|
17
|
+
- **the gap** — the same token counts priced against both
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
**After a session ends** it reads your local logs, finds the easy patterns your expensive model
|
|
24
|
-
kept handling, and promotes them into rules so a cheaper model takes them **from the next session
|
|
25
|
-
onward**. Rules are scoped global or per-project.
|
|
19
|
+
so `route-scan savings` traces **every dollar back to the rule that produced it.**
|
|
26
20
|
|
|
27
21
|
```bash
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
$ claude-token-saver route-scan savings
|
|
23
|
+
|
|
24
|
+
🔀 Routing saved, lifetime $2.09 (last 7d $1.40 · 30d $2.09)
|
|
25
|
+
|
|
26
|
+
By model change:
|
|
27
|
+
claude-fable-5 → claude-sonnet-5 — 1 run, $0.72
|
|
28
|
+
claude-opus-5 → claude-haiku-4-5 — 1 run, $0.57
|
|
29
|
+
|
|
30
|
+
By run (newest first):
|
|
31
|
+
2026-08-22 $0.51 claude-fable-5 → claude-haiku-4-5
|
|
32
|
+
rule: T2|paste|-Users-me-projects-my-app
|
|
31
33
|
```
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
**Counting honestly is the design principle.** Delegations no registered rule covers — `Explore`, your own agents, a plugin's subagents — were not routed by this tool, so they are **excluded**. When the pricing table cannot recognize a model id, the run is **dropped** rather than priced wrong. The number may be small, but it is real.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm i -g claude-token-saver # postinstall auto-registers the statusline + Skill
|
|
39
|
+
```
|
|
35
40
|
|
|
41
|
+
---
|
|
36
42
|
|
|
37
43
|
## ⚡ Why — the 30-second pitch
|
|
38
44
|
|
|
39
45
|
| | |
|
|
40
46
|
|---|---|
|
|
41
|
-
| 🔀 **
|
|
47
|
+
| 🔀 **Measured routing savings** | Every delegated run's saving is recorded in a ledger → lifetime total plus the model-change breakdown on statusline row 1 (audit it all with `route-scan savings`) |
|
|
48
|
+
| 🎯 **Model-fitting delegation** | Classifies the easy work your expensive model (opus/fable) keeps repeating into tiers (T0/T1/T2) → promotes haiku/sonnet delegation rules, auto-applied from the next session |
|
|
42
49
|
| 💸 **−18.6% measured cost** | Cost per user message $2.35 → $1.91 after adopting harness+ratchet (author's logs, [details](#real-world-impact--beforeafter-report)) |
|
|
43
50
|
| 🚨 **No surprise rate limits** | Instant warning when the 5H/7D window hits 90% + `handoff` to back up your work |
|
|
44
51
|
| 🧠 **Cache waste detection** | Hit rate, TTL countdown, 1M-context detection — token spikes diagnosed with issue codes |
|
|
45
52
|
| 🅷 **Stop repeating mistakes** | Recurring errors get promoted to ratchet rules — auto-applied from the next session |
|
|
46
|
-
| 💰 **Savings made visible** | See what prompt caching saved you, live (`💰 Cache saved $2.1K`) |
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
## Not a router — 60 seconds
|
|
55
|
+
|
|
56
|
+
It never intercepts a request in realtime.
|
|
57
|
+
**After a session ends** it reads your local logs, finds the easy patterns your expensive model
|
|
58
|
+
kept handling, and promotes them into rules so a cheaper model takes them **from the next session
|
|
59
|
+
onward**. Rules are scoped global or per-project.
|
|
60
|
+
|
|
61
|
+
Never switching models mid-session is the point. Prompt caches are per-model, so a mid-session switch throws away everything accumulated. This tool only ever delegates to **subagents**, leaving the main session's cache intact.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm i -g claude-token-saver@latest
|
|
65
|
+
claude-token-saver route-scan # find delegation candidates in your own history (0 LLM calls)
|
|
66
|
+
claude-token-saver route-scan rules # list promoted rules · rm <N> to remove
|
|
67
|
+
claude-token-saver route-scan savings # audit every dollar the routing saved
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Thresholds come from **your own last-14-day distribution (p25/p75)**, not someone else's benchmark.
|
|
71
|
+
Measured rule-health — whether a delegated run actually succeeded — landed in [v3.9.0](#v390-2026-08-01).
|
|
49
72
|
|
|
50
73
|
---
|
|
51
74
|
|
|
@@ -60,24 +83,31 @@ npm i -g claude-token-saver
|
|
|
60
83
|
|
|
61
84
|
The statusline appears at the bottom of Claude Code right away. If auto-registration was skipped (`--ignore-scripts`, sudo, sandboxed installs), run `claude-token-saver install`.
|
|
62
85
|
|
|
86
|
+
One install sets up everything: **statusline, Skill, SessionStart hook, the 🅷 Harness (5 principles), and a first route-scan.** The harness is **appended** to `~/.claude/CLAUDE.md` as a marked block (your existing content is backed up and preserved) and is left alone if one is already there. Skip it with `CTS_NO_HARNESS=1 npm i -g claude-token-saver`; undo it with `claude-token-saver harness uninit --global`.
|
|
87
|
+
|
|
63
88
|
> ⚠️ Avoid `sudo` global installs — the Skill lands in root's `~/.claude` instead of yours. Use nvm/fnm/Volta or `npm config set prefix ~/.npm-global`.
|
|
64
89
|
|
|
65
90
|
## Reading the statusline
|
|
66
91
|
|
|
92
|
+
Once the savings ledger has entries it renders as **two rows** — routing savings on row 1, diagnostics on row 2.
|
|
93
|
+
|
|
67
94
|
```
|
|
68
|
-
|
|
95
|
+
🔀 Routing saved $2.09 | fable→sonnet 1× $0.72 · opus→haiku 1× $0.57
|
|
96
|
+
⚠ Ctx 200k+ · 🅷 5/5 · 🤖 Opus 5 · 🧠 Cache hit 98.8% · ⏳ Cache expires 59:46 · ✦ current ███▓░░ 62% 🔄 21:33 · 📅 weekly ██▒░░░ 38% 🔄 Tue 19:33 · 📦 Ctx 47% of 1M · 💰 Cache saved $1.0K · last 1d
|
|
69
97
|
```
|
|
70
98
|
|
|
99
|
+
With an empty ledger (no measured delegation yet) row 1 is not drawn and the layout stays single-line. If your build renders only the first row (some macOS Claude Code versions), pass `--single-line`.
|
|
100
|
+
|
|
71
101
|
| Segment | Meaning |
|
|
72
102
|
|---|---|
|
|
103
|
+
| `🔀` **row 1** | **Lifetime routing savings + the model changes behind them.** The total is green, the breakdown gray. The breakdown sums exactly to the total (all pairs, never truncated) and drops version digits, which churn (`claude-opus-4-5-…` → `opus`). Full audit: `route-scan savings` |
|
|
73
104
|
| `🤖` | Active model |
|
|
74
105
|
| `🅷 5/5` | Harness principle score ([Harness mode](#-harness-mode)) |
|
|
75
106
|
| `🧠` | Cache hit rate (green at 85%+) |
|
|
76
107
|
| `⏳` | Cache TTL countdown — send a message before expiry to keep the cache warm |
|
|
77
108
|
| `✦ current` / `📅 weekly` | 5-hour / 7-day rate-limit window usage + reset time |
|
|
78
109
|
| `📦` | Context usage (e.g. `Ctx 68% of 1M`) — colored by fill. Current models default to 1M with no premium, but token volume itself drives per-turn cost and 5H/7D burn |
|
|
79
|
-
| `💰` | Cumulative savings from prompt caching |
|
|
80
|
-
| `🔀` | **Cumulative savings from model routing** — what work handled by a cheaper model instead of this one saved. A different number from prompt-cache savings (`💰`). Hidden until a delegation has actually been measured |
|
|
110
|
+
| `💰` | Cumulative savings from prompt caching — a **different** number from row 1's `🔀` (model routing) |
|
|
81
111
|
|
|
82
112
|
When something is wrong, a **warning chip leads the line**:
|
|
83
113
|
|
|
@@ -104,6 +134,7 @@ Run these in your shell (inside Claude Code, the `/claude-token-saver` Skill is
|
|
|
104
134
|
| `claude-token-saver mode [keywords...]` | Output config (`icon`/`text`, `en`/`ko`, `1h`–`30d` window, …) |
|
|
105
135
|
| `claude-token-saver harness ...` | 🅷 Harness management (below) |
|
|
106
136
|
| `claude-token-saver route-scan` | Detect recurring easy work on expensive models → propose haiku-delegation ratchet rules (below) |
|
|
137
|
+
| `claude-token-saver route-scan savings` | The routing-savings ledger — per-model-change rollup + per-run log (the evidence behind the figure) |
|
|
107
138
|
| `claude-token-saver compact-window` | Warn when a 1M-context session has no auto-compact cap → pin 400k with `set` (below) |
|
|
108
139
|
| `claude-token-saver install` | Manually register Skill + statusline |
|
|
109
140
|
|
|
@@ -301,11 +332,23 @@ npm uninstall -g claude-cache-monitor && npm i -g claude-token-saver
|
|
|
301
332
|
```
|
|
302
333
|
Also update `statusLine.command` in `~/.claude/settings.json` to `claude-token-saver …`.
|
|
303
334
|
|
|
304
|
-
**Background:** [GitHub Issue #46829](https://github.com/anthropics/claude-code/issues/46829) (cache TTL regression) · [HN discussion](https://news.ycombinator.com/item?id=47736476)
|
|
335
|
+
**Background:** [GitHub Issue #46829](https://github.com/anthropics/claude-code/issues/46829) (cache TTL regression) · [HN discussion](https://news.ycombinator.com/item?id=47736476)
|
|
305
336
|
</details>
|
|
306
337
|
|
|
307
338
|
## Release notes
|
|
308
339
|
|
|
340
|
+
### v3.17.0 (2026-08-22)
|
|
341
|
+
- **One install now sets up the 🅷 Harness too** — until now `harness init` was a separate step, without which the 🅷 score and ratchet-rule delivery did nothing. The install **appends** the 5-principle block to `~/.claude/CLAUDE.md` (existing content backed up and preserved; an existing block is left alone). Skip with `CTS_NO_HARNESS=1`, undo with `harness uninit --global`.
|
|
342
|
+
- **The README leads with the real statusline screenshot** — the capture replaces the code block at the top, and the duplicate image further down was removed.
|
|
343
|
+
|
|
344
|
+
### v3.16.0 (2026-08-22)
|
|
345
|
+
- **README restructured around routing savings** — `🔀 Routing saved` now opens the page, with how the figure is derived (before / after / gap) and the real `route-scan savings` output alongside it. Channel and homepage badges moved to a "Who makes this" section at the bottom.
|
|
346
|
+
- **Statusline screenshot refreshed to the current two-row layout** — captured from real output rather than mocked up. Regenerate with `npm run docs:statusline` (headless Chrome; no dependencies added).
|
|
347
|
+
|
|
348
|
+
### v3.15.0 (2026-08-22)
|
|
349
|
+
- **The statusline headline is one lifetime figure** — `🔀 Routing saved $2.09 | fable→sonnet 1× $0.72 · opus→haiku 1× $0.57 …`. The weekly and monthly sums are gone: the per-model breakdown that follows is a lifetime split, and next to a row of rolling windows it read as a breakdown of whichever one it touched. One timeframe for the whole line leaves nothing to mismatch. The rolling windows are still in `route-scan savings`.
|
|
350
|
+
- **The per-model breakdown is gray** — green is reserved for the lifetime total. Repeating that green on every component flattened the line into one loud block with nothing to land on first.
|
|
351
|
+
|
|
309
352
|
### v3.14.0 (2026-08-22)
|
|
310
353
|
- **The statusline headline names the model changes behind the total** — `🔀 Routing saved weekly $1.4 · monthly $2.1 · total $2.1 | fable→sonnet 1× $0.72 · opus→haiku 1× $0.57 …`. Versions are dropped (`claude-opus-4-5-20251101-v1:0` → `opus`) since they bump constantly and add nothing here. **Every** pair is listed rather than a top-N: the amounts sit next to a total, so a truncated list misstates what that total is made of. Families collapse the list on their own, so it stays short without being cut.
|
|
311
354
|
- **New `route-scan savings`** — the evidence behind the headline: a per-model-change rollup (from, to, runs, dollars) and the per-run log (date, amount, model change, the rule that caused it).
|
|
@@ -503,3 +546,13 @@ Older versions: see `git log`.
|
|
|
503
546
|
## License
|
|
504
547
|
|
|
505
548
|
MIT
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## Who makes this
|
|
553
|
+
|
|
554
|
+
[](https://www.youtube.com/@DeepPulseKR)
|
|
555
|
+
[](https://www.youtube.com/@DeepPulseEN)
|
|
556
|
+
[](https://rootstudioyaml.github.io/)
|
|
557
|
+
|
|
558
|
+
Built and used at **DeepPulse**, a channel about AI developer tooling. The [launch Short (60s)](https://www.youtube.com/shorts/RaD8qMsPTnA) covers where this came from and how it is used.
|
package/README.md
CHANGED
|
@@ -1,50 +1,73 @@
|
|
|
1
1
|
**한국어** · [English](./README.en.md)
|
|
2
2
|
|
|
3
|
-
[](https://www.youtube.com/@DeepPulseKR)
|
|
4
|
-
[](https://www.youtube.com/@DeepPulseEN)
|
|
5
|
-
[](https://rootstudioyaml.github.io/)
|
|
6
3
|
[](https://www.npmjs.com/package/claude-token-saver)
|
|
7
4
|
|
|
8
5
|
# claude-token-saver
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
## 🔀 Routing saved — 이 도구가 존재하는 이유
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+

|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
npm i -g claude-token-saver # postinstall이 statusline + Skill 자동 등록
|
|
16
|
-
```
|
|
11
|
+
**statusline 첫 줄에 뜨는 이 금액이 전부입니다.** 비싼 모델이 반복 처리해 온 쉬운 작업을 더 싼 모델로 내려보내서 **실제로 아낀 돈**이고, 옆에는 그 돈이 어느 모델에서 어느 모델로 옮겨서 생겼는지가 그대로 붙습니다.
|
|
17
12
|
|
|
18
|
-
|
|
13
|
+
이 숫자는 추정치나 홍보 문구가 아니라 **원장(ledger)에서 나옵니다.** 위임된 서브에이전트 실행 하나하나에 대해
|
|
19
14
|
|
|
20
|
-
|
|
15
|
+
- **기준(before)** — 룰 승격 전 그 유형을 실제로 처리하던 모델
|
|
16
|
+
- **결과(after)** — 실제로 그 일을 처리한 모델
|
|
17
|
+
- **차액** — 같은 토큰량에 두 모델의 가격표를 각각 적용한 값
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
**세션이 끝난 뒤** 로컬 기록을 읽어서, 비싼 모델이 반복해서 처리해 온 쉬운 유형을 뽑고,
|
|
24
|
-
그 유형은 **다음 세션부터** 싼 모델이 맡도록 룰로 겁니다. 룰은 글로벌·프로젝트로 범위가 나뉩니다.
|
|
19
|
+
을 기록합니다. 그래서 `route-scan savings` 한 줄이면 **모든 금액을 룰 단위까지 되짚을 수 있습니다.**
|
|
25
20
|
|
|
26
21
|
```bash
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
$ claude-token-saver route-scan savings
|
|
23
|
+
|
|
24
|
+
🔀 라우팅 절감 누적 $2.09 (최근 7일 $1.40 · 30일 $2.09)
|
|
25
|
+
|
|
26
|
+
모델 이동별:
|
|
27
|
+
claude-fable-5 → claude-sonnet-5 — 1회, $0.72
|
|
28
|
+
claude-opus-5 → claude-haiku-4-5 — 1회, $0.57
|
|
29
|
+
|
|
30
|
+
실행별 (최근순):
|
|
31
|
+
2026-08-22 $0.51 claude-fable-5 → claude-haiku-4-5
|
|
32
|
+
룰: T2|paste|-Users-me-projects-my-app
|
|
30
33
|
```
|
|
31
34
|
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
**정직하게 세는 것이 설계 원칙입니다.** 등록된 룰이 커버하지 않는 위임(`Explore`, 직접 만든 에이전트, 플러그인 에이전트)은 이 도구가 라우팅한 것이 아니므로 **금액에서 제외**합니다. 모델명을 가격표가 알아보지 못하면 틀린 금액을 내놓는 대신 그 실행을 **빼버립니다**. 작게 나오더라도 실제 숫자입니다.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm i -g claude-token-saver # postinstall이 statusline + Skill 자동 등록
|
|
39
|
+
```
|
|
34
40
|
|
|
41
|
+
---
|
|
35
42
|
|
|
36
43
|
## ⚡ 왜 쓰나 — 30초 요약
|
|
37
44
|
|
|
38
45
|
| | |
|
|
39
46
|
|---|---|
|
|
40
|
-
| 🔀
|
|
47
|
+
| 🔀 **라우팅 절감 실측** | 위임으로 아낀 금액을 원장에 실행 단위로 기록 → statusline 1줄째에 누적 + 모델 이동 내역 (`route-scan savings`로 전수 추적) |
|
|
48
|
+
| 🎯 **모델 피팅 위임** | 상위 모델(opus/fable)이 반복 처리해 온 easy 작업을 티어(T0/T1/T2)로 분류 → haiku/sonnet 위임 룰로 승격, 다음 세션부터 자동 적용 |
|
|
41
49
|
| 💸 **비용 실측 −18.6%** | harness+ratchet 도입 전후, 사용자 메시지당 비용 $2.35 → $1.91 (저자 로그, [상세](#실제-효과--도입-전후-리포트)) |
|
|
42
50
|
| 🚨 **한도 초과 예방** | 5H/7D rate-limit 윈도 90% 도달 시 즉시 경고 + `handoff`로 작업 백업 |
|
|
43
51
|
| 🧠 **캐시 낭비 감지** | 히트율·TTL 카운트다운·1M 컨텍스트 자동 감지 — 토큰 급증 원인을 코드로 진단 |
|
|
44
52
|
| 🅷 **같은 실수 차단** | 반복 에러를 감지해 ratchet 룰로 승격 — 다음 세션부터 자동 적용 |
|
|
45
|
-
| 💰 **절감액 가시화** | 프롬프트 캐시가 아껴준 금액을 실시간 표시 (`💰 Cache saved $2.1K`) |
|
|
46
53
|
|
|
47
|
-
|
|
54
|
+
## 라우터가 아닙니다 — 60초
|
|
55
|
+
|
|
56
|
+
요청을 실시간으로 가로채지 않습니다.
|
|
57
|
+
**세션이 끝난 뒤** 로컬 기록을 읽어서, 비싼 모델이 반복해서 처리해 온 쉬운 유형을 뽑고,
|
|
58
|
+
그 유형은 **다음 세션부터** 싼 모델이 맡도록 룰로 겁니다. 룰은 글로벌·프로젝트로 범위가 나뉩니다.
|
|
59
|
+
|
|
60
|
+
세션 중간에 모델을 바꾸지 않는 것이 핵심입니다. 프롬프트 캐시는 모델별이라 중간 전환은 누적 캐시를 통째로 날립니다. 이 도구는 **서브에이전트 위임**만 쓰므로 메인 세션의 캐시가 깨지지 않습니다.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm i -g claude-token-saver@latest
|
|
64
|
+
claude-token-saver route-scan # 내 지난 세션에서 위임 후보 뽑기 (LLM 호출 0)
|
|
65
|
+
claude-token-saver route-scan rules # 승격된 룰 확인 · rm <N> 으로 삭제
|
|
66
|
+
claude-token-saver route-scan savings # 위임으로 아낀 금액의 근거 전수 확인
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
기준선은 남의 벤치마크가 아니라 **내 최근 14일 분포(p25/p75)** 로 잡습니다.
|
|
70
|
+
넘긴 뒤 실제로 잘 됐는지까지 재는 실측 rule-health는 [v3.9.0](#v390-2026-08-01)에 들어갔습니다.
|
|
48
71
|
|
|
49
72
|
---
|
|
50
73
|
|
|
@@ -59,24 +82,31 @@ npm i -g claude-token-saver
|
|
|
59
82
|
|
|
60
83
|
설치 즉시 Claude Code 하단에 statusline이 나타납니다. `--ignore-scripts`/sudo 등으로 자동 등록이 안 됐다면 `claude-token-saver install`로 수동 등록하세요.
|
|
61
84
|
|
|
85
|
+
설치 한 번으로 **statusline · Skill · SessionStart 훅 · 🅷 Harness(5원칙) · 최초 route-scan** 이 모두 준비됩니다. Harness는 `~/.claude/CLAUDE.md`에 표시된 블록으로 **추가**되며(기존 내용은 백업 후 보존), 이미 설정돼 있으면 건드리지 않습니다. 원치 않으면 `CTS_NO_HARNESS=1 npm i -g claude-token-saver`로 건너뛰고, 되돌리려면 `claude-token-saver harness uninit --global`을 실행하세요.
|
|
86
|
+
|
|
62
87
|
> ⚠️ sudo 글로벌 설치는 Skill이 root의 `~/.claude`에 등록되는 함정이 있습니다 — nvm/fnm/Volta로 사용자 영역 설치를 권장합니다.
|
|
63
88
|
|
|
64
89
|
## statusline 읽는 법
|
|
65
90
|
|
|
91
|
+
절감 원장에 기록이 쌓이면 **두 줄**로 나옵니다. 1줄째는 라우팅 절감만, 2줄째는 진단 칩입니다.
|
|
92
|
+
|
|
66
93
|
```
|
|
67
|
-
|
|
94
|
+
🔀 Routing saved $2.09 | fable→sonnet 1× $0.72 · opus→haiku 1× $0.57
|
|
95
|
+
⚠ Ctx 200k+ · 🅷 5/5 · 🤖 Opus 5 · 🧠 Cache hit 98.8% · ⏳ Cache expires 59:46 · ✦ current ███▓░░ 62% 🔄 21:33 · 📅 weekly ██▒░░░ 38% 🔄 Tue 19:33 · 📦 Ctx 47% of 1M · 💰 Cache saved $1.0K · last 1d
|
|
68
96
|
```
|
|
69
97
|
|
|
98
|
+
원장이 비어 있으면(아직 위임 실측이 없으면) 1줄째는 그리지 않고 종전처럼 한 줄로 나옵니다. 일부 환경(macOS 구버전 Claude Code)에서 첫 줄만 렌더된다면 `--single-line`으로 한 줄 레이아웃을 유지하세요.
|
|
99
|
+
|
|
70
100
|
| 세그먼트 | 의미 |
|
|
71
101
|
|---|---|
|
|
102
|
+
| `🔀` **1줄째** | **라우팅으로 아낀 누적 금액 + 모델 이동 내역.** 금액이 녹색, 내역은 회색입니다. 내역의 합은 누적과 정확히 일치하며(전부 표시, 잘라내지 않음), 버전 숫자는 계속 바뀌므로 계열명만 남깁니다(`claude-opus-4-5-…` → `opus`). 근거 전수는 `route-scan savings` |
|
|
72
103
|
| `🤖` | 현재 모델 |
|
|
73
104
|
| `🅷 5/5` | harness 원칙 점수 ([Harness 모드](#-harness-모드)) |
|
|
74
105
|
| `🧠` | 캐시 히트율 (85%+ 녹색) |
|
|
75
106
|
| `⏳` | 캐시 TTL 카운트다운 — 만료 전에 메시지를 보내면 캐시 유지 |
|
|
76
107
|
| `✦ current` / `📅 weekly` | 5시간 / 7일 rate-limit 윈도 사용률 + 리셋 시각 |
|
|
77
108
|
| `📦` | 컨텍스트 사용률 (예: `Ctx 68% of 1M`) — 사용률 기준 녹/황/적. 현재 모델은 1M이 기본·프리미엄 없음이지만, 토큰량 자체가 턴당 비용과 5H/7D 한도를 태웁니다 |
|
|
78
|
-
| `💰` | 캐시가 절약해준 누적 금액 |
|
|
79
|
-
| `🔀` | **모델 위임으로 아낀 누적 비용** — 같은 일을 더 싼 모델이 대신 처리해서 아낀 금액이며, 프롬프트 캐시 절감(`💰`)과는 다른 수치입니다. 실측 위임이 없으면 표시되지 않습니다 |
|
|
109
|
+
| `💰` | 프롬프트 캐시가 절약해준 누적 금액 — 1줄째 `🔀`(모델 라우팅 절감)와는 **다른 수치**입니다 |
|
|
80
110
|
|
|
81
111
|
문제가 감지되면 **경고 칩이 맨 앞에** 붙습니다:
|
|
82
112
|
|
|
@@ -103,6 +133,7 @@ Claude 안에서 `/claude-token-saver` Skill을 실행하거나 칩 문구를
|
|
|
103
133
|
| `claude-token-saver mode [keywords...]` | 출력 설정 (`icon`/`text`, `ko`/`en`, `1h`~`30d` 윈도 등) |
|
|
104
134
|
| `claude-token-saver harness ...` | 🅷 Harness 관리 (아래 참고) |
|
|
105
135
|
| `claude-token-saver route-scan` | 상위 모델이 반복 처리한 easy 작업 감지 → haiku 위임 랫쳇 룰 제안 (아래 참고) |
|
|
136
|
+
| `claude-token-saver route-scan savings` | 라우팅 절감 원장 — 모델 이동별 합계 + 실행별 내역 (금액의 근거) |
|
|
106
137
|
| `claude-token-saver compact-window` | 1M 컨텍스트인데 자동 압축 창이 안 잡혀 있으면 경고 → `set`으로 40만 고정 (아래 참고) |
|
|
107
138
|
| `claude-token-saver install` | Skill·statusline 수동 등록 |
|
|
108
139
|
|
|
@@ -185,7 +216,7 @@ claude-token-saver route-scan savings # 절감 원장 — 어느 룰
|
|
|
185
216
|
`route-scan savings`는 statusline의 `🔀 Routing saved` 한 줄 뒤에 있는 근거를 그대로 보여줍니다. 모델 이동별 합계와 실행별 내역이 함께 나오므로, 금액이 어디서 나왔는지 추적할 수 있습니다.
|
|
186
217
|
|
|
187
218
|
```
|
|
188
|
-
🔀 라우팅 절감
|
|
219
|
+
🔀 라우팅 절감 누적 $2.09 (최근 7일 $1.40 · 30일 $2.09)
|
|
189
220
|
|
|
190
221
|
모델 이동별:
|
|
191
222
|
claude-fable-5 → claude-sonnet-5 — 1회, $0.72
|
|
@@ -272,6 +303,18 @@ npm uninstall -g claude-cache-monitor && npm i -g claude-token-saver
|
|
|
272
303
|
|
|
273
304
|
## 릴리스 노트
|
|
274
305
|
|
|
306
|
+
### v3.17.0 (2026-08-22)
|
|
307
|
+
- **설치 한 번으로 🅷 Harness까지 적용됩니다** — 지금까지는 설치 후 `harness init`을 따로 실행해야 statusline의 🅷 점수와 ratchet 룰 전달이 동작했습니다. 이제 설치가 `~/.claude/CLAUDE.md`에 5원칙 블록을 **추가**합니다(기존 내용은 백업 후 보존, 이미 있으면 건드리지 않음). 건너뛰려면 `CTS_NO_HARNESS=1`, 되돌리려면 `harness uninit --global`.
|
|
308
|
+
- **README 상단을 statusline 실제 스크린샷으로 교체** — 코드 블록 대신 실제 캡처를 최상단에 두고, 아래쪽에 중복으로 있던 이미지는 뺐습니다.
|
|
309
|
+
|
|
310
|
+
### v3.16.0 (2026-08-22)
|
|
311
|
+
- **README를 라우팅 절감 중심으로 재구성** — 이 도구의 핵심이 무엇인지 첫 화면에서 바로 보이도록 `🔀 Routing saved`를 최상단에 올리고, 금액이 원장에서 어떻게 나오는지(before/after/차액)와 `route-scan savings` 실제 출력을 함께 실었습니다. 채널·홈페이지 배지는 최하단 "만든 곳"으로 내렸습니다.
|
|
312
|
+
- **statusline 스크린샷을 현재 2줄 레이아웃으로 갱신** — 목업이 아니라 실제 출력을 캡처합니다. `npm run docs:statusline`으로 재생성할 수 있습니다(headless Chrome 사용, 의존성 추가 없음).
|
|
313
|
+
|
|
314
|
+
### v3.15.0 (2026-08-22)
|
|
315
|
+
- **statusline 헤드라인을 누적 한 줄로 줄였습니다** — `🔀 Routing saved $2.09 | fable→sonnet 1× $0.72 · opus→haiku 1× $0.57 …`. 주간·월간 합계는 뺐습니다. 뒤에 붙는 모델 이동 내역이 누적 기준 분해인데 롤링 창 세 개와 나란히 있으면 어느 것의 내역인지 읽히지 않았습니다. 한 줄 전체가 한 시점 기준이 되면 어긋날 여지가 없습니다. 주간·월간은 `route-scan savings`에서 계속 확인할 수 있습니다.
|
|
316
|
+
- **모델별 절감 내역은 회색으로** — 녹색은 누적 금액 하나에만 남깁니다. 구성 요소마다 같은 녹색을 반복하면 줄 전체가 한 덩어리로 시끄러워져 먼저 눈이 닿을 곳이 사라집니다.
|
|
317
|
+
|
|
275
318
|
### v3.14.0 (2026-08-22)
|
|
276
319
|
- **statusline 헤드라인이 모델 이동을 함께 보여줍니다** — `🔀 Routing saved weekly $1.4 · monthly $2.1 · total $2.1 | fable→sonnet 1× $0.72 · opus→haiku 1× $0.57 …`. 버전 숫자는 계속 올라가고 statusline에서는 잡음이라 계열명만 남깁니다(`claude-opus-4-5-20251101-v1:0` → `opus`). 이동 목록은 **자르지 않고 전부** 표시합니다 — 금액이 `total` 옆에 붙어 있어서 일부만 보이면 합계를 잘못 말하게 됩니다. 계열 단위로 접히면 조합 수가 원래 많지 않아 줄은 짧게 유지됩니다.
|
|
277
320
|
- **`route-scan savings` 추가** — 헤드라인 뒤에 있는 근거를 그대로 조회합니다. 모델 이동별 합계(어느 모델에서 어느 모델로 몇 회, 얼마)와 실행별 내역(날짜·금액·모델 이동·해당 룰)이 함께 나옵니다.
|
|
@@ -469,3 +512,13 @@ manifest.build의 "다들 LLM 라우터 만드는데 우리는 폐기했다"(7
|
|
|
469
512
|
## 라이선스
|
|
470
513
|
|
|
471
514
|
MIT
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
## 만든 곳
|
|
519
|
+
|
|
520
|
+
[](https://www.youtube.com/@DeepPulseKR)
|
|
521
|
+
[](https://www.youtube.com/@DeepPulseEN)
|
|
522
|
+
[](https://rootstudioyaml.github.io/)
|
|
523
|
+
|
|
524
|
+
AI 개발 도구를 다루는 채널 **DeepPulse**에서 만들고 씁니다. 이 도구의 배경과 사용법은 [출시 영상(60초)](https://www.youtube.com/shorts/RaD8qMsPTnA)에서 볼 수 있습니다.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-token-saver",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.17.0",
|
|
4
4
|
"description": "Route the easy work your expensive Claude model keeps repeating down to haiku/sonnet — post-hoc session analysis, no realtime router, no extra LLM calls.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"test": "node --test",
|
|
11
|
+
"docs:statusline": "node scripts/docs-statusline.mjs",
|
|
11
12
|
"postinstall": "node bin/cli.js install || true"
|
|
12
13
|
},
|
|
13
14
|
"files": [
|
package/src/commands/install.js
CHANGED
|
@@ -59,6 +59,55 @@ export async function run({ hasFlag }) {
|
|
|
59
59
|
} catch (e) { debug('install:route-scan-seed', e); /* hook-triggered scan covers it on the first session instead */ }
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
+
// Harness, set up as part of the install rather than left as a manual
|
|
63
|
+
// follow-up step. The 🅷 statusline segment and the ratchet rules that
|
|
64
|
+
// route-scan promotes both depend on the block existing in CLAUDE.md, so
|
|
65
|
+
// an install without it ships a tool that is half wired up.
|
|
66
|
+
//
|
|
67
|
+
// Scope is global (~/.claude/CLAUDE.md): a global install is not tied to
|
|
68
|
+
// any one project, and the harness principles are project-independent.
|
|
69
|
+
// Only ever ADDS — harnessInit appends its own marked block, backs up the
|
|
70
|
+
// previous file, and leaves surrounding content untouched. Skipped when a
|
|
71
|
+
// block is already there (nothing to do) and when CTS_NO_HARNESS=1 is set,
|
|
72
|
+
// for anyone who wants the statusline without the CLAUDE.md rules.
|
|
73
|
+
try {
|
|
74
|
+
const { harnessInit, harnessStatus } = await import('../harness.js');
|
|
75
|
+
const before = harnessStatus(undefined, { scope: 'global' });
|
|
76
|
+
if (process.env.CTS_NO_HARNESS === '1') {
|
|
77
|
+
console.log('');
|
|
78
|
+
console.log(lang === 'ko'
|
|
79
|
+
? ' harness: CTS_NO_HARNESS=1 이므로 건너뜁니다 (나중에 `harness init --global`).'
|
|
80
|
+
: ' harness: skipped (CTS_NO_HARNESS=1) — run `harness init --global` later.');
|
|
81
|
+
} else if (before.hasBlock) {
|
|
82
|
+
console.log('');
|
|
83
|
+
console.log(lang === 'ko'
|
|
84
|
+
? ` harness: 이미 설정됨 — 🅷 ${before.configured}/${before.total} (${before.file})`
|
|
85
|
+
: ` harness: already set up — 🅷 ${before.configured}/${before.total} (${before.file})`);
|
|
86
|
+
} else {
|
|
87
|
+
const h = harnessInit({ scope: 'global' });
|
|
88
|
+
console.log('');
|
|
89
|
+
for (const p of h.backedUp) {
|
|
90
|
+
console.log(lang === 'ko' ? ` harness: 백업 ${p}` : ` harness: backed up ${p}`);
|
|
91
|
+
}
|
|
92
|
+
for (const p of h.wrote) {
|
|
93
|
+
console.log(lang === 'ko' ? ` harness: 작성 ${p}` : ` harness: wrote ${p}`);
|
|
94
|
+
}
|
|
95
|
+
console.log(lang === 'ko'
|
|
96
|
+
? ' harness: 5원칙을 ~/.claude/CLAUDE.md 에 설정했습니다 — statusline에 🅷 5/5 가 표시됩니다.'
|
|
97
|
+
: ' harness: 5 principles installed in ~/.claude/CLAUDE.md — the statusline now shows 🅷 5/5.');
|
|
98
|
+
console.log(lang === 'ko'
|
|
99
|
+
? ' 되돌리려면: claude-token-saver harness uninit --global'
|
|
100
|
+
: ' to undo: claude-token-saver harness uninit --global');
|
|
101
|
+
}
|
|
102
|
+
} catch (e) {
|
|
103
|
+
// Never fail an install over this — the statusline and Skill are already
|
|
104
|
+
// in place, and `harness init` remains available as a manual step.
|
|
105
|
+
debug('install:harness-init', e);
|
|
106
|
+
console.log(lang === 'ko'
|
|
107
|
+
? ' harness: 자동 설정을 건너뛰었습니다 — `claude-token-saver harness init --global` 로 직접 설정하세요.'
|
|
108
|
+
: ' harness: auto-setup skipped — run `claude-token-saver harness init --global` yourself.');
|
|
109
|
+
}
|
|
110
|
+
|
|
62
111
|
console.log('');
|
|
63
112
|
console.log('Open Claude Code in any directory and just mention:');
|
|
64
113
|
console.log(' "cache hit rate" / "1M context" / "5H cap" — the skill auto-activates.');
|
|
@@ -27,9 +27,11 @@ export async function run({ args, hasFlag, numArg }) {
|
|
|
27
27
|
}
|
|
28
28
|
const t = delegationSavedTotals();
|
|
29
29
|
const money = (v) => `$${v.toFixed(2)}`;
|
|
30
|
+
// Lifetime leads (it is what the breakdown below adds up to); the
|
|
31
|
+
// rolling windows follow as context rather than as competing headlines.
|
|
30
32
|
console.log(lang === 'ko'
|
|
31
|
-
? `🔀 라우팅 절감
|
|
32
|
-
: `🔀 Routing saved
|
|
33
|
+
? `🔀 라우팅 절감 누적 ${money(t.total)} (최근 7일 ${money(t.week)} · 30일 ${money(t.month)})`
|
|
34
|
+
: `🔀 Routing saved, lifetime ${money(t.total)} (last 7d ${money(t.week)} · 30d ${money(t.month)})`);
|
|
33
35
|
|
|
34
36
|
// Per model-pair rollup first: the "what moved where" question is what
|
|
35
37
|
// this view exists to answer, and it is easier to read than the log.
|
|
@@ -274,22 +274,20 @@ export function formatReport(data, { color = true, verbose = false, timer = true
|
|
|
274
274
|
? `${c(GREEN)}${delegateLabel}${c(RESET)} ${formatMoney(delegationSaved)}`
|
|
275
275
|
: null;
|
|
276
276
|
|
|
277
|
-
// Routing-
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
//
|
|
281
|
-
//
|
|
277
|
+
// Routing-savings headline line (multi-line layout). The lifetime sum from
|
|
278
|
+
// the delegation ledger — the number the whole tool exists to grow, so it
|
|
279
|
+
// gets line 1 to itself while the diagnostics move to line 2.
|
|
280
|
+
//
|
|
281
|
+
// One figure, not three. The weekly and monthly sums used to sit here too,
|
|
282
|
+
// but the per-model breakdown that follows is a lifetime split, and next to
|
|
283
|
+
// a row of rolling windows it read as a breakdown of whichever one it
|
|
284
|
+
// touched. A single lifetime total makes the whole line one timeframe with
|
|
285
|
+
// nothing to mismatch.
|
|
286
|
+
// icon: "🔀 Routing saved $9.8 | opus→haiku 2× $6.4 · fable→sonnet 1× $3.4"
|
|
287
|
+
// text: "Routing saved $9.8 | opus→haiku 2× $6.4 · fable→sonnet 1× $3.4"
|
|
282
288
|
const totals = data.delegationTotals;
|
|
283
289
|
let totalsLine = null;
|
|
284
290
|
if (!singleLine && totals && Number(totals.total) > 0) {
|
|
285
|
-
// Money is green throughout — it is saved cost, the one number on the
|
|
286
|
-
// line that is unambiguously good news. The period markers stay gray so
|
|
287
|
-
// the eye lands on the amounts, not on "wk / mo / all".
|
|
288
|
-
// Period first, amount second — three bare amounts in a row read as one
|
|
289
|
-
// number until the eye finds the trailing marker, so the label leads and
|
|
290
|
-
// the green amount answers it.
|
|
291
|
-
const part = (usd, label) =>
|
|
292
|
-
`${c(GRAY)}${label}${c(RESET)} ${c(GREEN)}${formatMoney(Number(usd) || 0)}${c(RESET)}`;
|
|
293
291
|
const head = isIcon ? '🔀 Routing saved' : 'Routing saved';
|
|
294
292
|
// Model changes behind the total, family-level and version-free: `opus →
|
|
295
293
|
// haiku 2× $0.6`. Versions bump constantly and add nothing here — the
|
|
@@ -301,14 +299,16 @@ export function formatReport(data, { color = true, verbose = false, timer = true
|
|
|
301
299
|
// there are only so many tier-to-tier moves — so it stays short without
|
|
302
300
|
// being cut.
|
|
303
301
|
const pairs = Array.isArray(totals.pairs) ? totals.pairs : [];
|
|
302
|
+
// The breakdown stays entirely gray, amounts included. Only the total is
|
|
303
|
+
// green: it is the headline figure, and repeating that green on every
|
|
304
|
+
// component would flatten the line into one loud block with nothing to
|
|
305
|
+
// land on first.
|
|
304
306
|
const pairText = pairs
|
|
305
|
-
.map((p) => `${c(GRAY)}${p.from}→${p.to}
|
|
307
|
+
.map((p) => `${c(GRAY)}${p.from}→${p.to} ${p.runs}× ${formatMoney(p.usd)}${c(RESET)}`)
|
|
306
308
|
.join(` ${c(GRAY)}·${c(RESET)} `);
|
|
307
309
|
totalsLine =
|
|
308
310
|
`${c(GREEN)}${c(BOLD)}${head}${c(RESET)} ` +
|
|
309
|
-
`${
|
|
310
|
-
`${part(totals.month, 'monthly')} ${c(GRAY)}·${c(RESET)} ` +
|
|
311
|
-
`${part(totals.total, 'total')}` +
|
|
311
|
+
`${c(GREEN)}${formatMoney(Number(totals.total) || 0)}${c(RESET)}` +
|
|
312
312
|
(pairText ? ` ${c(GRAY)}|${c(RESET)} ${pairText}` : '');
|
|
313
313
|
}
|
|
314
314
|
|