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. Next.js 15 shell + PHP backend (Symfony) with magic-link auth, JWT sessions, AI chat with the Anthropic API, MCP tool providers for every primitive, asset library + compose-preview editor, Sites + Pages model with a render-runtime ECS service for the published frontend. Newest: the Sherpa autopilot (the chat drives the dashboard itself), a performance-review agent that drafts Radiant proposals from Pelorat reports, a Palver-backed Live Activity stream, and an admin waitlist queue + staff demo-tenant spin-up — plus proactive insights (Beth raises evidence-backed nudges on its own), in-dashboard Radiant proposal authoring (make a branch, AI-draft or hand-write, see the diff), and a sandbox toggle that flips the console into test mode. Newer still: the Explorer (a conversational onboarding flow that chats, provisions a tenant, then tours it), operator dashboards for the Media library and Sign envelopes, and a staff-only Engineering Handbook. Beth now defaults to Sonnet 4.6. Latest: operator auth moved to Mannix (password + MFA + passkeys, magic-link retired); a one-command demo-business seeder + bootstrap-dev that stand up four fully-populated verticals; and a page-builder Library (Templates / Widgets / Layouts / Themes) with a drag-and-drop layout canvas and live render-runtime preview. Newest: operator sessions are Valkey-backed, the MCP tools are auto-generated from the platform capability registry, and operator surfaces shipped for capability bindings and the needs ledger. Latest (June 6–11): multi-location businesses — business units with claim-sourced isolation, a team roster with hire / re-role / suspend / terminate, and per-operator console roles behind a platform PermissionGate; an "Open operator view" handoff that puts scoped operator tools (a POS widget, live tabs) on the tenant's own site; the Korell import wizard (or drag a data export onto Beth's chat); Mallow export & statement downloads; and Beth's capability coverage rebuilt in three waves after a 20-agent audit.

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 Valkey-backed; 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.
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 the Anthropic API. 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 and defaults to Sonnet 4.6.
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.
Media & Sign dashboards
Operator surfaces for the newest primitives, built on the same per-primitive client + dashboard pattern. The Media library uploads (browser → S3 presigned PUT, 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 ECS service behind an ALB with 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, or bootstrap-dev for a whole environment) 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 (Next.js, 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/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 via SES

# 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.