LanternDocs

Deployment

Lantern splits into a control plane (scheduling, routing, dashboard) and a data plane (microVMs, execution, secrets). The data plane runs in your cloud — agent data never leaves your VPC.

In plain termsTwo halves: the control plane is the brain (dashboards, scheduling, budgets — it decides what should run), and the data plane is the muscle (where agent code actually executes, with your API keys and your data). The point of the split: you can keep the muscle inside your own cloud account, so prompts, credentials, and customer data never leave your infrastructure — while the brain is run for you as a service. Pick the mix that fits: fully managed, hybrid, or everything self-hosted.

Architecture — the CP/DP split

Lantern architecture: control plane orchestrates, data plane executes Channels and builders enter through two gateways. The Go control plane orchestrates and never touches user code; the data plane runs it behind a fail-closed isolation gate. Runtime scheduler places work, runtime-manager spawns it, and the in-VM harness enforces egress and secrets. The control plane orchestrates; the data plane runs your code Orchestration is Go and Rust services. Untrusted code only ever runs inside a microVM, on the data plane. Channels WhatsApp · iMessage · Slack · Discord · Telegram voice (Twilio, LiveKit) · webchat /widget.js · email Builders SDKs (TypeScript, Python, Go) · lantern CLI dashboard · A2A peers surface-gateway :8444 · Rust inbound webhooks · signature verification · normalization gateway :8443 TLS · Rust JWT / API-key auth · rate limiting · streaming Control plane: orchestration, never user code control-plane :8080 REST · :50051 gRPC · Go agents, runs, sessions, budgets (402) evals, receipts, memory, auth, RLS workflow-engine :50052 gRPC · Go durable steps, event-sourced journal authoritative for run state model-router :50053 gRPC · Rust model: "auto" resolved by capability 4 routing strategies · failover scheduler tz-aware cron memory people graph · pgvector notifier webhooks · email · Slack billing usage metering · rollups Postgres (tenant-fenced rows, RLS) · Redis (live events) · S3/MinIO (bundles, snapshots) Data plane: your cloud (EKS, GKE, AKS, laptop) gRPC · service token · metadata only runtime-scheduler :50055 · Go HA leader election · placement: warm pool, region, fair share, cost, health · quota (402/429) runtime-manager :50054 · Rust isolation gate fails closed: Firecracker, Kata, gVisor, Wasm pause, resume, fork, file API microVM (the glass) harness (Rust, PID 1) egress allowlist proxy (:3128) secrets socket with SO_PEERCRED tool runner: shell_exec, http_fetch Control plane Trusted host In-VM harness microVM wall Trust boundary
The full system: channels → gateways → control plane → your data plane. The control plane never runs user code.
Your cloud runs the code; the control plane only orchestrates A request passes four control-plane steps: authenticate, budget and quota, mint per-VM identity, dispatch over service-token gRPC. It crosses a metadata-only trust boundary to the data plane, where the runtime scheduler picks a node, runtime-manager spawns the workload and the harness inside the microVM runs it. Step events, journal and a signed receipt come back up. Your cloud runs the code; the control plane only orchestrates User code executes in the data plane. The control plane decides and records by metadata. Control plane (managed SaaS) 1 Authenticate JWT or API key · RBAC tenant_id on every row, span and gRPC call · RLS 2 Budget and quota Forecast, then hard-fail limits: over budget is 402 per-tenant VM quota (402/429) 3 Mint identity Per-VM certificate at spawn Secrets are lantern.secret refs, resolved at run time 4 Dispatch gRPC to the data plane, service-token authenticated tenant_id in call metadata Also here: workflow engine · model router · memory · evals · marketplace · notifier Postgres, Redis, S3 hold metadata, costs and journals Trust boundary: token-authenticated, metadata only Down: specs, secret refs, tenant_id. Up: heartbeats, step events, audit. mTLS is the planned hardening; the shared service token is the current gate. Data plane: your VPC (EKS, GKE, AKS, laptop) runtime-scheduler :50055 · Go HA leader election · placement: warm pool, region, fair share, cost, health · picks the node for the spec runtime-manager :50054 · Rust isolation gate fails closed: Firecracker, Kata, gVisor, Wasm snapshot, restore, warm pools microVM (the glass) harness (Rust, PID 1) egress allowlist proxy (:3128) secrets via SO_PEERCRED reports bound to the VM's own run Comes back up: step events to the journal, then the run waterfall and traces, then a signed, verifiable receipt. Control plane Trusted host In-VM harness microVM wall Trust boundary
What crosses the boundary: specs, identity, and trace context go down; heartbeats, step events, and audit come back. Token-authenticated (mTLS hardening planned) — prompts and data never leave your VPC.

Deployment options

Fully managed (Lantern Cloud)

Both planes hosted by Lantern. No infrastructure to manage. Everything runs on Lantern infrastructure.

Best for: getting started and workloads without strict data residency requirements.

Hybrid (recommended for production)

Control plane hosted by Lantern; data plane in your cloud. Agent data stays in your VPC.

  1. Deploy the data plane Helm chart into your cluster (see below).
  2. Register via POST /v1/data-planes or Settings → Data Planes. This mints a one-time 32-byte bootstrap token — store it immediately.
  3. The data plane dials out to :50051 (gRPC), sends the bootstrap token via Register RPC, and receives a short-lived session JWT (1 h TTL, auto-rotated via RefreshToken).
  4. The data plane opens a persistent RunStream bidi RPC. The control plane pushes run assignments; the agent reports status and completion back. Only run metadata crosses the boundary.

Tunnel RPCs

Defined in packages/proto/lantern/v1/dataplane.proto, served on the control plane's :50051 listener.

RPCDirectionPurpose
Registeragent → CPExchange bootstrap token for session JWT
Heartbeatagent → CPLiveness (every 30 s); learns drain orders
ReportMetricsagent → CPCPU / memory / active-run pressure (every 60 s)
RefreshTokenagent → CPRotate session JWT before 1 h expiry
RunStream (bidi)agent ↔ CPCP pushes assignments; agent reports accepted / completed
Per-tenant cap: up to LANTERN_DP_MAX_STREAMS_PER_TENANT concurrent RunStream connections (default 10). Excess connections return gRPC RESOURCE_EXHAUSTED.

Fully self-hosted

Both planes in your infrastructure. Full control, full responsibility.

Operational overhead: you manage Postgres, Redis, and Kubernetes. Ensure your team has the capacity before choosing this path.

Helm

The repo ships one chart, infra/helm/lantern, with values-dev.yaml, values-staging.yaml and values-prod.yaml. It deploys the gateway, control plane, model router, workflow engine, runtime manager, runtime scheduler, surface gateway and dashboard, with in-cluster Postgres and S3-compatible storage for development and a Redis subchart. The chart defaults LANTERN_ENV=production, so the production startup guards are on.

helm install lantern ./infra/helm/lantern \
  --namespace lantern --create-namespace \
  --values infra/helm/lantern/values-prod.yaml

Top-level values keys: global, gateway, controlPlane, modelRouter, workflowEngine, runtimeManager, runtimeScheduler, surfaceGateway, dashboard, postgresql, redis, minio, ingress, networkPolicy, backup, secrets, serviceAccount. There is no separate data-plane chart yet; for a data plane in another cloud, use the Terraform path below.

Production settings

  • Autoscaling and disruption — <component>.autoscaling.enabled adds a CPU-based HPA (needs metrics-server) for the control plane, gateway, model router, workflow engine and dashboard; values-prod.yaml turns it on. Components with more than one replica get a PodDisruptionBudget.
  • NetworkPolicy — networkPolicy.enabled=true denies all traffic in the release, then allows only the service-to-service flows the platform needs, DNS, and scrapes of /metrics from networkPolicy.metricsFrom. Only the control plane, model router, workflow engine, runtime scheduler, runtime manager, surface gateway and backup job may leave the cluster; use networkPolicy.extraEgress for managed Postgres or Redis on private IPs. Your CNI must enforce policy (Calico, Cilium).
  • Secrets you must supply — secrets.jwtSecret, credentialKey, receiptSecret, grpcServiceToken, schedulerNodeToken, appDbPassword, and with managed stores postgresPassword and minioPassword (the S3 secret key). The control plane also refuses to start in production without its gRPC TLS cert and the runtime-manager mTLS client cert; the chart cannot create these, so mount them with controlPlane.extraVolumes and extraEnv.
  • Backups — backup.enabled=true adds a CronJob that writes a gzipped pg_dump to s3://<backup.s3Bucket>/postgres/ and prunes dumps older than backup.retentionDays. Prove a dump restores with scripts/db-restore-drill.sh <dump.sql.gz>; see docs/runbooks/db-restore.md. This is a floor; managed Postgres with point-in-time recovery is the recommended production path.
Limits: the scheduler's readiness probe uses /healthz by default because /readyz stays unready until a runtime-manager node registers.

In-cluster dependencies (dev) vs managed (prod)

Lantern needs Postgres with the pgvector extension, an S3-compatible object store and Redis. The chart can run them for you, which is what you want on kind or a laptop, but production should use managed services.

Dev / kind / evaluation (default)Production (values-prod.yaml)
Postgrespostgresql.enabled=true: one pgvector/pgvector StatefulSet with a PVC. Password is secrets.postgresPassword.postgresql.enabled=false and externalDatabase.host (plus port, sslmode). User and database names still come from postgresql.auth. Provision pgvector and the lantern_app role yourself.
Object storeminio.enabled=true: one SeaweedFS StatefulSet with a PVC, one identity built from minio.auth.rootUser and secrets.minioPassword. Buckets in minio.defaultBuckets are created by a post-install Job.minio.enabled=false and externalS3.endpoint, accessKeyId, bucket and region (must match the bucket's region); the secret key is secrets.minioPassword.
RedisBitnami subchart (redis.enabled).Same subchart for now.

With the in-cluster stores off, helm template fails unless externalDatabase.host and externalS3.endpoint are set, so a production install cannot silently fall back to a single-pod database.

Dev stores are not production storage. They are single replicas with no replication, point-in-time recovery or lifecycle rules. Image tags are pinned in values.yaml (postgresql.image, minio.image). Earlier versions of the chart used Bitnami subcharts for Postgres and MinIO; those crash-looped on the pgvector image and their MinIO images are no longer published. The new Postgres and object-store StatefulSets keep the old names but use different selectors, which Kubernetes will not patch in place: to move an existing release, take a dump (docs/runbooks/db-restore.md), uninstall, install, and restore.

Terraform

lantern infra install --cloud aws|gcp|azure generates Terraform for a data-plane cluster. Flags include --tenant-id (required), --region, --cluster-name, --existing-cluster, --instance-type and --node-count. The modules live in infra/terraform/ and are not published to the Terraform Registry. Review the output, then apply.

lantern infra install --cloud aws --region us-east-1 --tenant-id <tenant-id>   # generates terraform/ in the current directory
cd terraform
terraform init
terraform plan
terraform apply

Namespace isolation

Each tenant gets its own Kubernetes namespace: lantern-t-<tenant_id>. Provides network isolation, per-tenant resource quotas, and separate service accounts and secrets.

Monitoring

Every service emits OTel traces tagged with tenant_id, run_id, step_id, and agent_version. Compatible with Grafana + Tempo, Datadog, New Relic, Jaeger, and any OTel backend. The control plane also serves Prometheus metrics at :8080/metrics (HTTP request duration by status, run totals, budget blocks), unauthenticated, so scrape it only from inside the cluster. Alert rules and Grafana dashboards live in infra/monitoring/; runbooks in docs/runbooks/. See Observability for details.

Database migrations

The control plane manages its Postgres schema via golang-migrate. Migrations are embedded SQL shipped inside the binary.

  • Fresh databases — migration 0001 creates the full schema on first boot.
  • Existing databases — 0001 is fully IF NOT EXISTS; running it records version 1 in schema_migrations with no DDL changes.
  • New changes — sequential pairs (0002_*.up.sql / 0002_*.down.sql). Down migrations required after the baseline.
Only the control plane runs migrations. Other services read and write tables but never apply schema changes.