Show HN: Turo – An Aggressive Token-Saving Proxy for CLI AI Agents
Turo is an aggressive token-saving proxy that reduces prompt sizes for CLI AI agents by deleting filler words, replacing synonyms, and reducing to content words, with multiple compression levels including a Classical Chinese mode (wenyan). It can be integrated as a proxy or run directly with supported agents to cut token costs by up to 70%.
Uh oh!
There was an error while loading. Please reload this page.
Notifications You must be signed in to change notification settings
Fork 0
Star 0
BranchesTags
Open more actions menu
Folders and files
NameName
Last commit message
Last commit date
Latest commit
History
43 Commits
43 Commits
.github/workflows
.github/workflows
bin
bin
commands
commands
docs
docs
skills/turo
skills/turo
tools
tools
.gitignore
.gitignore
.goreleaser.yaml
.goreleaser.yaml
AGENTS.md
AGENTS.md
GEMINI.md
GEMINI.md
Makefile
Makefile
README.md
README.md
agents.go
agents.go
dict.go
dict.go
dictionary.csv
dictionary.csv
gemini-extension.json
gemini-extension.json
gloss_data.go
gloss_data.go
go.mod
go.mod
go.sum
go.sum
install.sh
install.sh
main.go
main.go
main_test.go
main_test.go
package.json
package.json
proxy.go
proxy.go
proxy_test.go
proxy_test.go
run.go
run.go
run_test.go
run_test.go
shrink.go
shrink.go
thesaurus_data.go
thesaurus_data.go
wenyan_data.go
wenyan_data.go
Repository files navigation
becomes 54 tokens — 61% fewer (turo, meaning intact):
Reviewing pull request make examine changed files verify new code introduce regressions existing behavior important check author added appropriate tests functionality untested break subtle ways difficult debug later also confirm documentation updated reflect changes commit messages explain notice potential security vulnerabilities unsanitized user input hardcoded credentials must flag merged
or 41 tokens — 70% fewer at --level ultra (deduped by lemma):
Review pull request make examine change file verify code introduce regression exist behavior important check author add test untested break debug later confirm documentation updated reflect commit message notice security vulnerability unsanitized user input hardcoded must flag merge
Or 69 characters with --level wenyan, which additionally swaps each word for a single Classical Chinese character (for CJK-tokenizer models — see wenyan):
閱引請作察變檔驗碼引退存為要查者增試 untested 破診後證文更映交訊覺安隙 unsanitized 戶入 hardcoded 須標併
766 -> 69 characters (35 Han chars). Token counts for that output:
tokenizer tokens
Qwen / DeepSeek / GLM (~1 per Han char) ~42
OpenAI cl100k (2-3 per Han char) 67
So wenyan wins on CJK-tokenizer models (~42 vs plain ultra's ~71) but loses on OpenAI (67 vs 41) — use it only with CJK models. See below.
No articles. No prepositions. No adverbs. No repeated words. Only the content words that carry meaning, deduplicated, in reading order. Every prompt, every turn — the savings compound. If a reduction is not smaller than the input, turo passes the original through unchanged.
Install turo once and any coding agent that can shell out to a binary — Claude Code, Codex, Gemini, Cursor, Windsurf, Cline, Copilot, and 20+ more — pipes its context through the same reducer. Code, paths, and identifiers pass through untouched.
Install
Method Command
Homebrew brew install kdeps/tap/turo
Go go install github.com/kdeps/turo@latest
Shell curl -fsSL https://raw.githubusercontent.com/kdeps/turo/main/install.sh | sh
Manual Download from releases
Usage
cat CLAUDE.md | turo # text -> deduped content words echo "fox jumps over dog" | turo # pipe mode turo --preamble # wrap for system prompt injection turo -passes 1 # single pass (default runs to convergence) turo -filler=false # skip filler deletion turo -synonyms=false # skip the synonym pass (keep words verbatim) turo -gloss=false # skip the defining-word swap (less lossy) turo -arrows # replace connective phrases with -> (opt-in) turo --version # print version
-gloss (on by default) replaces each word with the shortest same-part-of-speech word from its own dictionary definition (approach -> come). Definitions are prose, not synonyms, so it is the lossiest stage — disable it with -gloss=false / TURO_GLOSS=off when you need words closer to the original.
-arrows (off by default) replaces multi-word causal/sequential connectives (leads to, results in, gives rise to, which produces) with a single -> token. Only multi-word phrases qualify, so the swap always saves at least one token; single-token connectives (then, becomes, thus) are left alone because -> costs the same. Enable with -arrows / TURO_ARROWS=on.
A cache miss leads to a slow query which produces a timeout | -arrows Cache miss -> slow query -> timeout
Pipeline
Every run is four stages, each on by default:
text -> [1] delete filler -> [2] swap cheaper synonyms -> [3] swap defining words -> [4] reduce to content words
Filler deletion removes pleasantries, hedges, and leaders that survive word-level stopword lists (please, I think, of course, let me), while protecting code, paths, URLs, and identifiers verbatim. Disable with -filler=false / TURO_FILLER=off.
Synonym swap replaces words with a fewer-token synonym (see below). Disable with -synonyms=false / TURO_SYNONYMS=off.
Gloss swap replaces words with the shortest defining word from their dictionary definition — the lossiest stage. Disable with -gloss=false / TURO_GLOSS=off.
Reduction drops the remaining stopwords, keeps content words by part of speech, deduplicates, and (ultra) collapses inflections by lemma.
Arrows (opt-in, runs before reduction) rewrites multi-word connective phrases to ->, which the reducer keeps verbatim between the surviving content words. Off by default; enable with -arrows / TURO_ARROWS=on.
The whole pipeline repeats until the output stops changing (-passes 0, the default; a positive -passes N caps the count). The first pass keeps document structure (headings, per-section bodies); later passes flatten that and dedupe across it, so large structured docs keep shrinking before converging — this README goes 522 (1 pass) -> 376 tokens (converged, ~29 passes). Set -passes 1 to keep it single-shot.
turo never emits output larger than the input: if a stage does not save tokens, the text passes through unchanged.
Synonym substitution (on by default, lossy)
turo runs a first pass that replaces each word with a fewer-token synonym before reducing (utilize -> use, demonstrate -> show). The table is built from WordNet synsets (real synonyms) and frequency-filtered so swaps land on common words, then gated to same-part-of-speech words and validated to cost strictly fewer tokens. turo still passes the original through if the result is not smaller.
Disable it with -synonyms=false or TURO_SYNONYMS=off when you need words verbatim. The gain is usually small — modern tokenizers already encode most words as a single token. WordNet polysemy also leaves some noise (leverage -> purchase), so keep it opt-in for prose, not code. The table is generated by tools/gensyn.py (WordNet + wordfreq + the cl100k tokenizer), so token counts are measured for cl100k, not the target model's tokenizer.
Intensity levels
Level What it keeps Reduction
lite Adjectives, nouns, verbs, and leftover adverbs/prepositions ~65%
full Adjectives, nouns, verbs ~70%
ultra (default) Nouns and verbs only, deduplicated by lemma (base form) ~70%+
wenyan ultra, then swap surviving words for a single 文言 (Classical Chinese) character CJK models only
echo "the quick brown fox jumps over the lazy dog" | turo --level lite # quick brown fox jumps over lazy dog echo "the quick brown fox jumps over the lazy dog" | turo --level full # quick brown fox jumps lazy dog echo "the quick brown fox jumps over the lazy dog" | turo --level ultra # fox jump dog echo "the wise king studies the old book" | turo --level wenyan # 智王學舊書
wenyan (CJK-tokenizer models only)
wenyan reduces at ultra, then swaps each surviving English content word for one Classical Chinese character (water -> 水, king -> 王, verify -> 驗) from a ~380-entry hand-curated lexicon. One char per concept, no spaces (Classical Chinese has none).
Two examples, measured:
input ultra wenyan chars cl100k CJK-model (~1/char)
The wise king uses water and fire... (80 ch) Wise king use water fire person see mountain old tree 智王用水火人見山舊樹 10 15 ~10
the PR-review paragraph (766 ch) 283 ch / 41 tok 閱引請作察變檔驗碼引退存為要查者增試 untested 破診後證文更映交訊覺安隙 unsanitized 戶入 hardcoded 須標併 69 67 ~42
It collapses to the fewest characters (766 -> 69 on the paragraph). A CJK character is 2-3 tokens on OpenAI's cl100k, so wenyan is larger there (67 > 41). It only wins on CJK-optimized tokenizers (Qwen, DeepSeek, GLM), where a common character is ~1 token — then those 69 chars are ~42 tokens vs plain ultra's 71. Don't use it with OpenAI models.
turo's own token estimator counts CJK as 1 rune = 1 token (matching those models), so it treats wenyan as a reduction and never rejects it. Words outside the lexicon stay English (untested, unsanitized, hardcoded above); code/paths/URLs are preserved verbatim. Extend wenyanMap for more coverage.
In ultra, inflections of the same word collapse to one token by their dictionary base form: goes, went, going -> go; children -> child; servers -> server. A reduction is only applied when it lands on a real dictionary word, so no mangled non-words are ever emitted.
Set default via TURO_LEVEL env var.
Proxy — reduce every request for any agent
To compress all input for an agent that turo can't reach from the inside (Claude Code, Codex, ...), route the agent's requests through turo.
turo run — launch an agent with everything reduced (turnkey)
turo run claude # every claude request reduced, base URL wired for you turo run codex # OPENAI_BASE_URL wired instead turo run # list supported agents
turo run starts an in-process proxy on a free port, points the agent's base-URL env var at it (ANTHROPIC_BASE_URL for claude, OPENAI_BASE_URL for OpenAI-compatible agents), execs the agent, and stops the proxy when it exits. One command, no exports, no /turo inside the agent. Supported: claude, codex, opencode, qwen, aider, crush, goose, amp.
turo -proxy — the proxy on its own
turo -proxy -upstream https://api.openai.com # listens on 127.0.0.1:8787 export OPENAI_BASE_URL=http://127.0.0.1:8787/v1
Every /chat/completions (and Anthropic /messages) request has its message content reduced before it reaches the real endpoint; the response streams back untouched. By default only user and tool content is reduced (system and assistant history are left verbatim, since they are lossier to touch) — pass -proxy-all to reduce every role. Auth headers pass through; non-chat paths are forwarded unchanged.
kdeps does not need this: in agent mode it already pipes the preamble, input, tool results, and history through turo before every call.
Integration
npx turo installs the binary and registers the turo skill + /turo command with every coding agent it finds on your machine — Claude Code, Gemini CLI, opencode, Codex, Cursor, Windsurf, Cline, Copilot, and 20+ more. Install once; every agent gets the same reducer.
npx turo # binary + register with detected agents npx turo --list # show every supported agent and its status npx turo --only claude # register with one agent npx turo --all # register with every supported agent npx turo --no-binary # register agents only (binary already installed) npx turo --uninstall # remove binary + registered skills
Under the hood each agent gets one of:
Claude Code / opencode — the skill and /turo command are copied into the agent's config dir
Gemini CLI — gemini extensions install
everything else — npx skills add kdeps/turo --skill turo -a
Once turo is on PATH, any agent can also pipe context through it directly:
cat CLAUDE.md | turo --preamble # compact system prompt cat error.log | turo # reduce log output
Set TURO_LEVEL=ultra for maximum compression. KDEPS_TURO=off or TURO_DISABLED=1 to disable.
What it does NOT touch
Code blocks and inline code — passed through unchanged
URLs, file paths, version numbers — v
[truncated for AI cost control]