lanlan / dev / architecture

What's actually under the hood.

You've read the pitch. You're here for receipts. This page is the receipts — the data model, the deploy pipeline, the protocol layer, and the answer to the question every other platform's architecture page ducks: what happens if we want to leave?

the primitives

Six things a Lanlan site is made of.

Files. Structured content. Form submissions. Live values. Page-level settings. Snapshots. Plus the brand guide that travels with all of them. Each is its own primitive with its own tools.

primitive what's stored how you reach it where it lives
files HTML, CSS, JS, images, fonts get_site_files, update_file, patch_file, edit_element object storage
collections structured content with editable schemas (blogs, team pages, portfolios) collection (action-based) a database
forms submissions to the site's contact forms form (action-based) a database
live_data single live JSON values per key (counters, statuses, totals) live_data (action-based) a database
page_settings per-page status, preview links, PWA toggle (the site password lives on the site, set with protect) page_settings (action-based) a database
snapshots the last 20 published versions, each restorable list_snapshots, restore_snapshot object storage
brand design tokens — colors, fonts, voice notes — at /_brand/brief.md design_consultation, get_design_brief object storage (markdown file)

Everything except the database tables is a file in object storage. The database holds metadata, schemas, and the things that need to be queryable.

the pipeline

What happens when you call update_file.

The walk from tool call to live URL. Sub-15-second deploys, end to end.

  1. 01

    tool call

    agent → mcp.lanlan.site

    Your agent serializes the call as JSON-RPC and sends it over Streamable HTTP. Single round-trip.

  2. 02

    validate & write

    MCP server → object storage

    Server checks auth and the site pin, runs path validation, and writes the new source bytes to object storage.

  3. 03

    deploy

    object storage → global CDN⁰

    The site is built into a new, immutable version — partials and collections resolved — and the live pointer flips to it atomically. Every published version is kept for restore. On a site set to publish manually, the new version waits as a draft until someone presses Publish (or calls publish_site).

  4. 04

    serve

    edge cache → live URL

    CDN edge invalidates, the new bytes serve. HTTPS automatic, no build step.

⁰ The CDN and object-storage stack are Cloudflare's. Happy to share specifics on a sales call — info@lanlan.site.

the protocol

How the agent and the server talk.

Streamable HTTP. JSON-RPC. No server-side state except the session and your default site pin. Everything else is one round-trip.

tool call — agent → server
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "patch_file",
    "arguments": {
      "site_id": "33b69e87-...",
      "path": "index.html",
      "patches": [{
        "find": "Welcome to my site",
        "replace": "Studio days. Wedding nights."
      }]
    }
  },
  "id": 47
}
response — server → agent
{
  "jsonrpc": "2.0",
  "result": {
    "content": [{
      "type": "text",
      "text": "{\"success\": true,
                \"patches_applied\": 1,
                \"deploy_id\": \"...\"}"
    }]
  },
  "id": 47
}
Stateful
The session (auth) and the default site pin from select_site.
Stateless
Every tool call carries everything it needs. You can drop and resume mid-session and lose nothing.
Transport
Streamable HTTP. Older MCP clients on stdio need a transport bridge — most are on HTTP now.
the escape hatches

Five questions every other platform ducks.

If you ever want to leave, here's exactly what that looks like. Answered honestly, including the question with the awkward answer.

Can I export my sites? Yes.

get_site_files returns every file. One bash loop and you have a folder of HTML/CSS/JS on your machine. No proprietary block model to translate. The bytes you wrote are the bytes you get back.

The shape of an export — this is pseudocode for now. A real REST export endpoint is on the way; today this runs through your MCP client.

# pseudocode — the MCP equivalent today, REST export coming
for path in $(lanlan list-files --site $SITE); do
  lanlan get-file --site $SITE --path $path \
    > "./export/$path"
done
Are the files mine? Yes.

They're HTML, CSS, JS, and your media in standard object storage. Same shape any static site host expects. Drop them on Vercel, Netlify, S3, your own server. They work.

Can I keep my domain? Yes — with one step.

A domain you bring stays at your registrar the whole time; to leave, point the DNS somewhere else. A domain you buy with register_domain is registered through our Cloudflare Registrar account (ICANN-accredited, WHOIS privacy on). To take it with you, unlock it and get its transfer code — dns_records with unlock and auth_code — then start the transfer at any registrar. We don't hold it hostage.

Can I self-host the engine? Not today, honestly.

The engine is small — a few thousand lines — but it's tied to Cloudflare's edge in ways that make a one-button self-host non-trivial. If you're a team with a strong reason to host it yourselves, write to us. We'll have a real conversation.

What if Lanlan goes away? You keep what you built.

Sites keep serving for the duration of the CDN cache. After that, you have your files (export above), your domains (transfer them out with their auth codes), your Stripe account (in your client's name), and your form submissions (export them via the dashboard). No platform can promise to exist forever. We can promise that the day we stop, you don't lose your work.

We want you to stay because the product is good, not because leaving is hard.

The receipts hold up. Want to build?

Two lines of config and you're connected to the engine.