Skip to content
GitHub

Architecture

Internal design of the lexigram-ai-governance package.


lexigram-ai-governance provides AI governance policies that gate which LLM requests are allowed, denied, or throttled based on budget, rate, model, content, and data-classification rules.

flowchart TB
    App[Application Layer<br/>AI Agent · Pipeline · Chat]
    Gov[Governance<br/>Policy Engine · BudgetTracker<br/>ContentPolicyService]
    LLM[LLM Provider<br/>OpenAI · Anthropic · etc.]
    Audit[Audit Store<br/>InMemory · Database]
    Persist[Persistence<br/>InMemory · Redis · Database]
    Events[Event Bus<br/>BudgetAlertEvent · PolicyEvaluatedEvent]

    App -->|check_request| Gov
    Gov -->|evaluate policies| Gov
    Gov -->|record / query| Persist
    Gov -->|emit| Events
    Gov -->|record| Audit
    App -->|if ALLOW| LLM

Import direction: Application code depends on AIGovernanceProtocol from lexigram-contracts. The governance package implements that contract. No other governance package imports from the application layer.


Policies are declarative rules composed of scope-constrained conditions evaluated in priority order.

flowchart LR
    subgraph Store[PolicyStore]
        P1[Policy: cost-guard<br/>priority: 10]
        P2[Policy: model-blocklist<br/>priority: 20]
    end

    subgraph Engine[PolicyEngine]
        Eval[Evaluate enabled policies<br/>sorted by priority]
        Match{Match rule?}
        Deny[Return Err PolicyViolation]
        Allow[Return Ok PolicyDecision]
        Eval -->|next policy| Match
        Match -->|yes + effect=DENY| Deny
        Match -->|yes + effect=ALLOW| Allow
        Match -->|no rule matches| Allow
    end

    subgraph Types[Domain Types]
        Rule[PolicyRule<br/>scope · effect · condition · roles]
        Ctx[GovernanceContext<br/>model · role · cost · classification]
    end

    Ctx --> Engine
    Store --> Engine
    Deny --> Dec[PolicyDecision<br/>allowed · matched_policy · reason]
    Allow --> Dec
ScopeCondition KeysExample
MODELmodel_pattern (glob){"model_pattern": "gpt-4*"}
COSTmax_cost{"max_cost": 0.50}
GUARDRAILrequired (list){"required": ["pii_filter"]}
DATA_CLASSIFICATIONclassification{"classification": "pii"}

Evaluation: Load enabled policies sorted by priority. For each, iterate rules (skip if roles doesn’t match). First DENY match short-circuits → Err(PolicyViolation). No DENY → Ok(PolicyDecision(allowed=True)).


Governance checks fire at two points before an LLM call: request-level (model access / rate limits) and budget-level (per-request cap + monthly spend). Content gating is a third layer via ContentPolicyService + CompositeGate.

sequenceDiagram
    participant Caller as AI Pipeline
    participant Gov as AIGovernanceManager
    participant Persist as GovernancePersistence
    participant Audit as AIAuditStore

    Caller->>Gov: check_request(model, provider, user_id)
    Gov->>Gov: restricted_models + allowlist/denylist
    alt Blocked by model policy
        Gov-->>Caller: False
    else Model allowed
        Gov->>Persist: incr_requests(key, 60s)
        Persist-->>Gov: RPM count
        alt RPM exceeded
            Gov-->>Caller: False
        else RPM OK
            Gov-->>Caller: True
        end
    end

    Caller->>Gov: check_request_budget(est_cost)
    Gov->>Gov: per-request cap?
    alt Over cap
        Gov-->>Caller: Err(GovernanceError)
    else Within cap
        Gov->>Persist: get_spend(month_key)
        Persist-->>Gov: monthly spend
        alt Budget exceeded
            Gov-->>Caller: Err(GovernanceError)
        else Within budget
            Gov-->>Caller: Ok(None)
        end
    end
    Gov-)Audit: record decision (async)

sequenceDiagram
    participant Container as DI Container
    participant Prov as GovernanceProvider
    participant Config as GovernanceConfig
    participant Mgr as AIGovernanceManager

    Container->>Prov: register(container)
    Prov->>Container: singleton(GovernanceConfig, config)
    Prov->>Container: singleton(AIGovernanceManager)
    Prov-->>Container: done

    Container->>Prov: boot(container)
    Prov->>Prov: (no-op — in-process domain provider)
    Prov-->>Container: ready

    Container->>Mgr: resolve AIGovernanceManager
    Mgr->>Mgr: persist = InMemory | Redis | Database
    Mgr-->>Container: ready for calls

    Note over Container,Mgr: Runtime — check_request, check_budget, track_cost

    Container->>Prov: shutdown()
    Prov-->>Container: done

GovernanceProvider (priority DOMAIN) registers GovernanceConfig + AIGovernanceManager as singletons. The manager auto-selects persistence: explicit persistence= → use it; cache= (implements CacheBackendProtocol) → RedisGovernancePersistence; neither → InMemoryGovernancePersistence.


Contract SymbolSourceRole
AIGovernanceProtocollexigram.contracts.ai.governancePrimary service contract for check_request, check_budget, track_cost, reload_config
CostTrackingProtocollexigram.contracts.ai.governanceCost recording (track_cost)
AIAuditStoreProtocollexigram.contracts.ai.governanceAudit event persistence (record, query, aggregate)
GovernanceErrorlexigram.contracts.ai.governanceBase domain exception
BudgetExceededErrorlexigram.contracts.ai.governanceMonthly spend cap breached
CacheBackendProtocollexigram.contracts.infra.cacheDistributed counter/spend storage (optional)
DatabaseProviderProtocollexigram.contracts.dataSQL-backed persistence (optional)
EventBusProtocollexigram.contracts.eventsBudget alert emission (optional)
ContainerRegistrarProtocollexigram.contracts.core.diProvider registration
ContainerResolverProtocollexigram.contracts.core.diProvider boot-time resolution

PointMechanismExample
Custom policy rulePolicyScope enum + PolicyRule conditionAdd a JURISDICTION scope
Custom policy storeImplement PolicyStore-like CRUDDatabase-backed policy storage
Custom persistenceImplement GovernancePersistence protocolS3-backed spend counters
Custom content gateImplement ContentPolicyGateProtocolAbuse detection gate
Custom audit storeImplement AIAuditStore protocolElasticsearch audit sink
Policy observerImplement PolicyObserverProtocolMetrics counter on every evaluation
Budget alert handlerSubscribe to BudgetAlertEvent via EventBusProtocolPagerDuty at 90% spend
Hot-reload configCall AIGovernanceManager.reload_config()Runtime policy change without restart
Composite gate compositionAdd gates to CompositeGate(gates=[...])Abuse + quota + jurisdiction