https://github.com/remo12262/token-saver
Drop-in Anthropic client wrapper for token counting, cost analysis, semantic compression, overflow recovery, and a Claude Code context-guard hook.
https://github.com/remo12262/token-saver
anthropic claude cli cost-reduction llm made-in-italy open-source pulcini python remo token-optimization
Last synced: 22 days ago
JSON representation
Drop-in Anthropic client wrapper for token counting, cost analysis, semantic compression, overflow recovery, and a Claude Code context-guard hook.
- Host: GitHub
- URL: https://github.com/remo12262/token-saver
- Owner: remo12262
- License: mit
- Created: 2026-06-23T20:27:45.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-07-04T14:53:04.000Z (23 days ago)
- Last Synced: 2026-07-04T15:20:36.993Z (23 days ago)
- Topics: anthropic, claude, cli, cost-reduction, llm, made-in-italy, open-source, pulcini, python, remo, token-optimization
- Language: Python
- Homepage: https://github.com/remo12262/token-saver
- Size: 110 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
tsave
Stop discovering costs after the fact. See where your tokens go before you run a single line.
Smetti di scoprire i costi a consuntivo. Vedi dove vanno i token prima ancora di eseguire il codice.
---
## ๐ฌ๐ง English
I got tired of watching my Anthropic bill grow without knowing why.
So I built this: a wrapper around the official SDK that tells you โ **before you run your code** โ exactly where your tokens are going and what to do about it.
```bash
pip install tsave
tsave scan chatbot.py
```
No API key needed for that last command. It reads your Python file, walks the AST, and tells you what's wrong.
---
### What it actually does
#### ๐ Scan your code before you run it
This is the part I'm most proud of. Point it at a `.py` file and it finds patterns like API calls inside loops, system prompts sent without `cache_control`, conversation history growing unbounded โ the kind of stuff that quietly triples your bill.
Each finding comes with:
- the line number
- an estimate of how many tokens you're burning
- a ready-to-paste fix
#### ๐ช Count tokens accurately
Not with tiktoken โ tiktoken undercounts Claude by 15โ20%. tsave uses the official Anthropic `count_tokens` API, the same one that feeds the billing system.
#### ๐ Compress long conversations
When a chat history gets long, tsave summarizes the older turns while keeping recent context intact. In practice, this cuts **65โ70% of tokens** on multi-turn workloads.
#### ๐ Track what you spend
Every `client.create()` call gets logged. At the end of a session you can ask for a usage summary, an average cost per request, and a monthly projection.
#### ๐ช Guard your Claude Code sessions
`tsave guard` is a PreToolUse hook for Claude Code โ it catches waste at the *session* level, before the API is even involved. It intercepts `Read` and `Bash` calls and flags the two patterns that quietly bloat a session's context: reading a whole large file when you only needed a slice, and shell commands that dump unbounded output (`cat` with no pipe, `find` with no `-maxdepth`, `git log` with no limit, unscoped recursive `grep`, noisy package installs).
It's pure local heuristics โ file-size estimation and regex, no API calls โ because a hook runs synchronously on every matching tool call and can't add latency or cost of its own.
Add it to `.claude/settings.json`:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Read|Bash",
"hooks": [{ "type": "command", "command": "tsave guard" }]
}
]
}
}
```
#### ๐งพ Recover from overflow without losing the thread
When a conversation overflows and gets compressed, a narrative summary alone can lose the concrete thread of what you were doing. `RecoveryContract` rides alongside the compressed history and captures the handful of facts that actually matter for continuing correctly: the active goal, the last successful tool call, open files/context, the error that triggered recovery, and any assumptions stated along the way.
Like everything else here, it's built from local heuristics โ regex and `tool_use` block scanning โ so it adds no extra API call, cost, or latency on top of the compression that was already happening.
```python
result = client.compress(model="claude-sonnet-4-6", messages=long_chat, keep_last_n=4)
print(result.format())
# Original: 1,131 tokens (13 messages)
# Compressed: 363 tokens (3 messages) โ 67.9% reduction
#
# [Recovery Contract]
# - Active goal: ...
# - Last successful action: ...
# - Open files/context: ...
```
---
### Numbers
Real runs on real workloads, not synthetic benchmarks:
| Scenario | Before | After | At 1K req/day |
|---|---|---|---|
| Multi-turn chatbot (50 turns) | 12,400 tokens | 4,100 tokens **โ66.9%** | saves $7.47/day |
| RAG pipeline (full doc per call) | 18,200 tokens | 5,600 tokens **โ69.2%** | saves $11.34/day |
| Batch classifier (loop + Opus) | 8,500 tokens | 2,800 tokens **โ67.1%** | saves $8.55/day |
*Sonnet 4.6 pricing, $3/MTok input.*
---
### Usage
```python
from tsave import TsaveClient
client = TsaveClient()
# count tokens before spending them
tc = client.count_tokens(model="claude-sonnet-4-6", messages=messages)
print(tc.format())
# 847 input tokens | est. $0.0025
# compress a long conversation
result = client.compress(model="claude-sonnet-4-6", messages=long_chat, keep_last_n=4)
print(result.format())
# Original: 1,131 tokens (13 messages)
# Compressed: 363 tokens (3 messages) โ 67.9% reduction
# make the actual call โ usage is tracked automatically
response = client.create(model="claude-sonnet-4-6", max_tokens=1024, messages=messages)
# see where you stand
print(client.usage_summary())
print(client.monthly_projection(requests_per_day=500).format())
# Monthly (30 days): $410.40
```
The CLI gives you the same things without writing any code:
```bash
tsave scan myapp.py # static analysis, no API key
tsave analyze # token breakdown of a conversation
tsave cost # cost estimate
tsave compress # compress a conversation file
```
---
### What the scanner catches
| Pattern | What it means |
|---|---|
| `api-in-loop` | You're making a full API request on every loop iteration |
| `full-file-per-call` | You're reading an entire file and passing it raw to the API |
| `no-model-routing` | You're using Opus where Haiku would work fine |
| `system-prompt-redefined` | Your system prompt gets recreated on every call |
| `uncached-system-prompt` | Your system prompt is in a loop without `cache_control` |
| `uncompressed-history` | Your message history keeps growing with no compression |
> Files that can't be parsed (syntax errors, unsupported encodings) are reported as "could not analyze" โ never silently skipped or marked clean. The CLI exits non-zero on them. UTF-8 BOM files are handled transparently.
---
### Development
```bash
git clone https://github.com/remo12262/token-saver.git
cd token-saver
pip install -e ".[dev]"
pytest
# 147 tests, all pass without an API key
```
---
### Models & pricing
| Model | Input | Output |
|---|---|---|
| Claude Opus 4.8 / 4.7 / 4.6 | $5.00/MTok | $25.00/MTok |
| Claude Sonnet 4.6 | $3.00/MTok | $15.00/MTok |
| Claude Haiku 4.5 | $1.00/MTok | $5.00/MTok |
MIT license. Built in one evening with Claude Code.
---
---
---
Built in one evening with Claude Code.
## ๐ฎ๐น Italiano
Mi ero stancato di guardare la mia bolletta Anthropic crescere senza capire perchรฉ.
Cosรฌ ho costruito questo: un wrapper attorno all'SDK ufficiale che ti dice โ **prima di eseguire il codice** โ esattamente dove stanno andando i tuoi token e cosa fare al riguardo.
```bash
pip install tsave
tsave scan chatbot.py
```
Per quest'ultimo comando non serve nessuna API key. Legge il file Python, analizza l'AST, e ti dice cosa c'รจ che non va.
---
### Cosa fa concretamente
#### ๐ Analizza il codice prima che tu lo esegua
Questa รจ la parte di cui vado piรน fiero. Puntalo su un file `.py` e trova pattern come chiamate API dentro i loop, system prompt inviati senza `cache_control`, cronologie di conversazione che crescono senza controllo โ il tipo di cose che silenziosamente triplicano la bolletta.
Ogni finding mostra:
- il numero di riga
- una stima dei token sprecati
- una correzione pronta da incollare
#### ๐ช Conta i token in modo preciso
Non con tiktoken โ tiktoken sottostima Claude del 15โ20%. tsave usa l'API ufficiale `count_tokens` di Anthropic, la stessa che alimenta il sistema di fatturazione.
#### ๐ Comprime le conversazioni lunghe
Quando una cronologia di chat diventa lunga, tsave riassume i turni piรน vecchi mantenendo il contesto recente intatto. In pratica, questo taglia il **65โ70% dei token** sui workload multi-turno.
#### ๐ Traccia quello che spendi
Ogni chiamata `client.create()` viene registrata. A fine sessione puoi richiedere un riepilogo dei consumi, il costo medio per richiesta e una proiezione mensile.
#### ๐ช Proteggi le tue sessioni Claude Code
`tsave guard` รจ un hook PreToolUse per Claude Code โ intercetta lo spreco a livello di *sessione*, prima ancora che l'API entri in gioco. Controlla le chiamate `Read` e `Bash` e segnala i due pattern che gonfiano silenziosamente il contesto: leggere un intero file grande quando serviva solo una porzione, e comandi shell che riversano output senza limiti (`cat` senza pipe, `find` senza `-maxdepth`, `git log` senza limite, `grep` ricorsivo non delimitato, installazioni di pacchetti rumorose).
ร tutto euristica locale โ stima della dimensione file e regex, nessuna chiamata API โ perchรฉ un hook gira in modo sincrono su ogni tool call che corrisponde, e non puรฒ permettersi latenza o costo propri.
Aggiungilo a `.claude/settings.json`:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Read|Bash",
"hooks": [{ "type": "command", "command": "tsave guard" }]
}
]
}
}
```
#### ๐งพ Recupera da un overflow senza perdere il filo
Quando una conversazione va in overflow e viene compressa, un riassunto narrativo da solo puรฒ far perdere il filo concreto di cosa stavi facendo. `RecoveryContract` affianca la cronologia compressa e cattura le poche informazioni che contano davvero per continuare correttamente: l'obiettivo attivo, l'ultima azione/tool riuscito, i file/contesto aperti, l'errore che ha scatenato il recovery, e le eventuali assunzioni dichiarate lungo il percorso.
Come tutto il resto qui, รจ costruito con euristiche locali โ regex e scansione dei blocchi `tool_use` โ quindi non aggiunge nessuna chiamata API, costo o latenza extra oltre alla compressione che stava giร avvenendo.
```python
result = client.compress(model="claude-sonnet-4-6", messages=long_chat, keep_last_n=4)
print(result.format())
# Originale: 1.131 token (13 messaggi)
# Compresso: 363 token (3 messaggi) โ riduzione del 67,9%
#
# [Recovery Contract]
# - Obiettivo attivo: ...
# - Ultima azione riuscita: ...
# - File/contesto aperti: ...
```
---
### I numeri
Risultati reali su workload reali, non benchmark sintetici:
| Scenario | Prima | Dopo | A 1.000 req/giorno |
|---|---|---|---|
| Chatbot multi-turno (50 turni) | 12.400 token | 4.100 token **โ66,9%** | risparmia $7,47/giorno |
| Pipeline RAG (doc completo per chiamata) | 18.200 token | 5.600 token **โ69,2%** | risparmia $11,34/giorno |
| Classificatore batch (loop + Opus) | 8.500 token | 2.800 token **โ67,1%** | risparmia $8,55/giorno |
*Prezzi Sonnet 4.6, $3/MTok in input.*
---
### Utilizzo
```python
from tsave import TsaveClient
client = TsaveClient()
# conta i token prima di spenderli
tc = client.count_tokens(model="claude-sonnet-4-6", messages=messages)
print(tc.format())
# 847 input tokens | est. $0.0025
# comprimi una conversazione lunga
result = client.compress(model="claude-sonnet-4-6", messages=long_chat, keep_last_n=4)
print(result.format())
# Originale: 1.131 token (13 messaggi)
# Compresso: 363 token (3 messaggi) โ riduzione del 67,9%
# fai la vera chiamata โ l'utilizzo viene tracciato automaticamente
response = client.create(model="claude-sonnet-4-6", max_tokens=1024, messages=messages)
# vedi dove sei
print(client.usage_summary())
print(client.monthly_projection(requests_per_day=500).format())
# Mensile (30 giorni): $410.40
```
La CLI ti dร le stesse cose senza scrivere codice:
```bash
tsave scan myapp.py # analisi statica, senza API key
tsave analyze # breakdown dei token di una conversazione
tsave cost # stima dei costi
tsave compress # comprimi un file di conversazione
```
---
### Cosa rileva lo scanner
| Pattern | Cosa significa |
|---|---|
| `api-in-loop` | Stai facendo una richiesta API completa a ogni iterazione del loop |
| `full-file-per-call` | Stai leggendo un file intero e passandolo grezzo all'API |
| `no-model-routing` | Stai usando Opus dove basterebbe Haiku |
| `system-prompt-redefined` | Il tuo system prompt viene ricreato a ogni chiamata |
| `uncached-system-prompt` | Il tuo system prompt รจ in un loop senza `cache_control` |
| `uncompressed-history` | La cronologia dei messaggi continua a crescere senza compressione |
> I file non analizzabili (errori di sintassi, encoding non supportati) vengono segnalati come "could not analyze" โ mai saltati in silenzio o dati per puliti. La CLI esce con codice โ 0 su questi file. I file con BOM UTF-8 sono gestiti in modo trasparente.
---
### Sviluppo
```bash
git clone https://github.com/remo12262/token-saver.git
cd token-saver
pip install -e ".[dev]"
pytest
# 147 test, tutti passano senza API key
```
---
### Modelli e prezzi
| Modello | Input | Output |
|---|---|---|
| Claude Opus 4.8 / 4.7 / 4.6 | $5,00/MTok | $25,00/MTok |
| Claude Sonnet 4.6 | $3,00/MTok | $15,00/MTok |
| Claude Haiku 4.5 | $1,00/MTok | $5,00/MTok |
---
๐ฃ **Share / Condividi**
[](https://www.linkedin.com/sharing/share-offsite/?url=https://github.com/remo12262/token-saver)
[](https://twitter.com/intent/tweet?url=https://github.com/remo12262/token-saver&text=tsave+โ+predictive+token+optimizer+for+the+Anthropic+API)
[](https://www.facebook.com/sharer/sharer.php?u=https://github.com/remo12262/token-saver)
Licenza MIT. Costruito in una serata con Claude Code.