Last week I was watching an agent generate a perfectly ordinary CRUD controller in C#, and I caught myself counting the tokens it was spending. public async Task<ActionResult<Customer>>. [ApiController]. CancellationToken cancellationToken. var entity = await _db.Customers.FirstOrDefaultAsync(x => x.Id == id, cancellationToken); if (entity is null) return NotFound(); return Ok(entity);. Line after line of scaffolding the model has typed a million times, and will type a million more, and pay for every single one.
That is the thing nobody really talks about. The part we can actually shrink is not the thinking. It is the repeated boilerplate the model has to emit.
Output tokens are the bill, not input tokens
People hear "token cost" and reach for prompt caching. Fair instinct, but it only solves half the problem. Caching helps the input side, the giant system prompt and the files you keep resending. It does nothing for the output, and the output is where the cost starts to show up, because every generated token has to be produced and billed, and output tokens are usually the expensive side. (Inference cost is never only the output, the reasoning, the context size, the retries all count too. But the output is the part this particular tool can shrink.)
C# is unusually punishing here. It is a beautifully explicit language, which is great when a human reads it and expensive when a model has to keep emitting it. CancellationToken is one word to you and several tokens to a tokenizer. Multiply that by every method signature in a generated file, then by every file in a generated feature, then by every regeneration when the agent decides to redo the whole thing because you changed one route. The verbosity compounds.
I used to assume this just did not matter much. A few hundred extra tokens per file, who cares. Then I actually added it up across a week of heavy agent use and the number annoyed me enough to do something about it.
What Smoower.Minified actually is
Smoower.Minified is a collection of C# extension methods and type aliases that map to standard .NET and a few common libraries, but in a far more compact form. The whole point is to give a model fewer characters to emit for the same behavior.
The line I opened with, the find-or-404, becomes q.ok1(), which wraps "find one item or return a 404" on a query. According to the docs, that one swap saves around 17 tokens versus the long form. On its own, nothing. In dense CRUD and controller snippets the examples show much larger savings, sometimes close to half. Across a whole project the docs put it at 10 to 25 percent, which is the more honest number because most of a real codebase is not dense boilerplate.
A few of the moves:
s.nil()instead ofstring.IsNullOrWhiteSpace(s)CT ctinstead ofCancellationToken cancellationToken[API]instead of[ApiController]db.okNew(e)to fuse an Add, a SaveChanges, and a CreatedAtAction into one call
Here is the part that made me trust it. There is no source generator and no transpiler. The type aliases compile away to nothing. The small extension helpers do add method calls in your source, though in hot paths the JIT inlines a lot of them, so the runtime cost is usually noise. The important bit is that there is no clever build step someone has to debug at 2am. You are shipping ordinary C# that happens to be short.
The rule that keeps it sane
The thing I was most worried about was the obvious failure mode: a model gets handed a "write less" toolkit and starts compacting the stuff that must not change. Route templates. HTTP verbs. Status codes. DTO property names. Compress any of those and you have not saved tokens, you have shipped a bug.
Smoower's answer is a single rule it repeats everywhere: never compact the contract. Only the structural plumbing gets shortened, never the things your API actually promises to the outside world. That rule matters more than the aliases themselves. (Whether models reliably hold it under pressure is exactly the kind of thing version 0.1 is for finding out.)
How you actually use it
It is published as a set of modular NuGet packages, all at 0.1.0 right now, split so you only pull what you need: Smoower.Minified.Core, then AspNetCore, EFCore, Http, Redis, Logging, Validation, Json, Dapper. Add the package reference and the aliases light up.
The other half is telling your model the dialect exists, because none of this saves a token if the agent keeps writing long-form. For Claude there is a skill at .claude/skills/smoower-minified/. For GPT, Copilot, or Cursor there is a prompts/system-prompt.md you point the tool at. You are teaching the assistant a denser way to speak C#, then getting out of its way.
The measurements, by the way, use tiktoken's o200k_base as a stand-in for Claude's tokenizer. Not perfect, but a reasonable proxy, and the relative savings hold regardless of whose exact tokenizer you run.
This is 0.1, and it shows
I want to be straight about where this is. It is the first cut. The alias set is opinionated and incomplete, some of the names will not survive contact with real use, and there are whole corners of .NET it does not touch yet. I would not be shocked if a couple of the terser helpers turn out to hurt readability more than they help the token count, and those will get pulled.
What I am fairly sure about is the premise. Generated code has a verbosity tax, the tax is paid in the output tokens you buy, and .NET pays more of it than most. A compact dialect that keeps the same runtime behavior is a reasonable way to pay less of it.
More is coming. Next I want real before-and-after numbers on a few full repos rather than per-snippet estimates, and I want to see how badly the "never compact the contract" rule holds up when an agent is three tool calls deep and improvising. If you try it on something real, tell me where it breaks. That is the useful feedback at this stage, not whether you like the names.