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.
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:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Read|Bash",
"hooks": [{ "type": "command", "command": "tsave guard" }]
}
]
}
}
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
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:
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
git clone https://github.com/remo12262/token-saver.git
cd token-saver
pip install -e ".[dev]"
pytest
# 85 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.
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:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Read|Bash",
"hooks": [{ "type": "command", "command": "tsave guard" }]
}
]
}
}
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
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:
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
git clone https://github.com/remo12262/token-saver.git
cd token-saver
pip install -e ".[dev]"
pytest
# 85 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
Licenza MIT. Costruito in una serata con Claude Code.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tsave-0.3.0.tar.gz.
File metadata
- Download URL: tsave-0.3.0.tar.gz
- Upload date:
- Size: 32.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b85707e9d8b9f4cab7eaf5ec9c04498f397e123b997d7ce3bd5329d90cd41ddf
|
|
| MD5 |
c38509b33e1b73b957c7719607f3d3ac
|
|
| BLAKE2b-256 |
c9db338a00b3e5a2279054056edcfeeaf879eb196b686245e056283472361e1b
|
Provenance
The following attestation bundles were made for tsave-0.3.0.tar.gz:
Publisher:
publish.yml on remo12262/token-saver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tsave-0.3.0.tar.gz -
Subject digest:
b85707e9d8b9f4cab7eaf5ec9c04498f397e123b997d7ce3bd5329d90cd41ddf - Sigstore transparency entry: 2070976121
- Sigstore integration time:
-
Permalink:
remo12262/token-saver@714a0dd02e1a3b762677cef43aa412f23307d0d1 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/remo12262
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@714a0dd02e1a3b762677cef43aa412f23307d0d1 -
Trigger Event:
release
-
Statement type:
File details
Details for the file tsave-0.3.0-py3-none-any.whl.
File metadata
- Download URL: tsave-0.3.0-py3-none-any.whl
- Upload date:
- Size: 23.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1307a67f4878476218fa81f626b3e9c1bc9674d0ca225c5dd9a1b6c180259998
|
|
| MD5 |
15157822306c95e1a831d129559df5c1
|
|
| BLAKE2b-256 |
5d28001f0cfb311fef57be492ccd939df5e3dd2764fe46cff39800893d0d5afe
|
Provenance
The following attestation bundles were made for tsave-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on remo12262/token-saver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tsave-0.3.0-py3-none-any.whl -
Subject digest:
1307a67f4878476218fa81f626b3e9c1bc9674d0ca225c5dd9a1b6c180259998 - Sigstore transparency entry: 2070976134
- Sigstore integration time:
-
Permalink:
remo12262/token-saver@714a0dd02e1a3b762677cef43aa412f23307d0d1 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/remo12262
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@714a0dd02e1a3b762677cef43aa412f23307d0d1 -
Trigger Event:
release
-
Statement type: