Liminalis
§ Lenses the product thesis
BuiltNovel · Campaign · Legislation
Plususer-authored vocabulary lenses
The lens

The same corpus, read three different ways.

Underneath every lens is one engine: typed markdown documents, a knowledge layer derived from them, and a retrieval stack that doesn't know or care what domain it is working in. The lens is what sits on top — and it changes almost everything a user sees.

§ 01 what a lens controls
§ 01  Definition

A lens is a descriptor, and the descriptor is data.

Not a fork, not a mode flag threaded through the codebase. A serializable object that the server hands to the client, to the agent API, and to the MCP server — one source of truth for what a domain is called and what it can do.

Vocabulary
Tree sections and document-type labels. The same underlying type is a “Thread” in the Novel lens and a “Quest” in the Campaign lens — one engine concept, two domain words.
Interface
The sidebar tree, type pickers, “add” and “upload as” menus and document-browser facets all render from the served descriptor rather than from a table baked into the client.
Generation stages
Staged, dependency-ordered build plans — each stage declaring what it depends on, so a builder can render itself and refuse to run out of order.
Commands
The chat command set, and the /help listing rendered from it.
Parameter forms
The guided pre-generation form — which also writes the prose of the Parameters document, so the form and the document can't drift.
Facets and metrics
Facets are what the document browser filters on. Metrics are what charts plot. Deliberately different lists: a number you can chart is not automatically a number you should filter by.
Retrieval barriers
Every document carries a lens setting, or is left unscoped. The barrier strips out-of-lens material before context assembly. It is generic — it supports twenty lenses with no code change.
And what a lens deliberately doesn't control

Personas, stage generation prompts, validation rubrics and genuinely domain-specific mechanics — dice, virtual-tabletop sync, the live-session orchestrator — live in code next to the thing they serve. “Entirely descriptor-driven” was considered and retired as the wrong bar: it would have turned prompts into configuration and made them harder to reason about, not easier. Knowing which half a thing belongs in is the actual design work.

§ 02 the proof
Bench deltazero — byte-identical token counts before and after
§ 02  Was it real?

The abstraction was tested by an outsider domain.

Any codebase can claim its abstraction is clean. The way to find out is to point it at something it was never designed for. After the lens was factored out, the next task was to build a third lens — not another flavour of fiction, but a corpus of roughly ten thousand pieces of US state legislation.

The seam held. No special case was needed in ingestion, chunking, extraction, retrieval, context assembly, the access barriers, the job model, the agent API or the MCP server. Two latent bugs surfaced that only a third lens could have revealed — including a reverse index whose axes were documented as descriptor-driven and quietly weren't.

Verified

Retrieval was provably untouched

After the refactor the 44-query retrieval bench returned average token and character counts identical to the digit against the pre-refactor baseline. Not “about the same” — the same numbers.

The real finding

The hard part wasn't the lens. It was scale.

Everything lens-shaped generalized on the first try. What broke was code that had quietly assumed a hand-curated project of a few hundred documents and met ten thousand. That's the honest lesson, and it's a more useful one.

§ 03  The three lenses

Same engine. Three problems.

Where lenses meet

One world, two ways of working in it

A document is scoped to a lens, or left unscoped and visible to all of them. That makes “novelize the campaign you ran” or “run a game in your novel's world” an actual workflow rather than a copy-paste job — shared world material stays visible to both sides while lens-specific planning stays out of the other's way.

User-authored lenses

Vocabulary without a deploy

A lens can be authored as JSON at runtime and composed into the same registry as the built-ins — so it appears in the workspace, in the agent API's self-description, and in the MCP server, for free. Deliberately limited to vocabulary: a user lens renames and reorganizes, it can't invent document types or generation stages.