{"id":51444165,"url":"https://github.com/remo12262/token-saver","last_synced_at":"2026-07-05T14:30:38.649Z","repository":{"id":366918072,"uuid":"1278468916","full_name":"remo12262/token-saver","owner":"remo12262","description":"Drop-in Anthropic client wrapper for token counting, cost analysis, semantic compression, overflow recovery, and a Claude Code context-guard hook.","archived":false,"fork":false,"pushed_at":"2026-07-04T14:53:04.000Z","size":113,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-04T15:20:36.993Z","etag":null,"topics":["anthropic","claude","cli","cost-reduction","llm","made-in-italy","open-source","pulcini","python","remo","token-optimization"],"latest_commit_sha":null,"homepage":"https://github.com/remo12262/token-saver","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/remo12262.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-23T20:27:45.000Z","updated_at":"2026-07-04T14:53:07.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/remo12262/token-saver","commit_stats":null,"previous_names":["remo12262/token-saver"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/remo12262/token-saver","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remo12262%2Ftoken-saver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remo12262%2Ftoken-saver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remo12262%2Ftoken-saver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remo12262%2Ftoken-saver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/remo12262","download_url":"https://codeload.github.com/remo12262/token-saver/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remo12262%2Ftoken-saver/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35158308,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-05T02:00:06.290Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anthropic","claude","cli","cost-reduction","llm","made-in-italy","open-source","pulcini","python","remo","token-optimization"],"created_at":"2026-07-05T14:30:38.193Z","updated_at":"2026-07-05T14:30:38.640Z","avatar_url":"https://github.com/remo12262.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/remo12262/token-saver/actions/workflows/tests.yml\"\u003e\n    \u003cimg src=\"https://github.com/remo12262/token-saver/actions/workflows/tests.yml/badge.svg\" alt=\"tests\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://pypi.org/project/tsave/\"\u003e\n    \u003cimg src=\"https://img.shields.io/pypi/v/tsave\" alt=\"PyPI\"\u003e\n  \u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/python-3.10%2B-blue\" alt=\"Python\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/license-MIT-green\" alt=\"License\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/dependencies-anthropic-blue\" alt=\"dependencies\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003etsave\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\u003cem\u003eStop discovering costs after the fact. See where your tokens go before you run a single line.\u003c/em\u003e\u003c/p\u003e\n\u003cp align=\"center\"\u003e\u003cem\u003eSmetti di scoprire i costi a consuntivo. Vedi dove vanno i token prima ancora di eseguire il codice.\u003c/em\u003e\u003c/p\u003e\n\n---\n\n\u003c!-- ENGLISH VERSION --\u003e\n\n## 🇬🇧 English\n\nI got tired of watching my Anthropic bill grow without knowing why.\n\nSo 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.\n\n```bash\npip install tsave\ntsave scan chatbot.py\n```\n\nNo API key needed for that last command. It reads your Python file, walks the AST, and tells you what's wrong.\n\n---\n\n### What it actually does\n\n#### 🔍 Scan your code before you run it\n\nThis 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.\n\nEach finding comes with:\n- the line number\n- an estimate of how many tokens you're burning\n- a ready-to-paste fix\n\n#### 🪙 Count tokens accurately\n\nNot with tiktoken — tiktoken undercounts Claude by 15–20%. tsave uses the official Anthropic `count_tokens` API, the same one that feeds the billing system.\n\n#### 📉 Compress long conversations\n\nWhen 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.\n\n#### 📊 Track what you spend\n\nEvery `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.\n\n#### 🪝 Guard your Claude Code sessions\n\n`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).\n\nIt'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.\n\nAdd it to `.claude/settings.json`:\n\n```json\n{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Read|Bash\",\n        \"hooks\": [{ \"type\": \"command\", \"command\": \"tsave guard\" }]\n      }\n    ]\n  }\n}\n```\n\n#### 🧾 Recover from overflow without losing the thread\n\nWhen 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.\n\nLike 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.\n\n```python\nresult = client.compress(model=\"claude-sonnet-4-6\", messages=long_chat, keep_last_n=4)\nprint(result.format())\n# Original:   1,131 tokens (13 messages)\n# Compressed: 363 tokens (3 messages) — 67.9% reduction\n#\n# [Recovery Contract]\n# - Active goal: ...\n# - Last successful action: ...\n# - Open files/context: ...\n```\n\n---\n\n### Numbers\n\nReal runs on real workloads, not synthetic benchmarks:\n\n| Scenario | Before | After | At 1K req/day |\n|---|---|---|---|\n| Multi-turn chatbot (50 turns) | 12,400 tokens | 4,100 tokens **−66.9%** | saves $7.47/day |\n| RAG pipeline (full doc per call) | 18,200 tokens | 5,600 tokens **−69.2%** | saves $11.34/day |\n| Batch classifier (loop + Opus) | 8,500 tokens | 2,800 tokens **−67.1%** | saves $8.55/day |\n\n*Sonnet 4.6 pricing, $3/MTok input.*\n\n---\n\n### Usage\n\n```python\nfrom tsave import TsaveClient\n\nclient = TsaveClient()\n\n# count tokens before spending them\ntc = client.count_tokens(model=\"claude-sonnet-4-6\", messages=messages)\nprint(tc.format())\n# 847 input tokens | est. $0.0025\n\n# compress a long conversation\nresult = client.compress(model=\"claude-sonnet-4-6\", messages=long_chat, keep_last_n=4)\nprint(result.format())\n# Original:   1,131 tokens (13 messages)\n# Compressed: 363 tokens (3 messages) — 67.9% reduction\n\n# make the actual call — usage is tracked automatically\nresponse = client.create(model=\"claude-sonnet-4-6\", max_tokens=1024, messages=messages)\n\n# see where you stand\nprint(client.usage_summary())\nprint(client.monthly_projection(requests_per_day=500).format())\n# Monthly (30 days): $410.40\n```\n\nThe CLI gives you the same things without writing any code:\n\n```bash\ntsave scan myapp.py        # static analysis, no API key\ntsave analyze              # token breakdown of a conversation\ntsave cost                 # cost estimate\ntsave compress             # compress a conversation file\n```\n\n---\n\n### What the scanner catches\n\n| Pattern | What it means |\n|---|---|\n| `api-in-loop` | You're making a full API request on every loop iteration |\n| `full-file-per-call` | You're reading an entire file and passing it raw to the API |\n| `no-model-routing` | You're using Opus where Haiku would work fine |\n| `system-prompt-redefined` | Your system prompt gets recreated on every call |\n| `uncached-system-prompt` | Your system prompt is in a loop without `cache_control` |\n| `uncompressed-history` | Your message history keeps growing with no compression |\n\n\u003e 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.\n\n---\n\n### Development\n\n```bash\ngit clone https://github.com/remo12262/token-saver.git\ncd token-saver\npip install -e \".[dev]\"\npytest\n# 147 tests, all pass without an API key\n```\n\n---\n\n### Models \u0026 pricing\n\n| Model | Input | Output |\n|---|---|---|\n| Claude Opus 4.8 / 4.7 / 4.6 | $5.00/MTok | $25.00/MTok |\n| Claude Sonnet 4.6 | $3.00/MTok | $15.00/MTok |\n| Claude Haiku 4.5 | $1.00/MTok | $5.00/MTok |\n\nMIT license. Built in one evening with Claude Code.\n\n---\n---\n---\n\nBuilt in one evening with Claude Code.\n\n\n\u003c!-- VERSIONE ITALIANA --\u003e\n\n## 🇮🇹 Italiano\n\nMi ero stancato di guardare la mia bolletta Anthropic crescere senza capire perché.\n\nCosì 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.\n\n```bash\npip install tsave\ntsave scan chatbot.py\n```\n\nPer quest'ultimo comando non serve nessuna API key. Legge il file Python, analizza l'AST, e ti dice cosa c'è che non va.\n\n---\n\n### Cosa fa concretamente\n\n#### 🔍 Analizza il codice prima che tu lo esegua\n\nQuesta è 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.\n\nOgni finding mostra:\n- il numero di riga\n- una stima dei token sprecati\n- una correzione pronta da incollare\n\n#### 🪙 Conta i token in modo preciso\n\nNon 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.\n\n#### 📉 Comprime le conversazioni lunghe\n\nQuando 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.\n\n#### 📊 Traccia quello che spendi\n\nOgni chiamata `client.create()` viene registrata. A fine sessione puoi richiedere un riepilogo dei consumi, il costo medio per richiesta e una proiezione mensile.\n\n#### 🪝 Proteggi le tue sessioni Claude Code\n\n`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).\n\nÈ 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.\n\nAggiungilo a `.claude/settings.json`:\n\n```json\n{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Read|Bash\",\n        \"hooks\": [{ \"type\": \"command\", \"command\": \"tsave guard\" }]\n      }\n    ]\n  }\n}\n```\n\n#### 🧾 Recupera da un overflow senza perdere il filo\n\nQuando 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.\n\nCome 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.\n\n```python\nresult = client.compress(model=\"claude-sonnet-4-6\", messages=long_chat, keep_last_n=4)\nprint(result.format())\n# Originale:   1.131 token (13 messaggi)\n# Compresso:   363 token (3 messaggi) — riduzione del 67,9%\n#\n# [Recovery Contract]\n# - Obiettivo attivo: ...\n# - Ultima azione riuscita: ...\n# - File/contesto aperti: ...\n```\n\n---\n\n### I numeri\n\nRisultati reali su workload reali, non benchmark sintetici:\n\n| Scenario | Prima | Dopo | A 1.000 req/giorno |\n|---|---|---|---|\n| Chatbot multi-turno (50 turni) | 12.400 token | 4.100 token **−66,9%** | risparmia $7,47/giorno |\n| Pipeline RAG (doc completo per chiamata) | 18.200 token | 5.600 token **−69,2%** | risparmia $11,34/giorno |\n| Classificatore batch (loop + Opus) | 8.500 token | 2.800 token **−67,1%** | risparmia $8,55/giorno |\n\n*Prezzi Sonnet 4.6, $3/MTok in input.*\n\n---\n\n### Utilizzo\n\n```python\nfrom tsave import TsaveClient\n\nclient = TsaveClient()\n\n# conta i token prima di spenderli\ntc = client.count_tokens(model=\"claude-sonnet-4-6\", messages=messages)\nprint(tc.format())\n# 847 input tokens | est. $0.0025\n\n# comprimi una conversazione lunga\nresult = client.compress(model=\"claude-sonnet-4-6\", messages=long_chat, keep_last_n=4)\nprint(result.format())\n# Originale:   1.131 token (13 messaggi)\n# Compresso:   363 token (3 messaggi) — riduzione del 67,9%\n\n# fai la vera chiamata — l'utilizzo viene tracciato automaticamente\nresponse = client.create(model=\"claude-sonnet-4-6\", max_tokens=1024, messages=messages)\n\n# vedi dove sei\nprint(client.usage_summary())\nprint(client.monthly_projection(requests_per_day=500).format())\n# Mensile (30 giorni): $410.40\n```\n\nLa CLI ti dà le stesse cose senza scrivere codice:\n\n```bash\ntsave scan myapp.py        # analisi statica, senza API key\ntsave analyze              # breakdown dei token di una conversazione\ntsave cost                 # stima dei costi\ntsave compress             # comprimi un file di conversazione\n```\n\n---\n\n### Cosa rileva lo scanner\n\n| Pattern | Cosa significa |\n|---|---|\n| `api-in-loop` | Stai facendo una richiesta API completa a ogni iterazione del loop |\n| `full-file-per-call` | Stai leggendo un file intero e passandolo grezzo all'API |\n| `no-model-routing` | Stai usando Opus dove basterebbe Haiku |\n| `system-prompt-redefined` | Il tuo system prompt viene ricreato a ogni chiamata |\n| `uncached-system-prompt` | Il tuo system prompt è in un loop senza `cache_control` |\n| `uncompressed-history` | La cronologia dei messaggi continua a crescere senza compressione |\n\n\u003e 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.\n\n---\n\n### Sviluppo\n\n```bash\ngit clone https://github.com/remo12262/token-saver.git\ncd token-saver\npip install -e \".[dev]\"\npytest\n# 147 test, tutti passano senza API key\n```\n\n---\n\n### Modelli e prezzi\n\n| Modello | Input | Output |\n|---|---|---|\n| Claude Opus 4.8 / 4.7 / 4.6 | $5,00/MTok | $25,00/MTok |\n| Claude Sonnet 4.6 | $3,00/MTok | $15,00/MTok |\n| Claude Haiku 4.5 | $1,00/MTok | $5,00/MTok |\n\u003c/P\u003e ---\n\n📣 **Share / Condividi**\n\n[![LinkedIn](https://img.shields.io/badge/Share-LinkedIn-0A66C2?logo=linkedin)](https://www.linkedin.com/sharing/share-offsite/?url=https://github.com/remo12262/token-saver)\n[![Twitter/X](https://img.shields.io/badge/Share-X-000000?logo=x)](https://twitter.com/intent/tweet?url=https://github.com/remo12262/token-saver\u0026text=tsave+—+predictive+token+optimizer+for+the+Anthropic+API)\n[![Facebook](https://img.shields.io/badge/Share-Facebook-1877F2?logo=facebook)](https://www.facebook.com/sharer/sharer.php?u=https://github.com/remo12262/token-saver)\n\nLicenza MIT. Costruito in una serata con Claude Code.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremo12262%2Ftoken-saver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fremo12262%2Ftoken-saver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremo12262%2Ftoken-saver/lists"}