Skip to content
Getting started

How Nacre works

The mental model. There are two sides: the control plane (runs Nacre), and your agent environment (runs you). They talk to each other through a small set of signed endpoints.

Two planes, one agent

Every Nacre customer gets their own dedicated agent environment. That environment runs your OpenClaw instance and nothing else — fully isolated, no noisy neighbours.

Our control plane (the thing at nacre.sh) is the dashboard, billing, and the orchestrator that spawns, resizes, and retires VMs. It never reads your conversation content — just metadata (uptime, resource usage, OpenClaw version).

The control plane

Hosting
Next.js 14 on Vercel — marketing site, dashboard, API routes.
Database
Supabase Postgres with row-level security. Secrets encrypted with pgsodium.
Auth
Supabase Auth — email/password and Google OAuth.
Billing
Stripe Checkout + Customer Portal + webhook-driven lifecycle.
DNS & edge
Cloudflare. Each VM gets an A record at user-<id>.nacre.sh.
Offsite backups
Cloudflare R2 — a different cloud than your VM provider.

Your agent environment

When you pay, we provision a dedicated agent environment for your account — isolated from all other users. A single cloud-init script installs Docker and brings up four containers:

caddy:2-alpine
TLS termination via Let&apos;s Encrypt; routes /terminal and /ws to ttyd, everything else to OpenClaw.
openclaw
The AI assistant itself — pinned to a stable release tag.
ttyd
Web terminal. Only reachable via JWT-gated Caddy route.
oc-agent
Our Go binary. Heartbeats, command execution, backups. ~10 MB.

The /data volume holds your OpenClaw state — memory files, skills, conversation history, channel credentials. It is yours. We don't read it.

How the two planes talk

Three signed endpoints, all HTTPS, all on nacre.sh:

  • POST /api/internal/vm/:id/heartbeat — every 30 seconds, agent pushes CPU / RAM / disk / OpenClaw version.
  • POST /api/internal/vm/:id/ready — once, from cloud-init, when Docker Compose is up.
  • POST /api/internal/vm/:id/update-result — after an OpenClaw upgrade finishes, agent reports success or rollback.

Every request carries a per-VM HS256 JWT (scope: 'agent'). The control plane constant-time compares it against the copy it stored in pgsodium when the VM was provisioned.

The provisioning sequence

  1. Stripe webhook fires checkout.session.completed. We verify the signature and check idempotency against the event log.
  2. Subscription + VM rows are inserted in Postgres, state = creating.
  3. Provisioning job is enqueued — the Supabase edge function picks it up.
  4. Secrets are minted — agent JWT, ttyd password — and encrypted with pgsodium.
  5. Cloud API call — new agent environment provisioned in your region with a rendered cloud-init user-data payload.
  6. Cloudflare DNS — A record for your subdomain created as soon as we have an IP.
  7. First heartbeat — agent reports in; the VM row flips to ready; the welcome email goes out.
  8. You land on the dashboard — usually within a couple of minutes of payment.
Why dedicated agent environments?
We could pack customers onto shared containers and charge less. We don't, because a runaway loop, a kernel exploit, or a greedy neighbour all become someone else's problem when you have your own isolated environment. The price we pay for that guarantee is honest margin — see pricing.

What survives a disaster

Nightly, your agent tars /data, encrypts it with a per-customer key (HMAC-SHA256(platform_secret, user_id)), and pushes it to Cloudflare R2 — a different cloud provider than your agent environment runs on. If the primary provider loses your disk, we restore from R2 onto a fresh environment. Full DR runbook onsecurity@nacre.sh.