Skip to content
Select themeSelect language

Data dictionary

This page maps every term in the user glossary onto the schema that actually backs it. It is the identifier-level companion to the core data model, which draws the tenancy and resource spine; here the unit is the term, not the table. Migration numbers refer to files in server/migrations/ (see the migration index).

Naming is the ubiquitous language of ADR 0040: one term, one meaning across DB, code, API and UI.

  • The tenant table is workspaces, renamed from teams in migration 169 together with team_membersworkspace_members, team_invitesworkspace_invites, and every team_id FK → workspace_id.
  • organizations.kind='team' stays an internal enum value; its user-facing label is Organization (org_kind_team), against Personal for kind='personal'. Never surface the raw value.
  • team/teams is otherwise reserved for the agent domain (agent_teams, max_teammates). An architecture test fails a new team_id column or a new team-named tenant type, and a frontend i18n lint fails a new user-facing “Team” string outside the agent and delivery_* namespaces.
Term Authority What to know
Organization organizationsid, name, slug UNIQUE, kind kind CHECK is personal or team, NOT NULL DEFAULT team (mig 140). The plan is per organization on subscriptions, whose PK was re-keyed from workspace_id to organization_id in mig 143 — never look for a plan on a workspace.
Organization membership organization_membersuser_id, organization_id, role, seat_type_id UNIQUE (user_id) enforces the single-org model (no switcher, no X-Organization-Id). role is the wider org set: owner, billing_admin, admin, member.
Workspace workspaces; FK workspace_id on ~34 tables Renamed from teams in mig 169 (catalog-only rename, no row rewrite). Also carries autonomy_level, autonomy_overrides, experience_tier.
Workspace membership workspace_membersworkspace_id, user_id, role role CHECK tightened to owner, admin, member in mig 245. Trigger trg_team_member_org_invariant — deliberately not renamed by 169, so unchanged RLS policies still resolve — requires a matching organization_members row for the workspace’s org; a violation raises check_violation.
Seat seat_typeskey UNIQUE, entitlements JSONB, stripe_price_id UNIQUE; assigned via organization_members.seat_type_id Table created in mig 144, which also added the FK (ON DELETE SET NULL, so archiving a seat type unassigns rather than blocks). Entitlements resolve first-non-null: user override › seat type › workspace override › org plan. Billing quantity lives on subscription_items (organization_id, seat_type_id).
Project projects PR-flow autodev config no longer lives here: mig 299 dropped 12 auto_developer_* columns (only auto_developer_workflow_id survives), 302 dropped the auto_issue_debate_* set, 297 dropped the visual-verify columns. The pr_review row of project_automations is the authority. backlog_merge_policy CHECK is pr_only, auto_on_green, full_auto (mig 287).
Term Authority What to know
Task tasksproject_id, agent_type, status, config JSONB, agent_profile_id config is the per-launch override bag (effort, harness knobs, teammates, closeout); agent_profile_id is the WHO authority. The status/branch/timestamp columns are a denormalised cache of the latest run, never the source of truth.
Run runskind discriminator, task_id, workflow_id, parent_run_id, workflow_node_key next_event_seq (mig 220) mints a gapless, monotonic events.sequence_num per run via an atomic UPDATE … RETURNING; uq_events_run_seq is the safety net. autonomy_policy_json (mig 214) is the policy frozen at launch. events.task_id is nullable since mig 331 so a workflow-node event can key on a run with no task.
Schedule task_schedulesworkspace_id, cadence, next_run_at, agent_profile_id agent_profile_id added in mig 293 (ON DELETE SET NULL). cadence CHECK is once, daily, weekly, monthly, interval since mig 323, which also added interval_minutes bound by CHECK ((cadence = 'interval') = (interval_minutes IS NOT NULL)) and a 5–1440 range — cadence and column are inseparable.
Workflow workflows + workflow_nodes + workflow_edges workflow_nodes is UNIQUE (workflow_id, node_key); edges join by the node_key text (source_node/target_node), with source_handle defaulting to out. workflows.stages JSONB arrived in mig 311.
Term Authority What to know
Agent tasks.agent_type (plus the resolved container image) Not a table of its own — the agent is the harness process a run starts. The image is chosen from the repository’s detected language at launch.
Agent profile agent_profilesexecution_mode, is_workspace_default, autonomy_level, interactive_approval execution_mode CHECK is normal or workflow since mig 285; ultracode was retired to the effort axis (minimalmax), though the runtime still tolerates a legacy in-flight value in task config. is_workspace_default (mig 119) is bounded by the partial unique index uq_agent_profiles_workspace_default — at most one default per workspace.
Teammates Not a column. tasks.config keys agent_teams (bool) and max_teammates (int) No table and no migration; ADR 0040 keeps the key name because it is Claude Code’s own. The runtime emits CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS / CLAUDE_CODE_MAX_TEAMMATES for claude, and AGENT_TEAMS=1 for codex/gemini. max_teammates is emitted only when agent_teams is true.
Skill agent_capabilities with kind='skill' — Markdown in config.instructions kind CHECK is mcp or skill; UNIQUE (workspace_id, kind, name). config also carries targets, the per-harness allowlist. An induced skill is staged in the separate skill_proposals table (mig 218) and only becomes an agent_capabilities row once published. Capability writes are workspace-admin gated.
Council councils + council_participants + council_turns mode CHECK is analyze, propose, review, standup — the UI labels differ from these stored values, so map rather than assume. target_type gained workflow_step in mig 314, which is how a pipeline stage runs a council. The synthesis lands on judge_profile_id / judge_synthesis / judge_confidence.
Memory memoriesscope, source_type; siblings memory_versions, memory_review_items, memory_embeddings scope CHECK is personal, workspace, project. The source_type CHECK is deliberately wider than the user-facing allowlist (it admits repo_sync, agent_experiment and a harness_memory:% arm); validate_memory_source_type is the narrow gate, and system paths bypass it via create_system_memory. Governance is two-tier: workspace_settings.memory_governance_policy (mig 249) with a project override projects.memory_governance_policy (mig 289).
MCP No table. The catalog is code, exported to docs/mcp/ and drift-gated Per-task/workspace/profile caps are derived from audit_events so they survive restarts; in-flight reservations live in mcp_cap_reservations, whose task_id is nullable since mig 268 for the task-less external-gateway principal.
Term Authority What to know
Autonomy level workspaces.autonomy_level (NOT NULL DEFAULT 0, CHECK 0–100), projects.autonomy_level (nullable), agent_profiles.autonomy_level (nullable) — all mig 214 NULL means inherit, so the chain profile › project › workspace always terminates at a concrete workspace value. The result is then clamped by the plan ceiling plans.features->'autonomy.level_max' and the onboarding cap; a per-arm project_automations.autonomy_override (mig 210) can only lower it. runs.autonomy_policy_json freezes the outcome at launch.
Approval (gate) task_tool_approvalskind, status, timeout_policy, deadline_at kind CHECK is tool, question, visual, tier_change (widened by mig 321). tier_change is deliberately not question, because the parent-answer guard admits only question — a machine must not self-approve the gate it raised. Partial index uq_task_tool_approvals_task_pending allows at most one pending approval per task, and hold-policy rows are never auto-swept.
Backlog backlog_items plus the dispatch arm project_automations with kind='backlog' project_automations.kind CHECK is now pr_review, intake, backlog: tracker was renamed to intake (mig 303) and debate was retired (mig 291). Issue import and dispatch are separate paths — import runs regardless of mode.
Backlog item backlog_itemssource, external_id, scope, state Dedupe key is UNIQUE (project_id, source, external_id): mig 303 added source and backfilled it from tracker, mig 304 dropped the old column and its unique index. scope is nullable with CHECK small, medium, large (mig 226); NULL is routed as neutral. convergence_round / convergence_cost_usd bound the review loop (mig 232), and closed_at carries CHECK (closed_at IS NULL OR state = 'done') (mig 310).
Concept approval mode project_automations.pipeline_config JSONB → stages.plan.approval (bool) The approval_mode column was dropped in mig 301 after mig 300 folded it: conceptstages.plan.approval, pr_draftstages.implement.draft_pr_approval, human_gateprojects.backlog_merge_policy = 'pr_only'. concept_gate_on reads the flag with no enum fallback left, and the gate applies only to a kind='backlog' arm.
Completion action project_automations.post_completion_comment × close_source_issue (both nullable, mig 295) The two booleans span all four outcomes, including the previously inexpressible silent close (false, true). The legacy completion_action column still exists (close, comment, nothing) as a lossy dual-read fallback for a row whose boolean pair is NULL; its drop is deferred. Resolve the pair first, the enum only as fallback.
Closeout workspace_settings.closeout_config (JSONB NOT NULL, full default) + projects.closeout_config (nullable, sparse) + task.config.closeout; signals on task_outcomes.closeout_signals — mig 283 Resolution is per step, first-non-null: task ?? project ?? workspace ?? built-in. There is deliberately no master switch; the fold lives once in sc-persistence::models::closeout and is shared by the memory gate, the env injection and the status signal.
Term Authority What to know
App appsUNIQUE (workspace_id, name), manifest_yaml; source tree in app_files (mig 107) apps.db_namespace_id (mig 279) is the App’s database authority; app_db_resource_id survives only as the hint for which physical Postgres. app_migrations is no longer a table — mig 280 folded it onto db_namespace_migrations and left a read-only compatibility view. The schema is app_<id>, and db_namespace_bindings enforces exactly one binder.
Script scripts (mig 066) locally; the catalog row is marketplace_items with kind='script' An installed script is tracked on marketplace_installs.installed_script_ids. The Wasm script substrate is pure-compute and DB-isolated by design; it reaches the network only through a bound resource’s allowlisted authority.
Connector marketplace_items with kind='node', plus the per-workspace registry workflow_node_types workflow_node_types is UNIQUE (workspace_id, slug) and carries preset_config, required_resource_kinds, source_item_version_id. The component bytes ride the version manifest as component_data_b64.
Resource resourcesUNIQUE (workspace_id, name), kind, config JSONB, secret_vault_path kind is a CHECK list, currently smtp, telegram_bot, webhook_endpoint, imap, postgresql, s3, discord, seafile_webdav, fints_bank, chatwoot, intercom, custom (last widened by mig 324). Each kind gates on the plan feature key resources.<kind>. secret_vault_path is nullable, so a secret-less resource is representable. The UI calls these Connections.
Runner runnersstatus, drain_state, capabilities JSONB, auth_token_hash UNIQUE status CHECK is pending, online, offline, disabled; drain_state CHECK is active, cordoned, draining (mig 234). Dispatch reads status='online' AND drain_state='active'. lease_epoch is not on runners — it is on runner_work_assignments / connector_run_assignments (mig 239), because fencing belongs to the assignment. Enrollment lives in runner_enrollments + runner_grants (mig 236).
Term Authority What to know
Marketplace marketplace_items (UNIQUE (source_id, slug)) + marketplace_item_versions + marketplace_installs marketplace_items.kind CHECK is app, script, bundle, runner_offer, workflow, node — six values, so do not omit runner_offer. marketplace_installs is UNIQUE (workspace_id, item_id) since mig 112: a re-install upserts, never duplicates. install_manifest_sha256 drives drift detection.
Bundle marketplace_items with kind='bundle'; contents ride marketplace_item_versions.package_manifest JSONB under members members is a manifest block, not a column — a bundle is folded at publish into one members block plus a unioned install spec and requirements, so one install is one marketplace_installs row. Publish rejects fewer than two members, a member-slug collision, a self-reference, a cycle, more than one member db_namespace, and a paid member in a free bundle. An App member may carry its tree inline instead of a source_tarball_url / source_tarball_sha256 pair.
Term Authority What to know
Live mode No table. Per-surface session state in sc-iface-telegram/src/live_mode and sc-iface-discord/src/live_mode, and the web follow engine Follow is per surface: a Telegram launch streams only in Telegram. Both chat surfaces share the same pure render substrate; only the transport differs.
Verbosity chat_platform_accounts.verbosity + user_profiles.default_verbosity (mig 255) Both nullable with CHECK reduced or chatty. NULL is the layering signal, not a value: per-account ?? user default ?? built-in reduced. Orthogonal to debug mode — two axes, one renderer, one redaction wall.
Debug mode workspace_settings.allow_debug BOOLEAN NOT NULL DEFAULT false (mig 254) Fail-closed by default, unlike onboarding_mode, which coalesces to TRUE. The per-session activation on top of this ceiling is ephemeral and never persisted; the ceiling is enforced server-side on every surface.
Delivery board Frontend route /reports/delivery; HTTP surface GET /api/team-board; Rust services::team_board and sc-persistence::queries::delivery_board The UI, i18n (delivery_*) and route say delivery; the HTTP path and Rust module still say team_board. That split is intentional and unrenamed — there is no /delivery backend route. Only one i18n key is literally delivery_board_*.

Each of these reads plausibly but is wrong against the current schema.

Stale identifier Current truth Landed in
teams, team_members, team_id workspaces, workspace_members, workspace_id 169
subscriptions.workspace_id re-keyed to organization_id (PK); workspace_id dropped 143
project_automations.approval_mode (with a concept value) column dropped; pipeline_config → stages.plan.approval 300, 301
project_automations.kind='tracker' / 'debate' intake; debate retired 291, 303
backlog_items.tracker, dedupe (project_id, tracker, external_id) source, dedupe (project_id, source, external_id) 303, 304
projects.auto_developer_*, auto_issue_debate_*, visual-verify columns dropped; re-homed onto the project_automations arm 297, 299, 302
merge policy auto_merge_on_green auto_on_green 287
agent_profiles.execution_mode='ultracode' normal or workflow; effort carries the intent 285
runners.lease_epoch on runner_work_assignments / connector_run_assignments 239
app_migrations as a table read-only view over db_namespace_migrations 280
apps.app_db_resource_id as the App DB authority apps.db_namespace_id 279
task_schedules.cadence limited to once/daily/weekly plus monthly, interval (+ interval_minutes) 323
resource kinds ending at intercom custom added 324
workflow_steps, workflow_runs, workflow_node_runs dropped; folded into workflow_nodes and runs 046, 051
  • Glossary — the user-facing half of these terms
  • Core data model — the tenancy and resource spine, with the ERD
  • Migration index — numbering, gaps, and the shared-namespace rule
  • ADR 0040 — Workspace/Team naming cleanup and a single domain vocabulary