Skip to Content

Shared Models

The AEGIS shared library at shared/src/aegis_shared/ provides Pydantic v2 models, database helpers, and utilities used across all Python services. Every service depends on this library via a Poetry path dependency.

Location and Structure

shared/ ├── pyproject.toml # Library metadata and dependencies └── src/ └── aegis_shared/ ├── __init__.py ├── models/ │ ├── __init__.py # Re-exports all public models │ ├── common.py # AegisBase, AegisEntity, TenantEntity, enums │ ├── oilgas.py # Oil & gas domain entities │ ├── agent.py # Agent config, state, messages │ ├── compliance.py # Compliance status and matrix models │ ├── checklist.py # Filing checklist workflow models │ ├── rules.py # Rule versioning and lifecycle models │ ├── entity_resolution.py # ResolvedEntity + MatchedOn (R34 entity resolution) │ ├── events.py # Operational event system models │ └── event_types.py # Custom event type builder models └── db/ ├── postgres.py # PostgresPool (asyncpg wrapper) ├── redis.py # RedisManager (async Redis wrapper) └── kafka.py # Kafka producer manager

Base Classes (common.py)

All models derive from one of three base classes:

AegisBase

The root base class for all Pydantic models. Provides common configuration:

class AegisBase(BaseModel): model_config = ConfigDict( from_attributes=True, # Allow creating from ORM objects / dicts populate_by_name=True, # Allow field aliases str_strip_whitespace=True, # Auto-strip string whitespace )

Use AegisBase for:

  • API request/response models
  • Value objects and DTOs
  • Any model that does not need an id or timestamps

AegisEntity

For persistent entities that need a unique identifier and timestamps:

class AegisEntity(AegisBase): id: UUID = Field(default_factory=uuid4) created_at: datetime = Field(default_factory=datetime.utcnow) updated_at: datetime = Field(default_factory=datetime.utcnow)

TenantEntity

For entities scoped to a specific tenant (multi-tenancy support):

class TenantEntity(AegisEntity): tenant_id: str

Most domain entities (wells, leases, operators, etc.) extend TenantEntity.

Shared Enums (common.py)

The common module defines core enums used across multiple services:

EnumValuesUsed By
AgentTyperule_37, rule_32, compliance_monitor, flaring_monitorOrchestration engine, agent configs
ExecutionStatuspending, running, awaiting_hitl, completed, failed, cancelledOrchestration engine, approval service
ApprovalStatuspending, approved, rejected, modifiedApproval service
HITLCheckpointTypepre_filing, data_validation, cost_threshold, regulatory_submission, exception_requestApproval service, orchestration engine

Model Files

oilgas.py — Oil and Gas Domain Entities

The largest model file, containing all RRC regulatory domain entities:

ModelParentKey Fields
OperatorTenantEntityname, rrc_operator_id, p5_number
FieldTenantEntityname, rrc_field_id, district, county
FormationTenantEntityname, depth_top_ft, depth_base_ft
LeaseTenantEntityname, rrc_lease_id, operator_id, field_id
WellTenantEntityapi_number, well_name, well_type, status, spacing distances, production data
PermitTenantEntitypermit_number, permit_type, status, Rule 37 exception details
RegulationAegisBaserule_id, title, requirements, related_forms
HearingTenantEntitydocket_number, hearing_type, status, decision details
FilingTenantEntityfiling_type, form_number, status, HITL review data
EquipmentTenantEntityequipment_type, name, capacity, well/lease associations
FlaringAuthorizationTenantEntityauthorization_number, max_volume_mcf_per_day, expiration_date
FlaringEventTenantEntityevent_type, cause_category, volumes, repair obligation, RRC/EPA reporting
WellpadTenantEntityname, pad_id, location
FacilityTenantEntityname, facility_type, capacity
PipelineRouteTenantEntityname, diameter_inches, length_miles, from/to facility
InfrastructureProjectTenantEntityproject_type, name, timeline, gas capture estimates

Domain-specific enums include WellStatus, WellType, PermitStatus, HearingStatus, FilingStatus, FlaringDispositionCode, EquipmentType, FacilityType, ProjectType, and flare event enums (FlareEventType, FlareEventCauseCategory, FlareEventSource, VolumeSource, RRCReportStatus).

agent.py — Agent Configuration and State

ModelParentPurpose
SkillManifestAegisBaseLightweight skill descriptor (id, name, triggers, domain tags)
HITLPolicyAegisBaseWhen HITL approval is required (checkpoint type, reviewer strategy)
BudgetConfigAegisBaseToken and cost limits per execution and per day
AgentConfigAegisBaseFull agent definition (system prompt, skills, HITL policies, budget)
MessageAegisBaseSingle conversation message (role, content, tool calls)
HITLCheckpointAegisBasePending approval checkpoint (state snapshot, reviewer info)
AgentStateAegisBaseCore state flowing through LangGraph (messages, injected context, active skills, budget tracking)

compliance.py — Compliance Dashboard

ModelParentPurpose
ComplianceStatusAegisEntitySingle entity x domain compliance record
ComplianceSummaryAegisBaseDashboard summary card counts (overdue, due soon, anomalies)
ComplianceMatrixRowAegisBaseOne row in the entity x domain matrix
ComplianceMatrixResponseAegisBasePaginated matrix response
DeadlineChartEntryAegisBaseDeadline bar chart data point
ComplianceTrendEntryAegisBaseCompliance trend line data point
FilingStatusEntryAegisBaseFiling status donut chart data point
FlaringChartEntryAegisBaseFlaring volume vs authorization chart data point

Enums: ComplianceDomain (rule_37, rule_32, form_pr, flaring_monitor, epa_oooo), ComplianceStatusCode (compliant, action_needed, overdue, not_applicable, in_review).

checklist.py — Filing Checklist Workflow

ModelParentPurpose
ChecklistItemDefinitionAegisBaseItem template (name, type, completion method, agent/user roles)
ChecklistTemplateAegisEntityTemplate for a compliance domain’s checklist
ChecklistItemStateAegisBaseCurrent state of a checklist item (status, summary, data)
FilingChecklistAegisEntityChecklist instance for entity + domain
ChecklistArtifactAegisBaseGenerated document or file linked to a checklist item
CreateChecklistRequestAegisBaseAPI request to create a checklist
UpdateChecklistItemRequestAegisBaseAPI request to update an item
SubmitForReviewRequestAegisBaseAPI request to submit for HITL review
CreateArtifactRequestAegisBaseAPI request to create an artifact

Enums: ChecklistStatus, ChecklistItemStatus, ChecklistItemType, CompletionMethod, ArtifactType, GeneratedBy.

rules.py — Rule Versioning

ModelParentPurpose
RuleVersionAegisEntityImmutable versioned rule (rule data, effective date, source)
FilingRuleSnapshotAegisBaseFrozen copy of a rule at filing initiation
RuleChangeAlertAegisBaseAlert for rule changes affecting in-flight filings
CreateRuleVersionRequestAegisBaseAPI request to create a rule version
AcknowledgeRuleChangeRequestAegisBaseAPI request to acknowledge a rule change

Enums: RuleType (statewide, field_specific, notice), RuleDomain (spacing, density, flaring, reporting, environmental), RuleStatus, RuleSource.

events.py — Operational Events

ModelParentPurpose
OperationalEventTenantEntityUnified event record for all 5 MVP event types
DuplicationRuleTenantEntityDuplication prevention rules per event type
DuplicationCheckResultAegisBaseResult of the duplication rules engine check

Enums: EventType (flare_event, production_interruption, equipment_failure, spill_release, permit_exceedance, custom), Severity, EventStatus, SourceType, DupRuleType, DupAction.

event_types.py — Custom Event Type Builder

ModelParentPurpose
EventTypeDefinitionTenantEntityEvent type with lifecycle management (draft/preview/active/inactive/archived)
EventTypeFieldDefinitionAegisEntityA field within an event type form
ConditionalRuleAegisEntityShow/hide logic for fields
GuardRuleAegisEntitySubmission guard rule with versioning
GuardRuleVersionAegisBaseVersioned snapshot of a guard rule’s conditions

Database Helpers (db/)

PostgresPool

Wraps asyncpg with connection pool management:

from aegis_shared.db.postgres import PostgresPool pg = PostgresPool(dsn="postgresql://aegis:aegis_local@localhost:5432/aegis") await pg.connect() # Convenience methods row = await pg.fetchrow("SELECT * FROM agents WHERE id = $1", agent_id) rows = await pg.fetch("SELECT * FROM compliance_status WHERE tenant_id = $1", tenant_id) await pg.execute("INSERT INTO audit_logs (id, event_type) VALUES ($1, $2)", log_id, event_type) # Direct connection access async with pg.acquire() as conn: rows = await conn.fetch("SELECT * FROM agents") await pg.disconnect()

RedisManager

Wraps redis.asyncio with key-value and injection ledger helpers:

from aegis_shared.db.redis import RedisManager rm = RedisManager(url="redis://localhost:6379") await rm.connect() # Key-value operations await rm.set("key", "value", ex=3600) # with TTL val = await rm.get("key") await rm.delete("key") # Injection ledger (Redis Hash at skill:ledger:{conversation_id}) await rm.ledger_mark("conv-1", "skill:spacing-calc", "1") has = await rm.ledger_has("conv-1", "skill:spacing-calc") # True items = await rm.ledger_get_all("conv-1") # {"skill:spacing-calc": "1"} await rm.disconnect()

How to Add New Models

Step 1: Choose the Right File

  • Oil and gas domain entities: oilgas.py
  • Agent-related models: agent.py
  • Compliance dashboard models: compliance.py
  • Checklist/filing workflow: checklist.py
  • Regulatory rules: rules.py
  • Entity-resolution results: entity_resolution.py
  • Operational events: events.py
  • Event type definitions: event_types.py
  • Core enums/base classes: common.py
  • Entirely new domain: create a new file

Step 2: Define the Model

Choose the appropriate base class:

# For a request/response DTO class MyRequest(AegisBase): entity_id: str action: str # For a persistent entity without tenant scope class MyEntity(AegisEntity): name: str status: str = "active" # For a tenant-scoped persistent entity (most domain objects) class MyDomainEntity(TenantEntity): name: str entity_type: str data: dict[str, Any] = Field(default_factory=dict)

Step 3: Follow Pydantic v2 Conventions

from enum import StrEnum from datetime import date, datetime from typing import Any from uuid import UUID from pydantic import Field as PydanticField from aegis_shared.models.common import AegisBase, TenantEntity class MyStatus(StrEnum): ACTIVE = "active" INACTIVE = "inactive" ARCHIVED = "archived" class MyEntity(TenantEntity): # Required fields name: str entity_type: str # Optional fields with None default description: str | None = None parent_id: str | None = None # Enum fields with default status: MyStatus = MyStatus.ACTIVE # Date fields effective_date: date | None = None expires_at: datetime | None = None # Collections -- always use Field(default_factory=...) tags: list[str] = PydanticField(default_factory=list) metadata: dict[str, Any] = PydanticField(default_factory=dict) # Numeric fields score: float | None = None count: int = 0

When the parent class defines a Field import from Pydantic and your model file also needs it, use an alias to avoid shadowing: from pydantic import Field as PydanticField. This pattern is already used in oilgas.py and events.py.

Step 4: Export from init.py

Add your new models to shared/src/aegis_shared/models/__init__.py:

from aegis_shared.models.my_module import MyEntity, MyStatus __all__ = [ # ... existing exports ... "MyEntity", "MyStatus", ]

This allows services to import directly from the top-level package:

from aegis_shared.models import MyEntity, MyStatus

Step 5: Re-install in Dependent Services

After modifying the shared library, re-install it in any service that uses it:

cd services/orchestration-engine poetry install

Since the shared library is installed with develop = true, Python will use the live source code. However, Poetry needs to know about new dependencies if you added any to the shared pyproject.toml.

Design Principles

  1. Models are immutable representations — they describe data shape, not behavior. Business logic belongs in service modules, not model methods.

  2. Rule versions are never updated — create a new version instead. This is enforced by the RuleVersion model design and database constraints.

  3. Use StrEnum for all enumerations — this ensures JSON serialization produces readable strings, not integer codes.

  4. Prefer explicit fields over inheritance — AEGIS models use flat field definitions rather than deep inheritance hierarchies. AegisBase -> AegisEntity -> TenantEntity is the deepest chain.

  5. Request/response models are separate from domain modelsCreateChecklistRequest is not the same as FilingChecklist. API models may have fewer fields, different validation, or different defaults.

  6. The __init__.py is the public API — services should import from aegis_shared.models, not from individual files. This allows internal reorganization without breaking imports.

Last updated on