The two planes
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
- The user signs in to the hosted sevvo console and selects an agent deployment with a customer-supplied data-plane URL.
- The browser resolves that URL over the customer’s network or VPN and calls the agent directly.
- The agent reaches the source from inside the customer environment and applies the operation’s query, row, timeout, and sanitization limits.
- 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
- 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.
- On a schedule (or when you click Run), a control-plane action starts a
Temporal workflow with opaque inputs:
orgId,connectionId,modelId,destinationId. - 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. - 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.
- 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 asname, 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 lifecycle — static, 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.
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.