How it works

Smoower saves tokens in two ways: it collapses long identifiers that tokenize into several sub-tokens, and it fuses whole phrases of ceremony into a single call. Everything compiles to the same IL.

The bill nobody talks about

Here is a perfectly normal controller action. Count the ceremony:

[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
    var x = await _db.Users
        .AsNoTracking()
        .Where(u => u.Id == id)
        .Select(u => new { u.Id, u.Name, u.Email })
        .FirstOrDefaultAsync();
    return x == null ? NotFound() : Ok(x);
}

HttpGet, Task<IActionResult>, AsNoTracking, FirstOrDefaultAsync, NotFound, Ok — none of that is your logic. It is the framework tax, and your assistant pays it again in output tokens on every write, rewrite, and refactor.

The same action with Smoower.Minified:

[HG("{id}")]public Tr Get(int id)=>db.Users.nt().w(x=>x.Id==id).s(x=>new{x.Id,x.Name,x.Email}).ok1();

One line, same behaviour. ok1() runs the query and returns 200 with the row, or 404 if missing — the exact x == null ? NotFound() : Ok(x), folded into the call.

Where the savings come from

Two things do the work. First, collapsing long PascalCase identifiers that tokenize into three to five sub-tokens — FirstOrDefaultAsync, Task<IActionResult>, AddScoped — into short handles. Second, the result-fusing terminators that delete whole async/await/return/Ok phrases: q.ok1(), q.okl(), set.okId(id), db.okNew(e), db.delById<T>(id).

Dropping the long ...Async suffix is why async is the unmarked default and synchronous code takes the S suffix (saveS, idS) — the common path is the short one. Every mapping is listed on the Cheat sheet.

Still ordinary C#

The alias layer (L1) is plain C# extension methods, attributes, and type aliases — no transpiler, no source generator, the same IL the verbose form produces. You can step through it in a debugger like any other code. The opt-in [Crud<>] generator and the deeper compaction levels go further when you want them, always keeping the public contract intact.

Never compact the contract. Route templates, HTTP verbs, status codes, and DTO / JSON names stay exactly as your API requires. Shorten the code, not the contract.

Where to next