Skip to main content

Domain model

The Autonomous Inbox data model has nine first-class resources plus a few internal tables (revoked tokens, revoked client certs). Everything is multi-tenant by Workspace — every row hangs off exactly one workspace, and every API request is automatically scoped to the workspace derived from the JWT sub claim.

Relationship diagram​

Workspace
│
┌───────────┬─────────┼─────────┬───────────┐
▼ ▼ ▼ ▼ ▼
Inbox Email Agent Webhook SystemEvent
│ │ │ │
│ │ │ └── WebhookDelivery
│ │ │
│ └── AgentRun ──┘
│
└── (optional bound Agent)

Resources at a glance​

ResourcePurposeLifecycle
WorkspaceMulti-tenant root, mirrors a Kobana accountCreated via kobana-app provisioning hook
InboxA routable email address + processing policyCreated via API; deactivated rather than deleted
EmailA received message + processing stateCreated by SES ingestion or POST /emails
AgentAn LLM configuration (model, system prompt, skills)Created via API
AgentRunA single execution of an agent against an emailCreated by the worker; read-only via API
WebhookA subscription to one or more SystemEvent slugsCreated via API
WebhookDeliveryAn attempt to POST a webhook payloadCreated by the dispatcher; read-only via API
SystemEventAn immutable record of a domain eventEmitted by handlers/workers; read-only via API

Shared fields​

Every resource exposes:

FieldTypeNotes
idUUID v4Internal identifier.
created_atISO 8601Set at creation.
updated_atISO 8601Updated by Prisma on every change.
deleted_atISO 8601 | nullSoft-delete marker.

Some resources additionally expose:

FieldTypeNotes
external_idUUID v4Stable identifier from the originating system (Workspace, Inbox, Agent).
metadataJSONSystem-set metadata.
custom_metadataJSONFree-form, never inspected by the system.

Soft delete​

Resources that support deletion are soft-deleted: deleted_at is set, but the row stays in Postgres. Queries filter by WHERE deleted_at IS NULL through a Prisma middleware. Re-creating a row that conflicts with a soft-deleted one (e.g. same email on Inbox) returns 409 conflict — restore the original via internal tooling rather than recreating.

Idempotency and uniqueness​

ResourceUnique constraint
Workspaceexternal_id
Inboxemail (global, not per-workspace)
Emailmessage_id (the SES messageId)
Agentexternal_id
Webhook— (label is not unique)

Email.message_id uniqueness is what makes the SES ingestion handler idempotent: SNS may retry the same notification, but the second insert hits the unique constraint and the handler returns 200 immediately.