Caveman: Caveman-Speak That Grew Into a Token-Compression Engine

July 1, 2026

|repo-review

by Florian Narr

Caveman: Caveman-Speak That Grew Into a Token-Compression Engine

What it does

Caveman started as a joke: a Claude Code skill that makes your agent answer in clipped, low-token "caveman-speak" — "New object ref each render. Wrap in useMemo." instead of a paragraph explaining React re-renders. That skill is still there and it's MIT, one command (npx skills add JuliusBrussee/caveman), still funny. But the repo it lives in now is a 503-file Go monorepo with a compression engine, a local proxy, a browser automation layer, and a content-addressed recovery store. The meme is the marketing. The engine is the actual repo.

Why I starred it

The joke version only ever cut output tokens — what the agent says back to you. Everything the agent reads — tool schemas, file contents, command logs, chat history — went over the wire in full, every turn, regardless of how terse the reply was. Caveman 2 (the caveman claude / caveman wrap proxy) targets that instead: it sits between your agent and the provider API and structurally compresses what goes in, not what comes out. That's a much harder problem than trimming adjectives, and it's the part worth reading the source for.

How it works

The core is engine/compressors, a registry of per-content-type transforms behind one interface (engine/compressors/compressor.go:22):

type Compressor interface {
	ContentType() string
	SafetyClass() safety.Class
	Compress(input []byte) (out []byte, ok bool)
}

Default() at compressor.go:90 wires up fourteen of these — JSON, log, code, diff, search-result, text, HTML, tabular, config, tool-schema, TOON, accessibility-tree, repetition, terminal — and every one of them is required to be "fail-closed": on any parse ambiguity it returns ok=false and the caller forwards the original bytes unchanged. That contract is enforced by a safety-class ladder in engine/safety (S0 through S4), where S4 means "alters model-visible bytes, opt-in, must be reversible via CCR." No compressor gets to just decide it's fine to guess.

The code compressor (engine/compressors/code_cgo.go) is the one I spent the most time in. It's tree-sitter backed (Go, Python, JS/TS, Rust, Java, C, C++) and keeps imports, signatures, and type declarations while eliding function bodies to { /* caveman: body elided */ } or ... for Python. The interesting part isn't the elision, it's the validation gate at line 84:

// Byte-safe guarantee: the result must re-parse without error.
vroot, vtree, ok := parse(l, out)
if !ok {
	return nil, false
}
if vroot.HasError() {
	return nil, false
}
return out, true

It doesn't trust its own output. After stripping bodies it re-parses the elided source with the same grammar and bails if that fails. There's also isDirectiveComment (code_cgo.go:192), which refuses to strip //go:build, //go:embed, //go:linkname, //export, and TypeScript triple-slash directives even in comment-removal mode — because those comments carry build/linkage semantics that survive a re-parse but silently change behavior, exactly the class of bug a re-parse check can't catch. Someone got bitten by that once, or thought hard enough to avoid it.

When a compressor does run lossy (S4), the original bytes go into engine/ccr first — the "Caveman Context Recovery" store. It's content-addressed (sha256 of the original), so compressing the same payload twice yields the same handle and stores it once (engine/ccr/store.go:7). The agent gets a handle back and can call caveman_retrieve to pull the exact original if it needs to. SQLite on host platforms, an in-memory map under js/wasm since modernc.org/sqlite doesn't build there — same Store type, platform split at build time via store_sqlite.go / store_wasm.go.

The other piece worth naming is engine/contextwindow/contextwindow.go, a deterministic BM25 packer (k1=1.5, b=0.75) that scores candidate context items by relevance to a query, plus small recency-decay and error-signal boosts, and greedily fills a token budget in relevance order while returning selected items in original chronological order — so history stays readable even though selection wasn't. No embeddings, no network call, just Pack(query string, items []Item, opts Options) Result.

Using it

The skill install is trivial:

npx skills add JuliusBrussee/caveman
/caveman lite

The proxy is the more interesting surface:

npm install -g @caveman-ai/cli && caveman setup --install
caveman claude          # wraps Claude Code, routes traffic through the local proxy
caveman learn           # scans local session history, scores your setup, no account needed
caveman stats           # what caveman actually compressed, by content type

caveman learn is read-only and local — it reads your agent's on-disk history and reports a "Cave Score" plus ranked token sinks, each labeled safe fix, offload, habit, or load-bearing. caveman learn implement hands the plan to your own agent with a skill that requires a yes per diff and re-measures after applying it. That consent gate is the right call for something that's rewriting bytes your agent depends on.

Rough edges

The repo is honest about its own numbers in a way I don't see often — every benchmark claim is tagged inferred (locally estimated) or benchmark_counterfactual (a pinned, reproducible run), and verified is reserved for a paid cloud product that hasn't shipped yet. That's a good practice, but it also means most of the headline compression percentages in the README are self-reported estimates, not third-party audited numbers.

Sniffing language by byte substring (sniffLanguage in code_cgo.go:263, checking for "package " + "func " to guess Go, "def " + ":" for Python) is fragile in the abstract, but the design leans on the re-parse gate to catch mis-sniffs rather than trying to be a perfect detector — a reasonable tradeoff given the fallback is always "pass through unchanged," never "corrupt the output."

Scope is the real concern. What's pitched as "wrap your agent in one command" is backed by ten separate Go binaries (caveman-engine, caveman-proxy, caveman-mcp, caveman-browse, cavemem, cachebench, and more), a browser extension, a pixel-rendering subsystem that turns dense text into PNGs for vision models, and a licensing split (MIT skill, BSL-1.1 engine) that means the interesting compression logic isn't fully open source — it converts to Apache-2.0 on a 2030 date or four years after each version ships, whichever comes first. This has gone from a weekend joke to a platform play fast, and the 252 test files suggest the team knows it, but it's worth knowing what you're actually installing before you point caveman claude at a real session.

Bottom line

If you just want shorter agent replies, the MIT skill is a fun five-minute install. If you're actually trying to cut input-token spend on long agent sessions, the proxy's compressor registry and CCR-backed recovery store are a legitimately well-engineered answer to a real problem — read engine/compressors/code_cgo.go before you trust it with your codebase.

JuliusBrussee/caveman on GitHub
JuliusBrussee/caveman