Caveman 1.0.3
dotnet add package Caveman --version 1.0.3
NuGet\Install-Package Caveman -Version 1.0.3
<PackageReference Include="Caveman" Version="1.0.3" />
<PackageVersion Include="Caveman" Version="1.0.3" />
<PackageReference Include="Caveman" />
paket add Caveman --version 1.0.3
#r "nuget: Caveman, 1.0.3"
#:package Caveman@1.0.3
#addin nuget:?package=Caveman&version=1.0.3
#tool nuget:?package=Caveman&version=1.0.3
𦴠Caveman β Prompt Compressor for LLMs
<img width="1197" height="766" alt="caveman_splash" src="https://github.com/user-attachments/assets/4b534140-c519-423f-b918-e705565a039f" />
Caveman is a self-contained C# library that drastically reduces the number of tokens in your LLM prompts (Gemma 3, Llama, GPT-4, β¦). It strips grammatical "noise" (articles, prepositions, conjunctions, auxiliaries) and normalises inflected words to their base form, keeping the semantic payload intact.
"Why use many tokens when few tokens do trick?" β A caveman (and your wallet).
It is inspired by the token-saving idea behind the Caveman plugin for Claude, but it is an independent implementation written from scratch β no porting and no runtime NLP-model dependency.
β¨ Highlights
- Up to 70% token reduction β slash API costs and speed up local inference.
- 50+ languages out of the box β language data is embedded in the assembly; nothing to download at runtime.
- No heavy NLP runtime β pure lookup + heuristics over per-language word data. The only package dependency is
Microsoft.SemanticKernel(for the optional plugins). - Three compression levels β
Light,Semantic,Aggressive. - Fast language detection β a streaming parser reads only the stop-word section of each language to identify the input.
- Batch & custom filters β
CompressBatchAsync()and user-defined POS-style filters. - Semantic Kernel plugins + a suite of developer services (commit/review/stats/safety/wiki).
π οΈ Installation
dotnet add package Caveman
That's it β all language data ships inside the package. There are no models to install.
Quick start
using caveman.core;
var compressor = new CavemanCompressionService();
string input = "I would like to know if it is possible to receive information about cheap restaurants in Rome.";
var result = await compressor.CompressAsync(input, CavemanCompressionLevel.Semantic);
Console.WriteLine($"Compressed: {result.CompressedText}");
Console.WriteLine($"Efficiency: {result.EfficiencyPercentage:F1}%");
Console.WriteLine($"πΏ Energy saved: {result.EstimatedEnergySavedMWh:F3} mWh");
The input language is detected automatically; you can also call ApplyCompression(text, iso3, level) to force a specific language (ISO 639-3 code).
π Language detection (standalone)
You don't need to compress anything to use Caveman's language detector β it works on its own across all 50+ supported languages, with no model download:
var caveman = new CavemanCompressionService();
string iso3 = caveman.DetectLanguage("Vorrei un tavolo per due persone, per favore.");
// -> "ita"
// or get confidence scores per language (ISO 639-3 -> ratio of matched stop words)
var scores = caveman.DetectLanguageScores("Where is the nearest train station?");
// -> { "eng": 0.42, ... }
The detector is also usable directly via CavemanLanguageDetector if you don't want the compression service:
var detector = new CavemanLanguageDetector();
string iso3 = detector.Detect("Ich hΓ€tte gerne einen Kaffee."); // -> "deu"
Detection is backed by a tiny embedded stop-word index, so it stays fast even though it scores every supported language.
π Compression levels
| Level | Applied logic | What is kept | Typical savings |
|---|---|---|---|
| Light | Stop-word removal | Everything except function words & punctuation | ~25β30% |
| Semantic | Content selection + lemmatization | Content words, normalised to their base form | ~50% |
| Aggressive | Lemmatization + generic/descriptive pruning | Core nouns/verbs in base form | ~70% |
Example
| State | Prompt | Size |
|---|---|---|
| Original | "I would like to know if it is possible to have a margherita pizza immediately." | 100% |
| Light | "like know possible have margherita pizza immediately" | ~70% |
| Semantic | "know possible have margherita pizza immediately" | ~55% |
| Aggressive | "know possible margherita pizza" | ~40% |
π How it works
Caveman does not load any NLP model at runtime. Each language is described by a worddata/<iso3>.yaml source file with four sections:
function_wordsβ stop words, used both for compression and for language detection.lemmasβinflected form β base formmap (e.g.studying β study,gatti β gatto).verbsβbase verb β [conjugated forms]; folded into the lemma map at load time so every conjugation collapses to its base.proper_nounsβ a name gazetteer; capitalized tokens in it are kept verbatim (so names likeTerminiorMΓΌnchenare never compressed).
For shipping, these YAML sources are compiled (by scripts/compile-worddata) into compact embedded artifacts and a custom streaming parser keeps loading fast:
- Detection reads a tiny brotli-compressed index (
_index.br) holding only the stop words of every language, and scores the input by stop-word frequency β the large per-language data is never touched. - Compression then loads the one detected language from its brotli blob (
<iso3>.yaml.br), decompresses + parses it once, caches it, and applies the selected level.
This keeps the assembly small (~13 MB instead of ~68 MB of raw text) while loading only the language actually used.
Function words are dropped by their surface form before lemmatization, so a noisy lemma can never reinject a stop word.
Language data & provenance
The lemmas and verbs data are generated from the Universal Dependencies treebanks via scripts/import-ud-lemmas. Languages with little inflection (Chinese, Vietnamese, Thai, β¦) intentionally carry few or no lemma entries. See NOTICE for per-language attribution.
π Batch compression & custom filters
Batch β compress many prompts in one call:
string[] prompts =
{
"I would like to know about cheap restaurants in Rome.",
"Tell me how to get to the Colosseum from Termini station."
};
var results = await compressor.CompressBatchAsync(prompts, CavemanCompressionLevel.Semantic);
foreach (var r in results)
Console.WriteLine($"{r.CompressedText} (error: {r.ErrorMessage ?? "none"})");
Custom filters β override the default rules:
var filter = new CompressionFilter
{
KeepOnly = new HashSet<string> { "CONTENT", "PROPN" }, // keep content words & proper nouns
CustomPredicate = token => token.Length > 2 // skip very short tokens
};
var result = await compressor.CompressAsync(input, CavemanCompressionLevel.None, filter);
You can also blacklist categories with Remove (e.g. "FUNC", "PUNCT").
πΏ Sustainability
Every token processed by an LLM has an energy cost. Caveman exposes a built-in estimator:
- Energy saved: ~0.005 mWh (5 Β΅Wh) per saved token.
- COβ avoided: ~0.4 mg per mWh saved.
Compressing a prompt from 1000 β 400 tokens saves ~3 mWh and avoids ~1.2 mg COβ. At scale, that adds up.
π Semantic Kernel integration
var builder = Kernel.CreateBuilder();
builder.Plugins.AddFromType<TokenOptimizerPlugin>();
var kernel = builder.Build();
var result = await kernel.InvokeAsync<CompressionResult>("TokenOptimizer", "OptimizePrompt", new()
{
["input"] = "I would like to know if it's possible to get pizza near Rome.",
["level"] = 2 // Semantic
});
TokenOptimizerPluginβ prompt compression as a kernel function.CavemanWikiPluginβ on-demand, token-optimized project documentation (generate_project_wiki,get_project_summary,detect_project_type).CavemanServicesPluginβ exposes the developer services below.
𦴠Caveman services (developer toolkit)
| Service | What it does |
|---|---|
CavemanContextCompressor |
Compresses context files (CLAUDE.md, notes) into caveman-speak. |
CavemanCommitGenerator |
Conventional commit messages from a git diff, under 50 chars. |
CavemanReviewService |
Single-line PR review comments from a diff. |
CavemanStatsTracker |
Tracks token & cost savings across sessions (persists to %LOCALAPPDATA%/Caveman). |
CavemanSafetyGuard |
Auto-disables compression for security-critical/destructive content. |
CavecrewService |
Micro-agents: investigator / builder / reviewer. |
CavemanWiki |
AI-friendly, semantically compressed project documentation. |
var wiki = new CavemanWiki();
string context = await wiki.GenerateAsync(@"C:\Dev\MyProject");
await File.WriteAllTextAsync("AI_CONTEXT.md", context);
π License & attribution
Caveman is released under the Caveman License β the MIT License plus one mandatory condition:
Any use of this library must clearly and visibly disclose that it uses "Caveman" by Passaro Francesco Paolo (Digitalsolutions.it).
A disclosure such as the following, in your docs, an About/credits screen, or your repository, satisfies the requirement:
Powered by Caveman β Β© Passaro Francesco Paolo, Digitalsolutions.it (https://digitalsolutions.it)
See LICENSE for the full terms.
Bundled language data under worddata/ is derived from the Universal Dependencies treebanks and is provided under their respective licenses (predominantly CC BY-SA / CC BY), not under the Caveman software license. See NOTICE for attribution and source treebanks.
π€ Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
To regenerate the language data from Universal Dependencies and recompile the embedded artifacts:
# 1. import lemmas / verbs / proper nouns into worddata/*.yaml (the source)
dotnet run --project scripts/import-ud-lemmas -- --all # all languages
dotnet run --project scripts/import-ud-lemmas -- ita fra # specific languages
# 2. compile worddata/*.yaml -> worddata/*.yaml.br + worddata/_index.br (embedded)
dotnet run --project scripts/compile-worddata
# 3. rebuild the package so it embeds the fresh artifacts
dotnet pack caveman.core.csproj -c Release
Β© 2026 Passaro Francesco Paolo β Digitalsolutions.it
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.SemanticKernel (>= 1.74.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.0.3: Self-contained engine (no Catalyst/YamlDotNet at runtime). Lemmas, verb forms and a proper-noun gazetteer for 50+ languages imported from Universal Dependencies; verbs drive compression and names are kept verbatim. Language data compiled to brotli artifacts (~13 MB assembly vs ~68 MB) with a compact detection index. Licensed under the Caveman License (MIT + mandatory attribution); bundled data under Universal Dependencies terms (see NOTICE).