Primitive spec

Demerzel

The operator console. Demerzel is the human (and AI) interface to every other primitive — operator sign-in through Mannix, an MCP tool registry over the full platform, a visual asset editor with in-editor AI chat, multi-page tenant-facing sites, and an admin grid for Trantor, Terminus, Seldon, Hardin, Hober, and Mallow.

Status: Live at latticekit.app — the operator console and control plane. Beth (the AI operator) with tool coverage across every primitive, conversational onboarding, a page-builder with live preview, multi-location business units with per-operator roles (deny-by-default on money and admin surfaces), staff act-as, and operator consoles for everything in the catalog — scheduling, purchasing, channels, cases, forms, loyalty, imports, and payroll included. Self-serve signup is open: anyone can describe their business at latticekit.app/start, see a preview of it, have a live demo of it built at its own address, and keep that demo as their business when they create an account (email proven, terms accepted, card on file where the platform asks for one). Account self-service: a tenant's own plan and card on file, and API keys for MCP clients.

What it owns

Demerzel owns the surface where humans and AI agents see and edit Foundation state. Operator sign-in (now a Mannix relying party), the operator dashboard, the asset-authoring workflow, the AI chat loop with platform-wide tool calls, and the tenant-facing rendered sites that read from Radiant ui_view assets all live here.

Demerzel does not own domain state. It calls every other primitive's REST API (and MCP tools that wrap them) to read and write — Radiant for asset versions, Terminus for people and consent, Seldon for offers and bookings, and so on. Operator changes go through the same APIs an external integration would use.

Concepts

Auth (Mannix relying party)
Operator authentication moved to Mannix in a clean cutover: the console verifies Mannix-issued RS256 tokens and operators sign in with a password (plus optional TOTP MFA and passkeys) instead of the old magic-link-only flow. An Account → Security nav surfaces passkey + MFA enrollment, and act-as is a Mannix-issued scoped token. The legacy User / AuthSession / self-service-magic-link path is retired. Operator sessions are held in a fast shared store; staff can manage operators and invite an email to an existing tenant.
Tenant + Invitation
A Demerzel Tenant ties an operator to a Foundation tenant id. Invitations are the on-ramp: someone on the waitlist gets an Invitation, and accepting it binds their Mannix principal to the tenant context. The waitlist endpoint accepts the form from latticekit.app/waitlist.
Signup
The pre-tenant record of a self-serve signup: the email is proven by a single-use link, a card is put on file through the processor's hosted page, and the terms are accepted with a version stamp — only then are the Tenant, its billing profile and the owner created, in one step. The front door is a platform switch, invite-only by default, that staff flip at runtime without a deploy.
Account + API keys
A tenant reads its own plan, status and card on file and updates the card through the same hosted flow. An owner mints an API key for an MCP client — shown once, scoped, with an expiry and a daily call cap — which is what connects that client to Gaal.
MCP tool registry
A registry of Model Context Protocol tool providers, one per primitive. Each provider exposes the primitive's primary write and query operations as named MCP tools (radiant_create_asset, terminus_search_persons, seldon_query_availability, …). The AI chat invokes them in a tool loop; operators get the same tools through the dashboard's command palette. Coverage spans the platform, and the tools are now auto-generated from the platform CapabilityRegistry through an MCP bridge rather than hand-written per primitive — the nine bespoke providers were retired onto it — with an exposure matrix gating which surface (customer, operator, staff, or AI) may call each capability. A 20-agent coverage audit then rebuilt Beth's primitive catalogue and exposed safe, non-sensitive reads across 18 primitives, so she can answer from live data nearly anywhere.
AI chat
Conversation + Message + ToolInvocation entities with a tool loop that calls a large language model. Conversation context probes tenant state, the user's current dashboard journey, and the open editor target to compose a system prompt. "Apply to editor" pipes a model proposal into the live ui_view being authored. The assistant presents as Beth in the console.
Explorer (conversational onboarding)
A guided first-run flow where Beth chats through what the business does, reads back the customer-facing details (subdomain, public URL, business + offer names) for explicit confirmation, then provisions the tenant from the captured blueprint and walks the operator through sandbox, branches + PRs, and experiments. Re-enterable any time from the side rail; an already-provisioned "Confirm & build" hands over to Beth's walkthrough rather than dead-ending. The build loop itself is now agentic: hard validation relaxed to integrity-only checks so Beth has design room, Beth triggers the build herself when the blueprint is ready, a second AI build critic confirms the design before provisioning, and a failed build routes back to Beth to fix and retry. She also recognizes stays / rentals / variable-length businesses and knows a duration from a cadence.
The front door: describe, preview, demo, keep
The public concierge at /start. Someone describes their business in a chat; the concierge asks what it still needs and drafts a preview — the offers, hours, resources, staff and prices it would be set up with — shown as a website in a browser frame. From there they can have a live demo built: a real business at its own address, bookable, in about a minute, from one of the ten starters. It winds down after a week, or, if they create an account, it is promoted in place — the demo becomes the business, nothing copied and nothing rebuilt. The same door is an MCP surface for an outside assistant: the concierge, the preview, the demo, the signup and the grant are tools on POST /agent/v1/signup (see the Agent API).
Media & Sign dashboards
Operator surfaces for the newest primitives, built on the same per-primitive client + dashboard pattern. The Media library uploads (browser → signed PUT straight to storage, never proxied), browses, copies URLs, and deletes; the Sign console composes envelopes from a Media PDF, tracks signers, and manages provider configs.
Engineering Handbook
A staff-only, codebase-derived handbook (every doc cites real file paths) rendered behind the staff gate at /dashboard/admin/handbook — a section sidebar over a frontmatter-driven tree, with internal cross-links routed through a slug reader so they never 404.
Library + Sites + Pages
LibraryService indexes the tenant's Radiant assets. The dashboard's Library tab is the asset browser; opening one lands in a compose-preview editor with the in-editor chat. Site + Page entities compose ui_view assets into multi-page tenant-facing surfaces, published via PublishedSite entries.
Render runtime
Tenant-facing pages are served by a separate render runtime behind wildcard DNS. The runtime fetches the PublishedSite graph, resolves each Page's ui_view via Radiant, and SSRs the result with a built-in component catalog and server-side ${binding.…} resolution + data-loader. Beyond the layout primitives it now ships data-bound components — booking_calendar (live Seldon surface), menu (live Hardin menu), and a no-JS disclosure — and evaluates if conditions as CEL. Operator authoring (Demerzel) and end-user rendering (render-runtime) are deliberately separate processes.
Demo businesses & dogfooding
One command (seed-demo-business) provisions four fully-populated verticals — salon, restaurant, fitness, courier — at stable subdomains, marked isDemo. A shared ActivitySeeder drives synthetic customers through the full Seldon lifecycle into Mallow invoices + double-entry ledger, MOCK-processor Payments, and consent-gated Speaker comms, so every real pipeline runs end-to-end (a seeded salon tenant lands ~880 bookings / ~477 paid invoices). A SiteBuilder gives each demo business a real customer-facing home page — theme, hero, hours, and a live booking widget bound to its provisioned offer.
Page builder & layouts
The Library is split into Templates / Widgets / Layouts / Themes, with a drag-and-drop canvas that composes Radiant view_ref layouts from picked widgets, browse / Use / Fork over the platform template library, and a preview rendered by the real render-runtime. "Save as template" promotes a plain view into a parameterizable template, a reverse "used-by" lists the layouts that embed a widget, and CLI equivalents (compose-layout, attach-page) script the same operations.
Capability console & needs ledger
Two operator surfaces over the newest platform plumbing. A staff capability console browses every registered capability; a tenant binding authoring UI wires an event straight to an outcome (the Daneel event→outcome bindings) with no workflow to write. And a needs-ledger view collects deferred obligations — approvals to grant, payments still pending, obligations outstanding — with the scheduled-timer and compensation history visible alongside.
Business units, team & roles
Multi-location support. Admins manage business units (CRUD over settings.businessUnits) with a per-location activity breakdown, and hire from /dashboard/team — the roster drives the Terminus employee provisioner (hire / re-role / suspend / terminate). Underneath sits the platform role/permission keystone: per-operator console roles ride on the Mannix token, a PermissionGate wraps operator and per-location admin surfaces, and a SubTenantQueryScoper confines a location-scoped operator's Person / Booking / Order / Invoice / subscription reads to their unit — sourced from the verified token claim, not a header.
Operator view on the public site
An "Open operator view" button hands a console operator over to the tenant's own rendered site with a revocable render session (and an explicit exit). The render-runtime enforces server-side, view-level gating behind an airtight operator-mode boundary — public visitors and operators are split at the origin — and operator-gated components light up in place: a POS widget (a pos ui_view component scoped to the RENDER_OPERATOR front-end class) and a live_tabs widget fed by Palver-pushed reads over an operator realtime token.
Data import & export
The operator on-ramp to Korell: an import wizard with upload, AI-proposed per-file targets + mappings (editable), dry-run preview, and an inline run-in-chat card — or drag a data export straight onto Beth's chat and she proposes the plan. The export side is the Mallow export & statements UI: CSV, QBO journal, and PDF statement downloads behind per-capability gating.
Admin grids
Per-primitive table-style UIs for Trantor, Terminus, Seldon, Hardin, Hober, Mallow. Generated against the same DTOs the REST endpoints return; PATCH editor with echoed values on validation failure, schema visibility, and a JSON view per row.
Tenant admin, act-as & demo tenants
Staff can act as a tenant to debug or support it — a scoped, audited, time-boxed session (60-minute default, 240 max) carried on an opaque cookie and gated by a real JWT-backed staff check. It does not bypass Terminus consent or tenant policy. Staff can also spin up a throwaway demo tenant (demo-… slug, 7-day TTL) and drop straight into it over the same act-as path. The admin surface includes a waitlist queue with status and free-text (?q=) search.
Sherpa autopilot
The AI chat can drive the dashboard, not just describe it. A browser-tool transport (WebMCP) advertises UI tools — ui_list_forms, ui_open_form, ui_fill_form, ui_submit_form, ui_navigate — to the model as native tool calls; the panel executes them and returns results. Three modes set how much autonomy it gets: Manual (confirm each step), Auto (fill and navigate, pause before submit), and On-rails (hands-off). The console's existing forms are wired to useSherpaForm, so Beth drives the real form — same validation, same submit path — rather than a parallel API.
Performance-review agent
An on-demand or scheduled agent that reads recent Pelorat report runs, summarizes them to the model, and opens DRAFT Radiant proposals (authorKind=AI) for the opportunities it finds. A PerformanceReviewRun records the summary and the proposal ids; nothing applies until a human approves it on the standard review surface.
Live Activity
A dashboard page that subscribes to Palver with the Centrifuge client and renders the tenant's real-time event stream — bookings, orders, invoices, and the rest — as they happen.
Proactive insights & the feedback loop
Beth doesn't only answer — it raises evidence-backed nudges from what it notices in a tenant's data. Operator feedback is captured as signals and clustered into Signal Themes, a ranked backlog the LatticeKit team works from, and a failure console pulls CI, nightly-tester, and production HealthSignals into one dashboard so a regression surfaces in a single place instead of scattered logs.

API surface

Demerzel exposes both browser-facing routes (under /dashboard/…) and server-facing endpoints versioned under /demerzel/v1/. The headline ones:

Demerzel endpoints in the Foundation API reference OpenAPI 3.1 schema for Demerzel with request/response shapes, parameters, and a try-it client.
MethodPathPurpose
POST/demerzel/v1/waitlistAccept a waitlist signup. Validates, stores, and acknowledges.
GET/demerzel/v1/waitlist?status=&q=List and filter the waitlist queue by status or free-text search (staff).
POST/demerzel/v1/invitationsIssue an invitation for a waitlist entry; triggers magic-link email via Speaker.
GET/accept?token=…Route handler that exchanges a magic-link token for a JWT cookie.
GET/demerzel/v1/signup/modeWhether the front door is invite-only or self-serve. Public.
POST/demerzel/v1/signupStart a self-serve signup (business name, address, email) and send the verification link. 403 while the door is invite-only.
POST/demerzel/v1/signup/verifyRedeem the emailed link; returns the continuation the later steps present.
POST/demerzel/v1/signup/{id}/payment-methodBegin the processor-hosted card step; the browser is sent to the processor and back.
POST/demerzel/v1/signup/{id}/completeConfirm the card session and create the Tenant, its billing profile and the owner in one step; signs the browser in.
GET / POST/demerzel/v1/account/billing[/payment-method]The tenant's own plan, status and card on file; start and confirm an update of the card.
POST/agent/v1/signupPre-tenant MCP endpoint: an AI assistant starts a signup for a person and, once the business exists, claims a scoped connection to it. See the Agent API.
GET / POST/demerzel/v1/agent-grantsList the tenant's agent grants; mint an API-key grant for an MCP client (the key is shown once).
GET/demerzel/v1/meCurrent user + tenant context.
POST/demerzel/v1/conversationsOpen a new AI chat conversation.
POST/demerzel/v1/conversations/{id}/messagesAppend a message; the tool loop fires automatically.
GET/demerzel/v1/mcp/toolsList registered MCP tools (introspection + AI chat input).
POST/demerzel/v1/mcp/tools/{name}/invokeServer-to-server invoke of a registered tool.
POST / GET/demerzel/v1/sitesCreate + list tenant Sites.
POST / GET / PATCH/demerzel/v1/sites/{id}/pagesManage Pages on a Site.
POST/demerzel/v1/sites/{id}/publishSnapshot a Site to a PublishedSite; the render-runtime serves from there.

Example: invite from the waitlist

An operator pulls a waitlist entry into an invitation; Speaker sends the magic link; the invitee accepts and lands in the dashboard.

POST /demerzel/v1/invitations
Content-Type: application/json
Authorization: Bearer <operator-jwt>

{
  "waitlistEntryId": "wl_01JAZB…",
  "tenantId":        "t_01J8K2…",
  "role":            "operator"
}
→ 201 Created  Invitation  inv_01JAZC…
   Speaker queues the invitation email to the invitee

# Invitee accepts, sets a password, and signs in through Mannix
GET /accept?token=eyJ…
→ 302 /dashboard
   Set-Cookie: LK_SESSION=<mannix-issued>

How it fits with the rest

flowchart LR
  Op[Operator / AI agent] --> De(Demerzel)
  De -- MCP tools --> R[Radiant]
  De -- MCP tools --> S[Seldon]
  De -- MCP tools --> T[Trantor]
  De -- MCP tools --> Te[Terminus]
  De -- invitation email --> Sp[Speaker]
  De -- publish --> RR[Render runtime]
  RR -- resolve ui_view --> R
            

Demerzel calls every primitive's REST API, packaged as MCP tools so an AI agent can compose them. Outbound auth email goes through Speaker (the sign-in path is a recorded exception to the consent gate; everything else respects it). Published tenant sites live in Radiant as ui_view assets and are SSR'd by the render-runtime — Demerzel doesn't render end-user pages itself.