Point more. Token less.
A real instruction block — 138 tokens (cl100k):
When you are reviewing a pull request, please make sure that you carefully
examine each of the changed files and verify that the new code does not
introduce any regressions in the existing behavior. It is really important that
you check whether the author has added appropriate tests for the new
functionality, because untested code is very likely to break in subtle ways that
are difficult to debug later. You should also confirm that the documentation has
been updated to reflect the changes, and that the commit messages clearly
explain what was changed and why. If you notice any potential security
vulnerabilities, such as unsanitized user input or hardcoded credentials, you
must flag them immediately and request changes before the pull request can be
merged.
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.
| 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 | |
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
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.
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.
| 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
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.
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 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 -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.
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 dirGemini CLI—gemini extensions install
everything else—npx skills add kdeps/turo --skill turo -a <profile>
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.
-
Code blocks and inline code — passed through unchanged
-
URLs, file paths, version numbers — verbatim
-
Technical terms (API names, CLI commands, error strings) — exact
-
Embedded English dictionary (120k words, 14MB) classifies every word
-
Strips articles, prepositions, conjunctions, pronouns (~70 stop words)
-
Keeps the content words for the level (nouns, verbs, adjectives)
-
Deduplicates and emits them in reading order — then keeps the result only if it is actually smaller than the input
caveman is a sibling idea with the opposite dial. caveman deletes filler with regex (articles, pleasantries, hedges) and keeps readable prose. turo runs that same filler pass, then keeps going — POS-classifying, deduplicating, lemmatizing, and swapping words for shorter synonyms and glosses — trading readability for a much smaller token count.
Same input, measured with the cl100k tokenizer:
| output | tokens | |
|---|---|---|
| input | Please, I think you should really just utilize this approach to demonstrate the functionality of the component. |
|
| 19 | ||
| caveman | You should utilize this approach to demonstrate functionality of component. |
|
| 11 | ||
| turo full | Use come show functionality component |
|
| 5 | ||
| turo ultra | Use come show component |
|
| 4 |
| caveman | turo | |
|---|---|---|
| method | regex filler removal | dict POS + dedup + lemma + synonyms + gloss |
| output | readable prose | keyword stream |
| dictionary / WordNet | no | yes |
| synonym / gloss swaps | no | yes (on by default) |
| best when | you still need to read it | you only feed it to an LLM |
Use caveman when a human reads the result; use turo when only a model does.
System prompts are 50-200k tokens. Most of those words carry grammar, not meaning. Turo points at what matters and drops the rest.
Point more. Token less.