Org in a Box
Architecture

Database Schema

The Org in a Box PostgreSQL schema (≈40 tables across runtime, platform-admin, and gateway-pairing groups).

Extensions Required

CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;

The migrator enables these from SQL_FRAGMENTS.enableExtensions on every boot (packages/db/src/migrate.ts).

Core Tables

tenants

Organisation units. One Azure AD tenant = one OIAB tenant.

ColumnTypeNotes
iduuid PK
nametextDisplay name
slugtext UNIQUEURL-safe: "contoso"
entra_tenant_idtext UNIQUEAzure AD tenant ID
settingsjsonb{ groupRoleMapping: { "<group-id>": "admin" } }
statustextactive | suspended | deleted

users

One row per person. Links to their tenant and (optionally) Azure AD identity.

ColumnTypeNotes
iduuid PK
handletext UNIQUEShort identifier
tenant_iduuid → tenantsNULL = single-operator
emailtext
display_nametext
entra_object_idtextAzure AD object ID
statustextactive | suspended | deactivated

roles / user_roles

RBAC roles and their assignments.

  • roles.permissions is a typed JSONB column (RbacPermissions)
  • user_roles links users to roles within a tenant
  • System roles (owner/admin/member/viewer) are seeded on tenant creation

entra_sessions

Active Azure AD SSO sessions with encrypted tokens.

Memory Tables

memories

Long-term agent memories with pgvector embeddings.

ColumnTypeNotes
iduuid PK
user_iduuid → users
tenant_iduuid → tenants
kindtextfact | preference | event | skill-note
contenttext
visibilitytextprivate | team | org
embeddingvector(1536)Added via raw SQL migration
source_session_idtextSession that created this memory

personas

Named personas (e.g. "work", "personal") that contextualise memories.

Job Queue

jobs

The central job queue. Workers use SELECT FOR UPDATE SKIP LOCKED.

ColumnTypeNotes
iduuid PK
kindtextagent-turn | orchestrator-* | embed-memories | …
statustextpending | running | completed | failed
payloadjsonbJob-specific data
run_attimestampEarliest execution time
attemptsintCurrent attempt count
max_attemptsintDefault 3
dedupe_keytext UNIQUE (partial)Prevents duplicate jobs
locked_bytextWorker ID holding the lock

Orchestrator Tables

orchestrator_plans

One row per complex task decomposition.

ColumnNotes
statusplanning → executing → synthesizing → completed | failed
planJSONB subtask definitions
resultSynthesised final response

orchestrator_subtasks

One row per sub-task in a plan.

ColumnNotes
index0-based position
dependenciesint[] of dependency indices
statuspending → running → completed | failed
resultSub-task output text

Learning Loop Tables

trajectories

Tool usage trajectory per session with embedding.

ColumnNotes
toolsJSONB: [{ tool, input_hash, output_hash }]
embeddingvector(1536)
outcomesuccess | failure | partial
reflectionLLM-generated reflection text

skills

Versioned reusable skills.

ColumnNotes
statusproposed → promoted → deprecated
versionAuto-incremented on promote
source_trajectoriesUUID[] of contributing trajectories

Analytics

usage_events

Per-request token/cost data. Idempotent on request_id (prevents double-counting on retries).

audit_log

Append-only compliance log. Partitioned by (tenant_id, ts) index for fast range queries.

Templates & Providers

sessions_index

Session metadata plus the frozen template behavior used by that session.

ColumnNotes
template_slugProvenance only: which template the session started from
template_system_promptFrozen system prompt for stable re-prompts
template_model_overrideFrozen provider/model override for stable re-prompts
template_snapshot_atWhen the template snapshot was captured

agent_templates

Pre-built agent configurations. NULL tenant_id = global template.

providers

Encrypted LLM provider credentials. One row per provider per user.

Migrations

The source of truth is the idempotent migrator in packages/db/src/migrate.ts — a single inline DDL block (SCHEMA + PLATFORM_SCHEMA + GATEWAY_SCHEMA) where every statement uses CREATE TABLE IF NOT EXISTS / ADD COLUMN IF NOT EXISTS. There are no numbered migration files in play today. A legacy packages/db/migrations/0002_multi_tenancy.sql file is kept only as a raw-SQL reference for operators who want to diff the multi-tenancy slice.

Migrations run automatically on worker/API boot via runMigrations(postgresUrl).

On this page