Skip to main content
sevvo is a hybrid SaaS. The control plane lives in our environment and handles orchestration; the data plane lives in yours and handles data. The boundary between them is a real boundary — see Security for the guarantees it enforces.

The two planes

Control plane. Pipeline definitions, schedules, run metadata, schema fingerprints, connection metadata, and the UI. Runs in our environment, backed by sevvo’s control-plane services and a self-hosted Temporal cluster. Uses sevvo’s authentication service for user and agent auth, and Autumn for billing. It serves the console application but does not proxy requests to the customer’s data-plane URL. Browser path. A user loads the hosted console, supplies the HTTPS URL for their agent deployment, and connects to it directly from their browser. The URL may be reachable only from the customer’s VPN. Interactive previews, connection tests, AI chat streams, and artifact downloads use this path and do not pass through the control plane. Data plane. One agent container per customer, running inside the customer’s network. Handles extraction, canonical transformation, storage, runtime credential use, and the browser-facing data-plane API. Connects outbound to the control plane over TLS on port 443. The agent is a Temporal worker first. It connects outbound to our Temporal frontend and polls a tenant-scoped task queue (tenant-{orgId}). The sevvo control plane never opens an inbound connection to the agent. Interactive console features are different: the user’s browser must be able to reach the customer-supplied data-plane URL over the customer’s network.

How an interactive console request runs

  1. The user signs in to the hosted sevvo console and selects an agent deployment with a customer-supplied data-plane URL.
  2. The browser resolves that URL over the customer’s network or VPN and calls the agent directly.
  3. The agent reaches the source from inside the customer environment and applies the operation’s query, row, timeout, and sanitization limits.
  4. The agent returns the result directly to the browser. Convex, Temporal, and sevvo’s other control-plane services do not receive the result payload.

How a pipeline runs

  1. You define a connection, a canonical model, and a destination in the UI. The UI writes to the sevvo control plane; it stores only identifiers and non-secret metadata.
  2. On a schedule (or when you click Run), a control-plane action starts a Temporal workflow with opaque inputs: orgId, connectionId, modelId, destinationId.
  3. Your agent’s Temporal worker picks up the workflow from tenant-{orgId}. The agent resolves identifiers to runtime config locally — credentials, DSNs, and OAuth tokens never travel in workflow inputs.
  4. Workflow activities run inside the agent: Retrieve → Refresh → Build model → Resolve associations → Load. Each activity returns metadata only — row counts, byte counts, durations, schema fingerprints — never source rows.
  5. The agent writes canonical output to your own sink (S3, warehouse, Postgres). The control plane receives a summary metadata payload and surfaces it in the UI.

Agent-local state

The agent uses local Postgres through Prisma for data-plane state that should not live in the control plane. AI analyst threads, messages, sandbox state, and artifacts are stored there so prompts, responses, tool output, and generated files remain inside the data plane. Connector credentials follow the current connector-specific runtime path: native database credentials are resolved by the agent from the control plane when needed, and OAuth-backed connectors resolve provider tokens through Pipedream. User-facing control-plane connection queries still return only metadata such as name, type, status, and safeMetadata.

Connector and auth are separate concerns

v1 only ships a Postgres + username/password connector, but the internal model keeps the connector and its auth strategy independent. A single connector (Postgres, Snowflake, Salesforce) can eventually support multiple auth strategies (username_password, keypair, oauth2_auth_code, oauth2_client_credentials) without becoming a special case. Credentials carry a lifecyclestatic, refreshable, exchangeable, or ambient — and refreshable lifecycles will be handled by shared auth drivers in the data plane rather than duplicated across connectors. This split exists to keep future connectors small. If you’re evaluating sevvo against systems that mix auth into each provider driver, this is the core structural difference.

The data boundary

Every Temporal activity return type is a metadata shape — row counts, byte counts, durations, schema fingerprints, opaque references into customer storage. Activities never return raw rows, secrets, tokens, or PII to the control plane. Whatever an activity returns ends up in Temporal history and is visible to the control plane, so the return type is the contract. The same rule applies to orchestration inputs. Control-plane workflow inputs contain identifiers (orgId, connectionId, sourceConfigId, modelId, destinationId) — not DSNs, OAuth tokens, passwords, refresh tokens, or embedded cursor payloads. Browser-direct previews. A user-triggered preview may return bounded rows from the agent directly to the user’s browser so the UI can render a table. Those rows do not travel through Temporal or the control plane. The agent allows SELECT/WITH only, rejects multiple statements, caps rows at 100, truncates cell text, and sanitizes values. See Security → Browser-direct preview queries for the full constraints. Sync paths remain metadata-only.

Versioning and upgrades

Customer agents lag behind control-plane deploys, so the workflow interface is treated as a versioned public API:
  • Inputs are append-only. New fields on a workflow input are optional. Renames, retypes, and deletes require a new workflow type.
  • Workflow logic changes use Temporal’s patched() so in-flight histories replay safely after an agent upgrade.
  • New capabilities = new workflow types, not mutations of existing ones.
Control-plane upgrades do not push code to your agent. The agent runs the workflow definitions baked into its image; to pick up a new capability, you pull a new image tag. In-flight executions replay safely across versions.

Tenancy boundaries

  • Deployment boundary. One agent per tenant, running in the tenant’s own environment.
  • Task-queue boundary. Workflows are routed by a tenant-scoped Temporal task queue; workers only pick up work for their own tenant.
  • Auth boundary. Every user-facing control-plane operation is scoped by a signed session that resolves { orgId, userId }.
  • Network boundary. The customer controls which user networks can reach the data-plane URL. A private VPN hostname does not need to resolve from sevvo’s network.
  • Agent auth. Each agent deployment has its own sevvo deployment token; revoking it cuts off future bearer exchanges instantly.

Where the code lives

Workflow definitions live in the agent repo, not a shared package. Only the customer-hosted agent connects to Temporal; Convex/control-plane code must not import @temporalio/client or start workflows directly.