Skip to Content
Developer DocsDatabaseSchema

Database Schema

AEGIS uses PostgreSQL 15 with three extensions: pgvector for vector similarity search, Apache AGE for the knowledge graph, and uuid-ossp for UUID generation. The schema is initialized from SQL files mounted into the PostgreSQL container at startup.

Schema Initialization

The database is initialized by three SQL files executed in order:

FilePurpose
00-create-extension-age.sqlCreate the AGE extension with IF NOT EXISTS guard
infrastructure/docker/postgres/init.sqlCore tables: audit logs, episodic memories, agents, skills, approvals, conversations, budget
infrastructure/docker/postgres/002_checklist_compliance_tables.sqlChecklist templates, filing checklists, compliance status, rule versions, filing rule snapshots
infrastructure/docker/postgres/007_entity_type_definitions.sqlAdmin-managed entity type system: type definitions, field definitions, relationship rules, RRC mappings
infrastructure/docker/postgres/029_entity_type_vertex_label.sqlStored vertex_label column on entity_type_definitions (type_key → AGE label bridge, entity-explorer hardening Root A)
services/agent-config-service/.../001_initial_schema.sqlPrompt management: namespaces, templates, versions, budget tiers, audit log, access control

Extensions

CREATE EXTENSION IF NOT EXISTS vector; -- pgvector for episodic memory CREATE EXTENSION IF NOT EXISTS age; -- Apache AGE for knowledge graph CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- UUID generation

Graph Setup

After enabling extensions, the init script creates the AGE graph. Graphs are per-tenant (tenant_<hex>_oilgas, where <hex> is the dash-free hex of the tenant UUID) — there is no single global oilgas graph. init.sql seeds the dev tenant’s graph:

LOAD 'age'; SET search_path = ag_catalog, "$user", public; SELECT create_graph('tenant_00000000000000000000000000000001_oilgas'); SET search_path = public, ag_catalog, "$user";

The oilgas suffix is the logical schema name (the first installed vertical); entity/vertex labels are runtime DB-backed via entity_type_definitions (see Graph Schema), not hardcoded.

Every PostgreSQL connection that runs Cypher queries must execute LOAD 'age' and SET search_path = ag_catalog, "$user", public before any graph operation. The AgePool class handles this automatically.


Core Tables (init.sql)

audit_logs

Append-only audit trail. Database triggers prevent UPDATE and DELETE operations.

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEY, default uuid_generate_v4()Unique log entry ID
tenant_idVARCHAR(50)NOT NULLTenant isolation key
event_typeVARCHAR(100)NOT NULLType of audit event
event_dataJSONBNOT NULLFull event payload
actor_idVARCHAR(100)Who performed the action. Stays TEXT permanently (R42e): the table is append-only and hash-chained, so rows are never rewritten — historical actor strings resolve at READ time through identity_map
actor_typeVARCHAR(20)default 'system'Actor category (system, user, agent)
created_atTIMESTAMPTZdefault NOW()Event timestamp
signatureVARCHAR(256)HMAC signature for tamper detection

Protection Triggers:

CREATE OR REPLACE FUNCTION prevent_audit_modification() RETURNS TRIGGER AS $$ BEGIN RAISE EXCEPTION 'Audit logs are append-only. Updates and deletes are prohibited.'; END; $$ LANGUAGE plpgsql; CREATE TRIGGER no_update_audit BEFORE UPDATE ON audit_logs FOR EACH ROW EXECUTE FUNCTION prevent_audit_modification(); CREATE TRIGGER no_delete_audit BEFORE DELETE ON audit_logs FOR EACH ROW EXECUTE FUNCTION prevent_audit_modification();

The audit trail is immutable by design. Any attempt to UPDATE or DELETE a row will raise a PostgreSQL exception. This is enforced at the database level, not the application level, so it cannot be bypassed by service code.

users

Authentication accounts for the auth service. Accounts are admin-provisioned (no self-serve signup); passwords are stored as bcrypt hashes.

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEY, default uuid_generate_v4()Unique user ID
emailVARCHAR(255)NOT NULLLogin email (case-insensitively unique)
password_hashTEXTNOT NULLbcrypt password hash. Empty string = invited or system user — login fails closed
display_nameVARCHAR(200)Optional display name
is_activeBOOLEANNOT NULL, default TRUEInactive users cannot log in; deactivation is the removal path (no hard delete)
token_versionINTNOT NULL, default 0R42a revocation seam — bumped by logout-all / deactivation / password reset; compared against the JWT tv claim
password_set_atTIMESTAMPTZR42a — NULL = invited (empty password_hash, login fails closed)
created_atTIMESTAMPTZdefault NOW()Creation timestamp
updated_atTIMESTAMPTZdefault NOW()Last update timestamp

Indexes:

IndexTypeColumnsNotes
idx_users_email_lowerUNIQUELOWER(email)Enforces case-insensitive email uniqueness (no citext extension)

This table is created in init.sql for fresh databases; the auth-service boot-time migration runner (R42a) also re-ships it idempotently, so a fresh database converges on service start without manual psql. The legacy roles TEXT[] shadow column is dropped in R42e — grants live solely in user_roles; the boot runner drops the column only after its one-time backfill has run.

System users (R42e, migration 031): four non-loginable accounts seeded for FK integrity and attribution — password_hash = '' fails closed at login, is_active = TRUE so they satisfy FKs and appear in attribution joins:

EmailUUIDPurpose
system@aegis.local00000000-0000-0000-0000-000000000000Deliberately the nil UUID — the SYSTEM_USER literal seeds have always stamped into created_by, so historical rows satisfy the new FKs without a rewrite
legacy@aegis.local…0000001e9ac1Backfill target for unmappable historical identity strings
eval-runner@aegis.local…0000000000e5Eval replay identity — inserted only if the email is absent (deployed boxes keep their real row)
demo-seed@aegis.local…0000deed5eedDemo-data ownership tag — the demo seeder deletes-then-recreates only rows carrying this id

RBAC tables: roles, role_permissions, user_roles, user_invites (R42a)

Owned by auth-service’s boot-time migration runner (services/auth-service/src/auth_service/migrations/003_rbac_substrate.sql). Boot-order rule: non-auth services must never FK to roles/user_roles — only users is guaranteed to exist everywhere.

TablePurpose
roles(id, tenant_id NULL=platform, key, display_name, description, is_system) — the 4 seeded system roles (admin, power_user, reviewer, operator); unique on (scope, key)
role_permissions(role_id FK CASCADE, permission)resource.action strings; seeded from the signed-off R42 Appendix C matrix in auth_service/rbac.py
user_roles(user_id FK CASCADE, role_id FK CASCADE, granted_by, granted_at) — sole source of truth for a user’s roles; backfilled once from the legacy users.roles array (column dropped in R42e)
user_invites(user_id FK CASCADE, token_hash UNIQUE sha256, purpose invite/password_reset, expires_at, used_at, created_by) — one-time tokens, single-use via used_at IS NULL + row lock; invite 7d, reset 1h

episodic_memories

Conversation summaries with vector embeddings for semantic search.

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEY, default uuid_generate_v4()Memory ID
agent_idVARCHAR(100)NOT NULLWhich agent generated this memory
user_idUUIDREFERENCES users(id) ON DELETE RESTRICTUser who participated in the conversation (retyped from VARCHAR in R42e, migration 031)
conversation_idVARCHAR(100)NOT NULLSource conversation
summaryTEXTNOT NULLHuman-readable summary
key_decisionsJSONBDecisions made during the conversation
entities_mentionedJSONBEntity IDs referenced
tools_calledJSONBTools invoked during execution
embeddingvector(1536)OpenAI text-embedding-3-small vector
created_atTIMESTAMPTZdefault NOW()Creation timestamp

Indexes:

IndexTypeColumnsNotes
idx_episodic_embeddingIVFFlatembedding vector_cosine_opsWITH (lists = 100) for cosine similarity
idx_episodic_agent_userB-tree(agent_id, user_id)Filter by agent and user

agents

Agent definitions with configuration, system prompts, and skill assignments.

ColumnTypeConstraintsDescription
idVARCHAR(100)PRIMARY KEYAgent identifier (e.g., rule37-agent)
nameVARCHAR(200)NOT NULLDisplay name
configJSONBNOT NULLSystem prompt, model prefs, skills, budgets, HITL policies
statusVARCHAR(20)default 'active'Agent status
created_atTIMESTAMPTZdefault NOW()Creation timestamp
updated_atTIMESTAMPTZdefault NOW()Last update timestamp

skills

Skill registry with the three-tier injection architecture.

ColumnTypeConstraintsDescription
idVARCHAR(100)PRIMARY KEYSkill identifier (e.g., spacing-calculation)
nameVARCHAR(200)NOT NULLDisplay name
tier1_manifestJSONBNOT NULLTier 1: name, description, triggers (~50 tokens)
tier2_definitionJSONBNOT NULLTier 2: full specification (~200-800 tokens)
tier3_artifact_refsJSONBTier 3: references to artifact content
domain_tagsVARCHAR(100)[]Array of domain labels for skill matching
statusVARCHAR(20)default 'active'Skill status
created_atTIMESTAMPTZdefault NOW()Creation timestamp
updated_atTIMESTAMPTZdefault NOW()Last update timestamp

skill_artifacts

Tier 3 artifact content for skills (reference tables, form guides, regulatory text).

ColumnTypeConstraintsDescription
idVARCHAR(100)PRIMARY KEYArtifact identifier
skill_idVARCHAR(100)REFERENCES skills(id)Parent skill
nameVARCHAR(200)NOT NULLArtifact name
contentTEXTNOT NULLFull artifact content
content_hashVARCHAR(64)NOT NULLSHA-256 hash for change detection
token_estimateINTApproximate token count
created_atTIMESTAMPTZdefault NOW()Creation timestamp

approval_requests

HITL approval requests for agent execution checkpoints.

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEY, default uuid_generate_v4()Request ID
execution_idVARCHAR(100)NOT NULLAgent execution ID
agent_idVARCHAR(100)NOT NULLAgent that created the request
checkpoint_typeVARCHAR(100)NOT NULLHITL checkpoint type (e.g., pre_filing)
state_snapshotJSONBNOT NULLFull agent state at checkpoint
reviewer_idUUIDREFERENCES users(id) ON DELETE RESTRICTAssigned reviewer (retyped from VARCHAR in R42e, migration 031)
reviewer_strategyVARCHAR(50)NOT NULLAssignment strategy: named_individual or role_based
statusVARCHAR(20)default 'pending'Request status
decisionVARCHAR(20)Reviewer decision: approved, rejected, modified
reviewer_commentsTEXTReviewer feedback
originTEXTNOT NULL default 'conversation', CHECK ∈ (conversation,replay)R40b (022_approval_origin.sql): replay for eval-replay approvals so the admin queue hides them (list defaults to origin='conversation'; replay approvals never escalate to humans)
created_atTIMESTAMPTZdefault NOW()Creation timestamp
decided_atTIMESTAMPTZDecision timestamp

Index:

IndexColumnsPurpose
idx_approval_status(status, reviewer_id)Filter pending approvals by reviewer

conversations

Conversation sessions linking users to agents.

ColumnTypeConstraintsDescription
idVARCHAR(100)PRIMARY KEYConversation ID
agent_idVARCHAR(100)NOT NULLAssigned agent
user_idUUIDREFERENCES users(id) ON DELETE RESTRICTOwning user (backfilled from first attributed message by migration 023; retyped to uuid + FK in R42e, migration 031)
statusVARCHAR(20)default 'active'Conversation status
titleVARCHAR(200)Display title (falls back to first user message)
conversation_typeVARCHAR(50)filing_prep, field_event, replay (eval), test (golden/smoke) — replay/test are hidden from the user list
last_message_atTIMESTAMPTZRecency for list ordering
deleted_atTIMESTAMPTZSoft-delete marker
metadataJSONBAdditional metadata
created_atTIMESTAMPTZdefault NOW()Creation timestamp
updated_atTIMESTAMPTZdefault NOW()Last activity

budget_usage

Token and cost tracking per agent execution.

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEY, default uuid_generate_v4()Record ID
agent_idVARCHAR(100)NOT NULLAgent identifier
execution_idVARCHAR(100)NOT NULLExecution identifier
tokens_usedINTNOT NULLTotal tokens consumed
cost_usdDECIMAL(10,6)Dollar cost of the execution
modelVARCHAR(100)LLM model used
created_atTIMESTAMPTZdefault NOW()Record timestamp

Checklist & Compliance Tables (002_checklist_compliance_tables.sql)

checklist_templates

Templates defining the checklist structure for each compliance domain (one template per domain per version).

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEY, default uuid_generate_v4()Template ID
tenant_idVARCHAR(50)NOT NULLTenant key
compliance_domainVARCHAR(50)NOT NULLDomain: rule_37, rule_32, form_pr, flaring_monitor
versionINTdefault 1Template version
itemsJSONBNOT NULLOrdered array of checklist item definitions
min_required_itemsJSONBItem indices required for HITL submission
created_atTIMESTAMPTZdefault NOW()Creation timestamp
updated_atTIMESTAMPTZdefault NOW()Last update

Unique constraint: (tenant_id, compliance_domain, version)

filing_checklists

Active checklist instances — one per entity per compliance domain work session.

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEY, default uuid_generate_v4()Checklist instance ID
tenant_idVARCHAR(50)NOT NULLTenant key
entity_idVARCHAR(255)NOT NULLKG entity ID (well API#, facility ID)
entity_typeVARCHAR(50)NOT NULLEntity type: well, lease, facility, etc.
entity_nameVARCHAR(500)Display name
compliance_domainVARCHAR(50)NOT NULLCompliance domain
template_idUUIDREFERENCES checklist_templates(id)Source template
statusVARCHAR(20)default 'draft', CHECK constraintFiling status
deadlineTIMESTAMPTZFiling deadline
itemsJSONBNOT NULLCurrent state of each checklist item
metadataJSONBdefault '{}'Conversation IDs, reviewer notes, alerts
created_byUUIDREFERENCES users(id) ON DELETE RESTRICTWho initiated the checklist (retyped from VARCHAR in R42e, migration 031)
created_atTIMESTAMPTZdefault NOW()Creation timestamp
updated_atTIMESTAMPTZdefault NOW()Last update

Status values: draft, in_progress, ready_for_review, in_review, approved, rejected, filed, exception

Indexes:

IndexColumns
idx_filing_checklists_entity(tenant_id, entity_id, compliance_domain)
idx_filing_checklists_status(tenant_id, status)

checklist_artifacts

Generated documents, PDFs, and data exports attached to checklist items.

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEY, default uuid_generate_v4()Artifact ID
checklist_idUUIDREFERENCES filing_checklists(id) ON DELETE CASCADEParent checklist
item_indexINTNOT NULLChecklist item this artifact belongs to
artifact_typeVARCHAR(50)NOT NULLType: document, pdf, plat_draft, data_export, waiver, form_draft
nameVARCHAR(500)NOT NULLArtifact name
content_typeVARCHAR(100)MIME type
contentTEXTText/markdown/JSON content
file_pathVARCHAR(1000)Path for binary artifacts
metadataJSONBdefault '{}'Source attribution, version, confidence
generated_byVARCHAR(50)CHECK IN ('agent', 'user', 'system')Who created the artifact
created_atTIMESTAMPTZdefault NOW()Creation timestamp

Index: idx_checklist_artifacts_checklist on (checklist_id, item_index)

compliance_status

Materialized cache of the entity-by-domain compliance matrix.

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEY, default uuid_generate_v4()Row ID
tenant_idVARCHAR(50)NOT NULLTenant key
entity_idVARCHAR(255)NOT NULLKG entity ID
entity_typeVARCHAR(50)NOT NULLEntity type
entity_nameVARCHAR(500)Display name
entity_fieldVARCHAR(255)Field name from KG
entity_districtVARCHAR(10)RRC district
compliance_domainVARCHAR(50)NOT NULLCompliance domain
statusVARCHAR(20)NOT NULL, CHECK constraintCompliance status
deadlineTIMESTAMPTZNext deadline for this domain
checklist_idUUIDREFERENCES filing_checklists(id)Active checklist if exists
detailsJSONBdefault '{}'Domain-specific status details
last_assessed_atTIMESTAMPTZdefault NOW()Last assessment timestamp

Status values: compliant, action_needed, overdue, not_applicable, in_review

Unique constraint: (tenant_id, entity_id, compliance_domain)

Indexes:

IndexColumns
idx_compliance_status_tenant(tenant_id, status)
idx_compliance_status_domain(tenant_id, compliance_domain)
idx_compliance_status_deadline(tenant_id, deadline)

rule_versions

Immutable, versioned regulatory rules. Never UPDATE existing rules — always create a new version.

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEY, default uuid_generate_v4()Rule version ID
tenant_idVARCHAR(50)NOT NULLTenant key
rule_typeVARCHAR(50)NOT NULLstatewide, field_specific, notice
rule_domainVARCHAR(50)NOT NULLspacing, density, flaring, reporting
rule_identifierVARCHAR(255)NOT NULLUnique rule key (e.g., SWR_37)
versionINTNOT NULLVersion number (monotonically increasing)
effective_dateDATENOT NULLWhen the rule took effect
superseded_dateDATEWhen superseded (NULL if current)
sourceVARCHAR(50)NOT NULLrrc_ingestion, rule_monitor_agent, manual, docket_hearing
source_referenceVARCHAR(500)Citation, docket number, URL
rule_dataJSONBNOT NULLActual rule parameters
graph_node_idVARCHAR(255)Reference to KG node
change_summaryTEXTWhat changed in this version
detected_atTIMESTAMPTZdefault NOW()When the change was detected
detected_byVARCHAR(100)Who/what detected the change
statusVARCHAR(20)default 'active', CHECK constraintRule status

Status values: active, superseded, pending_review, draft

Unique constraint: (tenant_id, rule_identifier, version)

Indexes:

IndexColumnsNotes
idx_rule_versions_active(tenant_id, rule_identifier, status)Partial: WHERE status = 'active'
idx_rule_versions_domain(tenant_id, rule_domain)

filing_rule_snapshots

Frozen copies of rules at the time a filing was initiated. Used for stale detection.

ColumnTypeConstraintsDescription
idUUIDPRIMARY KEY, default uuid_generate_v4()Snapshot ID
checklist_idUUIDREFERENCES filing_checklists(id) ON DELETE CASCADEParent checklist
rule_version_idUUIDREFERENCES rule_versions(id)Original rule version
snapshotted_atTIMESTAMPTZdefault NOW()Snapshot timestamp
rule_data_at_snapshotJSONBNOT NULLFrozen copy of rule_data
is_currentBOOLEANdefault trueFalse if rule has been superseded
superseded_byUUIDREFERENCES rule_versions(id)Newer version if superseded
acknowledgedBOOLEANdefault falseUser acknowledged the stale rule
acknowledged_byVARCHAR(255)Who acknowledged
acknowledged_atTIMESTAMPTZWhen acknowledged

Indexes:

IndexColumnsNotes
idx_filing_rule_snapshots_checklist(checklist_id)
idx_filing_rule_snapshots_stale(is_current)Partial: WHERE is_current = false

Entity Type System Tables (007_entity_type_definitions.sql)

entity_type_definitions

Admin-managed entity type schemas (e.g., Well, Facility, Wellpad).

ColumnTypeConstraintsDescription
type_idUUIDPRIMARY KEY, default gen_random_uuid()Type ID
tenant_idUUIDNOT NULLTenant key
type_keyVARCHAR(64)NOT NULLMachine key (e.g., well, facility)
vertex_labelTEXTNOT NULL, CHECK identifier shape (migration 029)Stored AGE graph vertex label (e.g., Well, FlaringAuthorization). Immutable; backfilled as PascalCase of type_key. Unique per (tenant_id, vertex_label)
display_nameVARCHAR(128)NOT NULLUI display name
iconVARCHAR(64)Icon identifier
colorVARCHAR(7)Hex color code
compliance_footprintBOOLEANNOT NULL, default falseWhether this type appears in compliance matrix
is_system_typeBOOLEANNOT NULL, default falseSystem types cannot be deleted
created_atTIMESTAMPTZNOT NULL, default NOW()Creation timestamp
updated_atTIMESTAMPTZNOT NULL, default NOW()Auto-updated via trigger

Unique constraint: (tenant_id, type_key)

Index: idx_etd_tenant on (tenant_id)

Auto-update trigger: trg_etd_updated fires BEFORE UPDATE to set updated_at = NOW().

entity_field_definitions

Field definitions for each entity type (dynamic schema).

ColumnTypeConstraintsDescription
field_idUUIDPRIMARY KEY, default gen_random_uuid()Field ID
type_idUUIDNOT NULL, REFERENCES entity_type_definitions(type_id) ON DELETE CASCADEParent entity type
tenant_idUUIDNOT NULLTenant key
field_keyVARCHAR(64)NOT NULLMachine key (e.g., api_number)
labelVARCHAR(128)NOT NULLDisplay label
input_typeVARCHAR(32)NOT NULLInput type (text, number, date, select, etc.)
requiredBOOLEANNOT NULL, default falseWhether field is required
validation_presetVARCHAR(64)Preset validation rule
optionsJSONBOptions for select/enum fields
display_groupVARCHAR(64)UI grouping
sort_orderINTEGERNOT NULL, default 0Display order
created_atTIMESTAMPTZNOT NULL, default NOW()Creation timestamp

Unique constraint: (type_id, field_key)

Index: idx_efd_type_order on (type_id, sort_order)

entity_relationship_rules

Defines allowed relationships between entity types.

ColumnTypeConstraintsDescription
rule_idUUIDPRIMARY KEY, default gen_random_uuid()Rule ID
tenant_idUUIDNOT NULLTenant key
parent_type_idUUIDNOT NULL, REFERENCES entity_type_definitions(type_id) ON DELETE CASCADEParent entity type
child_type_idUUIDNOT NULL, REFERENCES entity_type_definitions(type_id) ON DELETE CASCADEChild entity type
cardinalityVARCHAR(16)NOT NULL, default 'one_to_many'Relationship cardinality
requiredBOOLEANNOT NULL, default falseWhether relationship is required
display_labelVARCHAR(128)UI label for the relationship
created_atTIMESTAMPTZNOT NULL, default NOW()Creation timestamp

Unique constraint: (tenant_id, parent_type_id, child_type_id)

Indexes: idx_err_tenant, idx_err_parent, idx_err_child

rrc_field_mappings

Maps RRC data fields to entity field definitions for automated data import.

ColumnTypeConstraintsDescription
mapping_idUUIDPRIMARY KEY, default gen_random_uuid()Mapping ID
tenant_idUUIDNOT NULLTenant key
type_idUUIDNOT NULL, REFERENCES entity_type_definitions(type_id) ON DELETE CASCADEEntity type
rrc_field_keyVARCHAR(128)NOT NULLRRC field name
entity_field_idUUIDNOT NULL, REFERENCES entity_field_definitions(field_id) ON DELETE CASCADETarget entity field
created_atTIMESTAMPTZNOT NULL, default NOW()Creation timestamp

Index: idx_rfm_type on (type_id)


Connecting to the Database

# Via psql psql -h localhost -U aegis -d aegis # Password: aegis_local (from docker-compose.yml)

Prompt Management Tables (008_prompt_management.sql)

These tables support the agent-config-service’s prompt template management system.

prompt_namespaces

Organizes prompt templates into named groups with approval and access settings.

ColumnTypeDescription
idUUIDPrimary key
tenant_idUUIDTenant isolation
namespace_keyVARCHAR(64)Unique key within tenant (e.g., agents)
display_nameVARCHAR(255)Human-readable name
auto_approveBOOLEANSkip approval on promotion to active
approversTEXT[]List of approver user IDs
max_render_timeoutINTEGERRender timeout in milliseconds
data_classificationVARCHAR(20)public, internal, confidential, restricted

prompt_budget_tiers

Token budget limits per namespace.

ColumnTypeDescription
idUUIDPrimary key
namespace_idUUIDFK to prompt_namespaces
tier_keyVARCHAR(64)Unique key within namespace
max_tokensINTEGERMaximum token count for prompts in this tier

prompt_templates

Prompt template metadata with a pointer to the active version.

ColumnTypeDescription
idUUIDPrimary key
namespace_idUUIDFK to prompt_namespaces
slugVARCHAR(128)Unique identifier within namespace
budget_tier_idUUIDFK to prompt_budget_tiers (optional)
expected_variablesJSONBVariable definitions for the template
active_version_idUUIDFK to the currently active prompt_version

prompt_versions

Versioned prompt bodies with lifecycle status and validation results.

ColumnTypeDescription
idUUIDPrimary key
template_idUUIDFK to prompt_templates
version_numberINTEGERAuto-incrementing per template
statusVARCHAR(20)draft, pre_production, active, archived
bodyTEXTJinja2 template content
draft_owner_idUUIDOwner (only for drafts; retyped to uuid by agent-config migration 020, R42e)
target_usersTEXT[]Pre-prod per-user pinning list
target_rolesTEXT[]Pre-prod role targeting (migration 021, R42e) — a pre_production version is served when the caller is pinned in target_users OR holds a role overlapping target_roles
validation_resultJSONBFull validation pipeline result
author_idUUIDWho created this version (retyped to uuid by migration 020, R42e)
approved_byUUIDWho approved activation (retyped to uuid by migration 020, R42e)

Partial unique indexes enforce: one draft per user per template, one pre-prod per template, one active per template.

prompt_audit_log

Append-only, HMAC-signed audit trail for all prompt lifecycle events. Triggers prevent UPDATE and DELETE.

ColumnTypeDescription
idUUIDPrimary key
tenant_idUUIDTenant isolation
template_idUUIDFK to prompt_templates
version_idUUIDFK to prompt_versions
actionVARCHAR(30)Lifecycle event type
actor_idVARCHAR(255)Who performed the action. Stays TEXT permanently (R42e) — append-only, HMAC-verified rows are never rewritten; audit-log list responses resolve the actor’s email at read time (actor_resolved, via identity_map)
hmac_signatureVARCHAR(128)HMAC-SHA256 tamper detection

namespace_access_control

Role-based access control per namespace per user.

ColumnTypeDescription
namespace_idUUIDFK to prompt_namespaces
user_idUUIDUser identifier (retyped to uuid by agent-config migration 020, R42e)
roleVARCHAR(20)viewer, author, approver, admin
granted_byVARCHAR(255)Who granted this access

Skills-Based Agent Tables (agent-config-service, R35)

These tables back the R35 skills-based agent architecture. As of R35 Phase 3a the skill-loading source reads themsystem_prompt_node resolves the agent_definitions row by agent_key (= agent_type) via fetch_agent_definition (a direct Postgres read over the orchestration pool) and loads its root_skill_key skill (rule_37rrc_rule37, rule_32rrc_rule32, general → NULL = no task skill). AGENT_DEFAULT_SKILLS is demoted to a fallback that fires only for an unseeded tenant (no row → fetch returns None); a seeded row is authoritative, so there is no double-load. As of P3b prompts are assembled from skill personas + context templates (no longer FALLBACK_PROMPTS), and as of P4 the visible tool list derives from core capabilities + the loaded skills’ llm_visible code blocks (AGENT_TOOLS / get_tools_for_agent deleted; the lone R35-FENCE keeps the hardcoded set for the deferred flaring_monitor / compliance_monitor agents).

skill_personas (008_skill_persona_and_flags.sql)

A persona is the voice/identity for a skill. Either an inline prompt_text or an R29 prompt-template slug (prompt_template_ref) — exactly one of the two (enforced at the app layer).

ColumnTypeDescription
idUUIDPrimary key
skill_idUUIDFK to skill_definitions(id) (the UUID, ON DELETE CASCADE)
persona_keyVARCHAR(128)Unique within skill (UNIQUE (skill_id, persona_key))
display_nameVARCHAR(255)Human-readable name
prompt_textTEXTInline persona prompt (voice/identity only)
prompt_template_refVARCHAR(255)OR an R29 prompt-template slug
is_defaultBOOLEANAt most one default per skill (partial unique index WHERE is_default)
sort_orderINTEGERDisplay ordering

agent_definitions (009_agent_definitions.sql)

Platform/agent records. Seeded dormant in P1 (general, rule_37, rule_32).

ColumnTypeDescription
idUUIDPrimary key
tenant_idUUIDTenant isolation (UNIQUE (tenant_id, agent_key))
agent_keyVARCHAR(128)Agent identifier (e.g. rule_37)
root_skill_keyVARCHAR(128)SLUGskill_definitions.skill_key (NULL = general mode). No FK — it references the slug, not the UUID PK; the slug→UUID lookup happens once at load (orchestration/integrity.py:resolve_skill_uuid). Do not “fix” into a UUID FK.
persona_keyVARCHAR(128)NULL = root skill default, else platform default
model_configJSONBModel preference. Seeded rows no longer pin model_preference (now null), so the tenant Platform Settings default_model governs; an explicitly set per-agent value still overrides
loaded_skillsTEXT[]Carried to honor the 004_skill_schema.sql DO-block contract
is_active / is_systemBOOLEANFlags

New columns on existing skill tables (008)

TableColumnTypeDescription
skill_code_blocksllm_visibleBOOLEAN NOT NULL DEFAULT trueLightweight tool-visibility flag (R35 §11.3)
skill_definitionscontext_modeVARCHAR(20) NOT NULL DEFAULT 'reason_alongside'reason_alongside | compute_and_return (R35 §11.4; isolating runtime deferred to the Sub-Agent release)
skill_definitionsresponse_mode (migration 019)VARCHAR(20) NOT NULL DEFAULT 'llm_synthesis'llm_synthesis | verbatim — the verbatim output contract: the platform renders the skill’s code-block tool results to the user as the turn’s primary response (promoted artifact card); the LLM still sees the result in context but is instructed not to restate it. Success envelopes only — errors stay on the normal synthesis path.

A startup integrity check (orchestration-engine) verifies that every active agent_definition’s root_skill_key / persona_key resolves. It is warn-not-fail in R35 P1 (the rrc_rule37 / rrc_rule32 skills land in P2) and flips to fail-loud via the R35_INTEGRITY_FAIL_LOUD env var.


Skill Router Tables (agent-config-service, 010_skill_routers.sql, R36)

These tables back R36 message-driven skill selection (pull_routers / select_skill). The router layer is a new curated recruitment taxonomy — deliberately not domain_tags (routing-inert display metadata). Multi-homing = multiple skill_router_map rows. Selection payloads are derived reads over these tables — no materialized/compiled router block exists anywhere.

skill_routers

Admin-curated recruitment taxonomy. recruitment_blurb is the only routing-authoritative prose in the system (admin-owned, topic-scoped, never absorbs child skill text). One router level, no recursion. Rows are soft-deactivated (is_active = false), never hard-DELETEd — CRUD enforces this so the MAX(updated_at) manifest-delta watermark cannot miss a change.

ColumnTypeDescription
idUUIDPrimary key
tenant_idUUIDTenant isolation (UNIQUE (tenant_id, router_key))
router_keyVARCHAR(128)Router identifier (e.g. spacing, flaring)
display_nameVARCHAR(255)Human-readable name
recruitment_blurbTEXT NOT NULLThe manifest text the LLM recruits against
is_activeBOOLEANSoft-deactivate flag (no hard delete)
created_at / updated_atTIMESTAMPTZMAX(updated_at) is the manifest-delta watermark

skill_router_map

Router → skill mappings with a promotion state machine. Selection reads join only status = 'approved' rows; admin-authored submissions auto-approve. UNIQUE (router_id, skill_id) keeps one row per pair (multi-homing = multiple pairs); a mapping change re-promotes the row to pending_review in place.

ColumnTypeDescription
idUUIDPrimary key
router_idUUIDFK to skill_routers(id) ON DELETE CASCADE
skill_idUUIDFK to skill_definitions(id) ON DELETE CASCADE
statusVARCHAR(20)draft | pending_review | approved | rejected
submitted_by / reviewed_byUUIDPromotion actors
review_commentTEXTReviewer feedback

skill_description_versions

Author-submitted disambiguation descriptions, append-only — the level-2 payload text the LLM reads to pick a skill. The payload read takes the latest approved version per skill (ORDER BY created_at DESC); approving a new version supersedes the old by recency (no status flip on prior rows), and a pending revision never blocks the currently-approved one.

ColumnTypeDescription
idUUIDPrimary key
skill_idUUIDFK to skill_definitions(id) ON DELETE CASCADE
descriptionTEXT NOT NULLDisambiguation description
statusVARCHAR(20)draft | pending_review | approved | rejected
submitted_by / reviewed_byUUIDPromotion actors

New column on skill_definitions (010)

TableColumnTypeDescription
skill_definitionsversion_check_on_turnBOOLEAN NOT NULL DEFAULT falsetrue = compliance-grade: the loaded-skill version check runs every turn; false = check only at skill-touch (router re-pull). Governance economy, not perf.

Platform Settings Tables (agent-config-service, 016_platform_settings.sql + 017_llm_call_settings.sql)

Tenant-level LLM runtime config plus per-user daily budget overrides — the admin Platform Settings page (/configuration/platform-settings) replaces box env-var edits. All value columns are nullable: NULL = inherit the next tier down (user override → tenant setting → service env default). Like the other agent-config-service migrations, 016/017 self-apply at boot. 017 adds the per-LLM-call knobs (max_output_tokens_per_call, thinking_mode) — the fix for Claude Sonnet 5’s adaptive-thinking-by-default eating a small max_tokens ceiling.

platform_settings

One row per tenant.

ColumnTypeDescription
tenant_idUUIDPrimary key
default_modelTEXTPrimary LLM model (curated LiteLLM id); NULL = env DEFAULT_LLM_MODEL
fallback_modelTEXTOne retry on primary-model errors; NULL = no fallback
max_tokens_per_executionINTEGERPer-execution token budget; NULL = env default
max_cost_usd_per_executionNUMERIC(10,4)Per-execution cost budget; NULL = env default
max_output_tokens_per_callINTEGERPer-LLM-call max_tokens ceiling (thinking + visible output); NULL = env default (migration 017)
thinking_modeTEXTadaptive | disabled, sent explicitly to Anthropic models; NULL = env default (migration 017)
max_tokens_per_dayBIGINTTenant-aggregate daily token cap; NULL = uncapped
max_cost_usd_per_dayNUMERIC(12,4)Tenant-aggregate daily cost cap; NULL = uncapped
updated_byTEXTLast admin to write
created_at / updated_atTIMESTAMPTZTimestamps

user_budget_overrides

Per-user daily caps under the tenant aggregate.

ColumnTypeDescription
tenant_id / user_idUUIDComposite primary key
max_tokens_per_dayBIGINTDaily token cap for this user
max_cost_usd_per_dayNUMERIC(12,4)Daily cost cap for this user
updated_byTEXTLast admin to write
created_at / updated_atTIMESTAMPTZTimestamps

Index: idx_user_budget_overrides_tenant on (tenant_id)

prompt_audit_log changes

Platform-settings mutations are audit-logged to prompt_audit_log, so 016 widens action to VARCHAR(64) and re-creates prompt_audit_log_action_check with the three new actions appended (platform_settings.update, platform_settings.user_override.upsert, platform_settings.user_override.delete). 016 is now the authoritative owner of that CHECK (the 012/013 single-owner lesson); the append-only triggers are untouched.


Conversation Runtime State Tables (016_conversation_runtime_state.sql, R36)

Orchestration-side tables (in infrastructure/docker/postgres/) — the durable home for the R36 sealed prefix + tail-append rules. This is deliberately not a LangGraph checkpointer: messages stay in conversation_messages; graph state stays in-memory per turn. Additive and idempotent; apply manually on existing volumes (numbered migrations are not auto-applied).

conversation_runtime_state

One row per conversation, created at conversation birth. No FK to conversations(id) — that row is upserted at end of turn while this one is born at the start of the first turn.

ColumnTypeDescription
conversation_idVARCHAR(100)Primary key
tenant_idUUID NOT NULLTenant isolation
sealed_prefixTEXT NOT NULLThe index-0 system block exactly as rendered at birth (persona + identity + router manifest). Trigger-enforced immutable — reused byte-for-byte on reopen
router_watermarkTIMESTAMPTZManifest-delta watermark (MAX(skill_routers.updated_at) observed). NULL for agent-mode conversations (no manifest rendered)
rendered_router_keysTEXT[]Router keys the conversation has been shown (frozen manifest + deltas)
loaded_skillsJSONBslug → version map of loaded skills (version pinning + reload-on-cold-resume source)

The trg_sealed_prefix_immutable trigger raises on any UPDATE that changes sealed_prefix — one prefix per conversation, for the life of the conversation.

conversation_context_appends

Ordered, timestamped append-only log (UPDATE/DELETE rejected by trigger, matching the audit_logs house pattern). Every post-birth context change is a tail append; together with the sealed prefix this is the R36 audit property.

ColumnTypeDescription
idUUIDPrimary key
conversation_idVARCHAR(100)Conversation (UNIQUE (conversation_id, seq))
seqINT NOT NULLAppend order
kindVARCHAR(30)router_delta | router_retirement | tombstone | supersession
contentTEXT NOT NULLThe appended notice

Tool-Call Dedup Table (018_tool_call_dedup.sql, R39 P2)

Durable idempotency for MUTATING_TOOLS: tool_node claims (conversation_id, tool_call_id) with INSERT ... ON CONFLICT DO NOTHING before dispatching a mutating tool. Losing the claim means the call already ran (the stored result string is returned byte-identically) or is still running (bounded poll, then a structured duplicate_in_flight error — never a second execution). The claim happens downstream of the HITL gate, so a gate pause writes no row and the approved replay claims as the first execution. Flag: TOOL_DEDUP_ENABLED (default on).

tool_call_dedup

ColumnTypeDescription
conversation_idTEXTPK (with tool_call_id)
tool_call_idTEXTThe LLM-assigned tool call id
tool_nameTEXT NOT NULLThe mutating tool executed
statusTEXTin_flight | done (CHECK-enforced)
resultTEXTThe tool_output string, stored verbatim for replay
created_at / completed_atTIMESTAMPTZClaim / completion times; 30-day retention sweep at boot

Eval Capture Tables (019_eval_capture.sql, R40a)

Expert verdict capture: turn_snapshots freezes the full assembled context of a completed turn (published fire-and-forget to the snapshots:pending Redis stream at turn end; a background writer drains it — the turn path never waits on persistence). eval_cases is the system of record for tester verdicts; Langfuse gets a best-effort score mirror whose failure never fails capture. Snapshots older than 30 days are swept at boot unless referenced by an eval_cases row (promoted snapshots are permanent). Flag: TURN_SNAPSHOTS_ENABLED (default on).

turn_snapshots

ColumnTypeDescription
execution_idTEXTPK — the turn’s id (also the seed of the deterministic Langfuse trace id)
conversation_idTEXTConversation the turn belongs to
tenant_idUUID NOT NULLTenant scope
persona_key / model_idTEXTPersona and model used on the turn
agent_type / agent_idTEXTDriving agent (added by 020_turn_snapshots_agent.sql, R40a hotfix) — lets the R40b replay runner select the agent deterministically. Pre-hotfix rows are NULL; replay skips agent-less cases
loaded_skillsJSONBskill_key → version at turn end
system_promptTEXTAssembled prompt as sent (sealed prefix + tail)
messagesJSONB NOT NULLFull final message list incl. tool-role messages (truncated tail-first with an in-list marker above 1MB)
tool_callsJSONBPer-call {name, input, output} convenience view
final_outputTEXT NOT NULLLast assistant message
payload_bytesINTEGEROriginal (pre-truncation) payload size

eval_cases

ColumnTypeDescription
idUUIDPrimary key
tenant_idUUID NOT NULLTenant scope
conversation_id / execution_idTEXTCapture anchors; UNIQUE (execution_id, captured_by) — a repeat gesture upserts, never duplicates. No hard FK to turn_snapshots
scoreSMALLINT-1 | 1 (CHECK-enforced)
expected_output / note / category_tagTEXTOptional enrichment (sticky across upserts)
captured_byUUID NOT NULLGateway-injected X-User-Id
snapshot_statusTEXTlinked | missing — explicit linkage truth, upgraded by the boot re-link pass
mirror_statusTEXTmirrored | failed | pending — Langfuse mirror outcome, never silent
replay_modeTEXT (generated)frozen when linked, else live — consumed by the R40b runner

Note: turn_snapshots also carries agent_type / agent_id (added by 020_turn_snapshots_agent.sql, R40a hotfix) so the R40b runner can select the driving agent for an expert case.

Eval Runs Tables (021_eval_runs.sql, R40b)

Baseline-able eval runs. A baseline is a tagged, completed run flagged is_baseline — at most one per (tenant, model), enforced by a partial unique index (uq_eval_runs_one_baseline_per_model … WHERE is_baseline), so a model bump gets its own baseline and the regression diff structurally compares like-for-like. The dashboard reads these tables exclusively (never Langfuse).

eval_runs

ColumnTypeDescription
idUUIDPrimary key
tagTEXTHuman label; a baseline is a tagged run
tenant_idUUID NOT NULLTenant scope
model_idTEXT NOT NULLExact resolved model string this run drove
git_shaTEXT NOT NULLSERVICE build SHA (from /health), not the CLI checkout
skill_revisionsJSONB NOT NULL{skill_key: version} registry snapshot
judge_thresholdNUMERICscore ≥ threshold → pass
run_as_user_id / run_as_tenant_idUUID NOT NULLIdentity the replay drove as (§8b; R41 re-scopes)
statusTEXT NOT NULLrunning | completed | aborted
is_baselineBOOLEANBaseline flag; CHECK NOT is_baseline OR status='completed'
n_cases / n_pass / n_fail / n_degradedINTEGERRolled up from eval_case_results
tokens_used / cost_usdBIGINT / NUMERICSummed per run (from ExecuteResponse)
created_at / completed_atTIMESTAMPTZ

eval_case_results

ColumnTypeDescription
idUUIDPrimary key
eval_run_idUUID NOT NULLFK → eval_runs (ON DELETE CASCADE)
case_sourceTEXTpin | expert
case_refTEXTPin id (P-A1) or eval_cases.id; UNIQUE (eval_run_id, case_source, case_ref) — the regression join key
replay_conv_id / replay_exec_idTEXTFresh replay ids (forensics; exec id → trace)
verdictTEXTpass | fail | degraded
graderTEXTpin_check | llm_judge
judge_scoreNUMERICnull for pin_check
violationsJSONBPin violation list, or judge rationale
tokens_used / cost_usdINTEGER / NUMERICPer-case spend

Flaring Authorizations Table (028_flaring_authorizations.sql, F1)

SQL system of record for R-32 flaring authorizations (owned by flaring-monitor). The KG FlaringAuthorization vertex is a write-through projection synced by flaring/authorizations.py on every SQL write; the R41 assessors keep reading the vertex through F1–F3. Migration 028 also normalizes flare_events.well_id/facility_id/authorization_id to TEXT (they hold entity slugs, not UUIDs) and backfills flare_events.authorization_id by the attribution rule: the single approved authorization whose effective→expiration window covers the event start and whose scope covers the event’s well — 0 or >1 candidates leave it NULL (un-attributed volume = unauthorized flaring).

flaring_authorizations

ColumnTypeNotes
idUUIDPrimary key
tenant_idUUIDNOT NULL
entity_idTEXTUNIQUE — the fa-… slug (KG vertex identity)
authorization_numberTEXTe.g. FL-2024-08821; UNIQUE (tenant_id, authorization_number)
authorization_typeTEXTinitial | renewal
statusTEXTdraft | filed | approved | expired | denied
well_id / lease_idTEXTScope — well- or lease-level (slugs)
operator_idTEXTNOT NULL
filed_date / effective_date / expiration_dateDATEexpiration_date NOT NULL
max_volume_mcf_per_dayNUMERICDaily cap
authorized_volume_mcfNUMERICTotal period cap (nullable)
authorized_daysINTEGER180-day style cap
period_start / period_endDATEVolume-cap window (feeds calculate_burn_rate)
reason / infrastructure_timelineTEXTNarrative fields mirrored to the vertex

Event Number Sequences (030_event_number_sequences_reconcile.sql)

The event-numbering split, reconciled after a long-standing migration collision: migration 004 created event_number_sequences keyed by the platform event_type_enum, 006 created custom_event_number_sequences keyed by an event_type_id UUID, and 010 tried to RENAME the custom table over the platform one — which errors on every ordered application (and failed silently in tolerant psql mode). The two consumers in flaring/event_number.py need mutually exclusive shapes, so the contract from 030 on is two tables:

TableKeyed byPurpose
event_number_sequences(tenant_id, event_type, year) — the platform event_type_enumPer-year numbering for platform events
custom_event_number_sequences(tenant_id, event_type_id, year) — UUID FK → event_type_definitions(id)Per-year numbering for custom events

010’s rename statement is tombstoned; 030 converges every historical shape (004-first survivor, rename-succeeded, zombie re-created 006 tables, missing tables) and is a no-op where flaring’s schema is absent entirely.


Identity Normalization (031_identity_normalization.sql, R42e)

R42e makes user identity uuid end-to-end with DB-level foreign keys. Migration 031 (applied manually on existing volumes, safe to re-apply) does three things:

  1. Seeds the system users — see the users table above for the four non-loginable accounts (system@ = nil UUID, legacy@, eval-runner@, demo-seed@).
  2. Retypes VARCHAR/TEXT identity columns to uuid via a convergent UPDATE (castable-and-exists → kept; identity_map hit → mapped; else → legacy@aegis.local) followed by a guarded ALTER TYPE.
  3. Adds FKs → users(id) ON DELETE RESTRICTNOT VALID first, then VALIDATE — on ~17 core columns: conversations.user_id, conversation_messages.user_id, conversation_attachments.user_id, episodic_memories.user_id, approval_requests.reviewer_id, filing_checklists.created_by, ontology_versions.created_by, projects.owner_user_id, eval_cases.captured_by, eval_runs.run_as_user_id, and the operational-event created_by / reviewed_by columns (operational_events, event_type_definitions, guard/duplication/detection-rule tables).

audit_logs.actor_id and prompt_audit_log.actor_id are deliberately not touched — append-only, hash-chained history is never rewritten; those actors resolve at read time through identity_map. This is the permanent design, not a transition state. FKs reference users(id) only — never roles/user_roles (the boot-order rule). The agent-config-owned tables are normalized by that service’s own self-applying migration 020; users.roles is dropped by auth-service’s boot runner after its backfill.

identity_map

ColumnTypeNotes
legacy_idTEXTPrimary key — a historical identity string (system, system-seed, demo-seed, old tenant-UUID strings, …)
user_idUUIDNOT NULL REFERENCES users(id) ON DELETE RESTRICT
sourceTEXTWhere the mapping came from (e.g. seed)

Used both by the retype backfills above and by read-time resolution of append-only actor columns. auth-service re-converges the seeded rows on every boot.


Connector Tables (connector-service, R44a)

Owned by connector-service’s boot-time migration runner (services/connector-service/src/connector_service/migrations/001_connector_catalog.sql, self-applied on every boot — auth-service pattern, no applied-tracking; guarded by ci/connector_double_boot.sh).

integration_connectors

The external data source catalog. One row per registered connector; secret material never lands here — credential_ref is a secret-store reference only.

ColumnTypeNotes
idUUIDPrimary key
tenant_idUUIDUNIQUE (tenant_id, connector_key)
connector_keyVARCHAR(128)Stable lowercase slug — becomes part of the secret name and later (R44c) tool names
connector_typeTEXTpostgres | snowflake (CHECK)
configJSONBNon-secret, typed per engine (postgres: host/port/database/sslmode; snowflake: account/warehouse/database/schema/role)
credential_refTEXTSecret-store ref ONLY (gcp://... / dev://...); never material
statusTEXTunconfigured | probing | active | probe_failed | disabled (CHECK)
read_only_verified_atTIMESTAMPTZSet by a passing probe; cleared on credential/destination change
last_probeJSONB{at, ok, checks, error, remediation} — no secret material
data_classificationTEXTConnector-level classification floor for exposures (R44b), default internal
created_byUUIDRegistering admin

connector_schema_snapshots

Discovery snapshots (is_current flag; superseded rows retained). snapshot is {schemas: [{name, tables: [{name, columns, approx_rows}]}], truncated, truncation_reason}, size-guarded (schema cap 50 / 2 MB byte cap — degrades loudly, never silently).

connector_execution_log

Governance trail for R44b previews and R44c executions, created now so the first execution ever run has its audit row. params_hash is a SHA-256 over canonical params JSON — parameter values are never logged. status is preview | ok | truncated | error | denied; error_class is typed (no message bodies). connector_tag_mappings is reserved by name only.

connector_exposures

First-class, connector-scoped, parameterized SELECT queries (R44b, migration 002). Approve once, bind to many skills (R44c). UNIQUE (connector_id, exposure_key); ON DELETE CASCADE from integration_connectors.

ColumnTypeNotes
idUUIDPrimary key
connector_idUUIDFK → integration_connectors (CASCADE)
exposure_keyVARCHAR(128)Stable slug; the R44c tool name derives from it
descriptionTEXTBecomes the LLM tool description (R44c) — written for the model
sql_textTEXTThe parameterized read; validated structurally at every write
sql_hashTEXTsha256 of the raw exact sql_text (no canonicalization)
dialectTEXTpostgres | snowflake — derived from the connector engine
paramsJSONB[{name, type, required, default, description}]
row_cap / byte_cap / timeout_sINTExecution caps (1–1000 / 1 KB–4 MB / 1–30 s)
data_classificationTEXTNULL inherits the connector floor; never resolves below it
review_statusTEXTdraft | pending_review | approved | rejected | retired (CHECK)
approved_sql_hashTEXTThe pinned hash — R44c execute verifies sql_hash == approved_sql_hash; any content edit reverts to draft and clears this
proposed_by / approved_byUUIDAuthor / approver

Key Source Files

FilePurpose
infrastructure/docker/postgres/init.sqlCore table definitions
infrastructure/docker/postgres/002_checklist_compliance_tables.sqlChecklist, compliance, and rule tables
infrastructure/docker/postgres/007_entity_type_definitions.sqlEntity type system tables
infrastructure/docker/postgres/00-create-extension-age.sqlAGE extension setup
services/agent-config-service/src/agent_config/migrations/001_initial_schema.sqlPrompt management tables
services/agent-config-service/src/agent_config/migrations/008_skill_persona_and_flags.sqlR35: skill_personas, llm_visible, context_mode
services/agent-config-service/src/agent_config/migrations/009_agent_definitions.sqlR35: agent_definitions table
services/agent-config-service/src/agent_config/migrations/010_skill_routers.sqlR36: skill_routers, skill_router_map, skill_description_versions, version_check_on_turn
services/agent-config-service/src/agent_config/migrations/016_platform_settings.sqlPlatform Settings: platform_settings, user_budget_overrides, prompt_audit_log.action widening
infrastructure/docker/postgres/016_conversation_runtime_state.sqlR36: conversation_runtime_state (sealed prefix), conversation_context_appends
infrastructure/docker/postgres/018_tool_call_dedup.sqlR39 P2: tool_call_dedup (idempotent authoring writes)
infrastructure/docker/postgres/019_eval_capture.sqlR40a: turn_snapshots + eval_cases (expert verdict capture)
infrastructure/docker/postgres/030_event_number_sequences_reconcile.sqlEvent-numbering split: platform vs custom sequence tables, 010 rename tombstoned
infrastructure/docker/postgres/031_identity_normalization.sqlR42e: system users, identity_map, uuid retypes + FKs → users(id)
services/agent-config-service/src/agent_config/migrations/020_identity_normalization.sqlR42e: uuid retypes on agent-config-owned identity columns
services/agent-config-service/src/agent_config/migrations/021_prompt_target_roles.sqlR42e: prompt_versions.target_roles (role-based pre-prod targeting)
services/connector-service/src/connector_service/migrations/001_connector_catalog.sqlR44a: integration_connectors, connector_schema_snapshots, connector_execution_log
shared/src/aegis_shared/db/postgres.pyAsyncPG connection pool helpers
Last updated on