The two planes
tenant-{orgId}).
You do not need to open inbound control-plane APIs — everything that drives
the agent arrives over its outbound Temporal connection.
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.
One exception. previewQueryWorkflow returns actual rows to the control
plane so the UI can render a tabular preview. It is bounded: SELECT/WITH
only, a single statement, a 100-row cap, per-cell text truncation, and value
sanitization. See Security → The preview-query exception
for the full constraints. Sync paths do not reuse this transport.
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 }. - Agent auth. Each agent deployment has its own sevvo deployment token; revoking it cuts off future bearer exchanges instantly.
Where the code lives
| Layer | Path |
|---|---|
| Web UI (TanStack Start + Vite) | apps/web/ |
| Control-plane backend | packages/db/convex/ |
| Agent (NestJS + Temporal worker) | apps/agent/ |
| Workflow definitions | apps/agent/src/workflows/ |
| Connector implementations | apps/agent/src/connectors/implementations/ |
| Canonical sync activities | apps/agent/src/canonical-sync/ |
| Shared UI components (shadcn) | packages/ui/ |
@temporalio/client or start workflows directly.