Liminalis
Interfaces HTTP agent API
MCP server
webhooks
Tools11 over MCP
Developers

A knowledge backend other applications can actually call.

Everything the workspace does — retrieval, grounded chat with memory, document reads, proposals, generation, long-running jobs — is reachable over HTTP and over the Model Context Protocol. Access control, the retrieval barriers and the credit meter apply identically, because there is no path around them.

§ 01 the clean room
Enforced bythe build graph, not by convention
§ 01  The design constraint

The MCP server holds zero references to the application.

It talks to Liminalis over HTTP with an API key, exactly like any third party would. That isn't a guideline someone might quietly break under deadline pressure — the project simply has no reference to the server assemblies, so the compiler enforces it.

Consequence 01

It cannot bypass anything

Project access checks, the GM-only wall, the lens barrier and the credit meter all sit on the HTTP path. A tool server that can only speak HTTP inherits every one of them, permanently, without anyone having to remember to apply them.

Consequence 02

It doubles as the API's acceptance test

If the server can only speak HTTP, then every gap in the public API surfaces as “I can't implement this tool” during development — instead of being quietly papered over with a direct internal service call that no external caller could ever make.

Also stateless, deliberately

No repository, no cache, no vector service, no background work. Any persistence appearing inside the tool server is treated as a design bug rather than an optimisation.

§ 02 the surface
Self-describingthe lens descriptor is the tool catalogue
§ 02  What an agent can do

Eleven tools over MCP, and the HTTP API behind them.

Tool What it does
describe Self-description: the project's lenses, document types, sections, stages and commands. An agent discovers the domain rather than having it hardcoded.
outline The shape of the project — structure without pulling every document.
search Grounded retrieval over the corpus, through the same stack the workspace uses.
read_document A document, with truncation declared rather than silent.
lookup Resolve a name — title, slug or alias — to the thing it means.
propose_document Create a new document as a reviewable draft.
propose_edits Suggest anchored changes to an existing document.
apply_edits Apply them, given the scope to do so.
run_command Invoke a lens command — the same ones a user types in chat.
generate Run a generation stage from the lens's build plan.
job_status Poll long-running work.

The HTTP API additionally exposes chat and chat history, job submission and cancellation, and webhook subscriptions. Streaming chat is deliberately excluded from the tool surface.

The headline tool

An agent gets the memory loop for free

An agent holding one chat id inherits the entire rolling-summary memory system without implementing any part of it — retrieval, decay, summarization, the cached prefix, all of it. Verified with a deliberately anaphoric second turn that could only be answered by remembering the first, with cost reported per call.

Self-description

New domains need no client changes

Because one lens descriptor feeds the workspace, the agent API's describe, and the tool registration, a lens authored at runtime shows up to agents automatically. The domain is data on every consumer of it.

§ 03  Writing, and not writing

Agents propose. People decide.

Propose, don't write

Agent output lands in the draft queue marked as generated provenance. Direct write requires an explicit scope that is off by default.

Scopes only narrow

Effective permission is the minimum of the key's scope and the key owner's role on the project. A key can never grant more than the person who created it has.

Barriers before assembly

Access filtering happens before context is built. A prompt-injected agent cannot extract material that never entered its context in the first place.

No silent clipping

Matched spans are expanded in place; truncation is declared both in the text and as a structured field, with a token estimate. Retrieval that doesn't lie to you about what it showed you.

Webhooks with the boring parts done

Per-key subscriptions, an echo handshake, HMAC signatures the listener independently recomputes, per-key rate limiting, and an SSRF guard whose rejection classes — including the cloud metadata address — are covered by tests.

Thin payloads

A webhook says that something happened and what to fetch. It never carries a result body, so an event delivery is not an exfiltration channel.

§ 04 case study
ProductThe Familiar
UsesLiminalis headless — no workspace
§ 04  Case study

Liminalis already runs headless, behind an application that isn't the workspace.

The Familiar is a consumer product with its own WebGL client, its own interface and its own audience — a small creature that keeps you company while you write, built around journalling and collaborative fiction. It is not a Liminalis feature and it does not look remotely like a document workspace. Underneath, it is Liminalis: the document engine, the knowledge layer and retrieval are the backend, and nothing else is.

Structurally, one of its worlds is one Liminalis project. The corpus, chunking, extraction, the association graph, recall and generation all arrive with it. What the product added was domain vocabulary: two new document types for journal entries and vignettes, and a generation stage plan for writing them that delegates to the same runner the Novel lens uses for chapter outlines. That is the whole of the integration at the document layer.

Because it registers as a lens, the Liminalis workspace can already render its documents, sections and type pickers with no frontend work at all — the SPA builds those from the served lens descriptor. That view is used purely as an inspection and debugging surface onto a product whose real interface is something else entirely. It is the clearest demonstration available that the lens is a real abstraction rather than a naming convention.

Layer What the second product did
Corpus & retrieval Reused whole. A world is a project; documents, embeddings, the knowledge layer and recall came with it.
Domain vocabulary Added: two document types and a generation stage plan, declared on a new lens descriptor.
Accounts & access Reused whole — cookie sessions, Google and AT Protocol sign-in, project access control.
Metering Reused whole. Model spend for a creature is metered by the same ledger that meters a manuscript.
Background work Reused the worker shape, including the out-of-band steering pattern first built for the Pacing Watcher.
Inspection UI Came free, from lens registration alone.
Ephemeral state Deliberately not documents. The creature's short-lived state expires; the corpus is permanent. It got its own tables rather than being forced into a document model that would have had to learn how to forget.
One honest distinction

The Familiar is a first-party client. It calls the ordinary controllers, exactly as the workspace SPA does — not the agent API described above. That was a deliberate choice rather than a shortcut: the agent surface is propose-scoped and draft-mediated, which is the right shape for something reviewing a corpus on your behalf and the wrong shape for a live interactive loop where a creature has to respond now.

So treat it as proof that the platform boundary holds — one engine, two products, one of which never shows a document to a user — rather than as a reference implementation of the agent API. Both claims are worth making; only one of them is this one.

Good fits

What this is for

  • An application that needs grounded answers over a private corpus, without building a retrieval stack.
  • An agent that should read and propose changes to a body of documents under review rather than write to it directly.
  • A domain tool that wants the knowledge layer — entities, relations, facts, motifs, a reverse index — without deriving one.
  • A team wanting one metered, audited place where model spend against their corpus happens.
Open and honest

What isn't there yet

  • Search over the API runs at the deterministic assembly level; the higher fan-out thinking levels aren't exposed to it.
  • Idempotency exists for jobs, not beyond them.
  • Lens authoring over the agent API is deliberately out of scope.
  • Tool descriptions are compile-time, so they can't enumerate a project's lenses — callers are pointed at describe instead.