Tramai Logo
Tramai

Sovereign Mode

Sovereign Mode is a secure-by-default composition wrapper that wires the policy engine, model registry, audit store, DLP, approval workflows, and artifact verification into a single fail-fast SovereignTramai runtime. It replaces ad-hoc security wiring with an opinionated, validated builder that catches misconfiguration at build time rather than runtime.

Module: dev.tramai:tramai-sovereign (aggregator, depends on tramai-standalone + tramai-security)


What

SovereignTramai wraps Tramai (from tramai-standalone) with mandatory security configuration. Every builder input is validated at build time — missing models, unregistered providers, missing trust zones, and cross-zone routing violations all throw before any runtime code executes.

What It Includes

FeatureHow Sovereign Enables It
Policy enforcementPolicyConfiguration.secure() deny-by-default is wired automatically. Every provider, model, tool, and permission must be explicitly allowed.
Model registryModelRegistry SPI is mandatory and always enabled (non-disableable). Builder validates every allowed model has a primary route.
Audit trailAuditEngine with SHA-256 hash-chained events is wired automatically via AuditEnginePolicyDecisionAuditEmitter.
DLPOptional .dlp(interceptor) — wires DlpInterceptor into the standalone builder with optional .dlpRedactionAudit(emitter).
Approval workflowsOptional .approvalGateCoordinator(coordinator) with lifecycle audit via AuditEngineApprovalLifecycleAuditEmitter.
Artifact verificationOptional .modelArtifactVerifier(verifier) — verified at build time; receipts accessible via verificationReceipts().
Evidence packs.evidencePack() generates deterministic SovereignEvidencePackV1 with audit chain, verification receipts, and optional sub-sections.
Offline deploymentSovereignDeploymentMode.OFFLINE rejects any non-LOCAL provider at build time.

Security Invariants

The sovereign builder enforces these invariants:

  1. checkNotNull for required inputsSovereignProfileConfiguration, ModelRegistry, and AuditStore are all required; missing any one throws IllegalStateException at build time.
  2. Init validation on configSovereignProfileConfiguration.init rejects blanks, wildcards (^*+$), empty allowedModels/allowedProviders, providers without trust zones, and fallback providers not in allowedProviders.
  3. .secure().copy() patterntoPolicyConfiguration() starts from PolicyConfiguration.secure() (all sets empty = deny-all) and overlays only explicitly allowed entries. No wildcard bypass.
  4. Forced-enabled featuresModelRegistrySettings(enabled = true) and classification-aware ProviderRoutingConfiguration(enabled = true) are always set.
  5. BEFORE_WORKFLOW_RESUME is allowed by policy — resume authorization is enforced by the ApprovalGateCoordinator, not the policy engine.

When to Use

Use Sovereign Mode when you need:

  • A hard security boundary — every model, provider, tool, and permission must be explicitly allowed in the profile
  • Fail-fast configuration — provider/route mismatches are caught at build(), not at model invocation time
  • Audit-grade policy decisions — every Allow/Deny is recorded in a SHA-256 hash-chained event stream
  • Trust-zone enforcement — classify each provider as LOCAL, EU_CLOUD, or GLOBAL_CLOUD and enforce data-classification routing
  • Air-gapped deployments — use SovereignDeploymentMode.OFFLINE to reject any non-local provider
  • Multi-tenant platforms — each tenant gets its own isolated sovereign runtime with independent allowlists

Do not use Sovereign Mode for prototyping or scripting — use Tramai.builder() from tramai-standalone instead.


Quickstart

// 1. Define the sovereign profile
val profile = SovereignProfileConfiguration(
    allowedModels = setOf("llama3.2"),
    allowedProviders = setOf("ollama"),
    allowedFallbackProviders = emptySet(),
    allowedTools = emptySet(),
    allowedPermissions = emptySet(),
    providerZones = mapOf("ollama" to ProviderTrustZone.LOCAL),
    deploymentMode = SovereignDeploymentMode.STANDARD,
)

// 2. Build the sovereign runtime
val tramai = SovereignTramai.builder()
    .profile(profile)
    .modelRegistry(modelRegistry)
    .auditStore(auditStore)
    .provider(ollamaProvider, name = "ollama", default = true)
    .model("llama3.2", "ollama")
    .build()

// 3. Use like a normal Tramai instance
val service = tramai.create<MyService>()

Builder Requirements

The builder enforces these inputs at build time:

InputRequiredValidated
SovereignProfileConfigurationYesBlanks, wildcards, missing trust zones, empty allowlists
ModelRegistryYesEvery allowed model must have an approved model entry
AuditStoreYesHash-chained audit events emitted for every policy decision
At least one providerYesMust be registered via .provider()
Provider trust zonesYesEvery allowed provider must have an entry in profile.providerZones

Builder API Reference

Required Methods

fun profile(configuration: SovereignProfileConfiguration): Builder
fun modelRegistry(registry: ModelRegistry): Builder
fun auditStore(store: AuditStore): Builder
fun provider(
    provider: ModelProvider,
    name: String = provider.providerId(),
    default: Boolean = false,
): Builder
fun model(modelName: String, providerName: String): Builder

Provider Registration

The .provider() method validates:

  • Provider name must not be blank
  • Provider name must not have surrounding whitespace
  • Provider name must not be a duplicate

Model Registration

The .model() method maps a logical model name to a registered provider. Every model in allowedModels must have a primary route.

Fallback Routes

fun fallbackModel(
    requestedModelName: String,
    fallbackModelName: String,
    providerName: String,
): Builder

fun fallbackProvider(
    modelName: String,
    providerName: String,
): Builder  // convenience: fallbackModel with same model name

Fallback providers must be in allowedFallbackProviders, which must be a subset of allowedProviders.

Default Provider

fun defaultProvider(providerName: String): Builder

Overrides the default flag on a previously registered provider. Must be in allowedProviders.

Optional Features

.dlp(interceptor)                                          // DLP
.dlpRedactionAudit(emitter)                                // DLP audit
.approvalGateCoordinator(coordinator)                      // Approval workflows
.approvalContinuationStore(continuationStore)              // Approval persistence
.suspendedInvocationStore(invocationStore)                 // Suspension persistence
.toolArgumentsDigester(digester)                           // Approval argument hashing
.modelArtifactVerifier(verifier)                           // Artifact verification
.modelArtifactVerificationSettings(settings)               // Verification settings
.cache(cache)                                              // Response caching
.circuitBreaker(settings)                                  // Resilience
.retryPolicy(settings)                                     // Retry policy
.tokenBudget(settings)                                     // Token budget
.observer(observer)                                        // Observability
.interceptor(interceptor)                                  // Operation interceptors
.engineEventObserver(eventObserver)                        // Engine events
.toolResultFiltering(settings)                             // Tool result filtering
.clock(clock)                                              // Custom clock

Build-Time Validation

The sovereign builder performs fail-fast validation before any runtime code runs. Validation order:

  1. Required inputscheckNotNull for profile, modelRegistry, auditStore
  2. Registered providers — at least one must be registered
  3. Cross-reference — every registered provider must be in allowedProviders and vice versa
  4. Trust zones — every registered provider must have a zone in providerZones
  5. Model routes — every allowed model must have a primary route
  6. Primary route targets — every route targets a registered, allowed provider
  7. Fallback routes — source and target models are allowed, target provider is registered and in allowedFallbackProviders
  8. Default provider — registered and in allowedProviders
  9. Offline deployment — all providers/routes are LOCAL (runs before registry lookup)
  10. Artifact verification — manifests are resolved and verified against local model files

Error messages use safe-code identifiers for deterministic integration testing:

  • "offline-profile-non-local-provider-rejected"
  • "artifact-approved-model-lookup-failed"
  • "artifact-digest-required-for-local-model"

Provider Trust Zones

Each provider is classified into a trust zone. The zones are enforced by the policy engine during provider routing:

ZoneMeaning
ProviderTrustZone.LOCALSame-machine or local-network provider (Ollama, vLLM, llama.cpp)
ProviderTrustZone.EU_CLOUDEU-hosted cloud provider (GDPR-aligned)
ProviderTrustZone.GLOBAL_CLOUDGlobal cloud provider (standard SaaS)

Classification-aware routing is always enabled in sovereign mode via ProviderRoutingConfiguration.sovereignDefaults():

ClassificationAllowed ZonesFallback Zones
RESTRICTEDLOCAL onlyNone (no fallback)
CONFIDENTIALLOCAL, EU_CLOUDLOCAL, EU_CLOUD
INTERNALAny zoneAny zone
PUBLICAny zoneAny zone

Hash-Chained Audit

The AuditEngine is wired automatically and records every policy decision:

val auditEng = AuditEngine(store = auditStore, clock = clock)
val policyAuditEmitter = AuditEnginePolicyDecisionAuditEmitter(auditEng)
val approvalLifecycleEmitter = AuditEngineApprovalLifecycleAuditEmitter(auditEng)

Each AuditEvent contains:

  • Sequential sequenceNumber per audit stream
  • previousEventHash — SHA-256 of the preceding event (hash-chained)
  • enforcementPoint, decision, actor, reasonCode
  • eventHash — SHA-256 of the full event (self-hash)
  • ISO-8601 timestamp

The BEFORE_WORKFLOW_RESUME enforcement point is intentionally allowed by the sovereign policy engine — resume authorization is enforced by the ApprovalGateCoordinator, which validates token binding and expected-version checks before the workflow can resume.


Verification Receipts

After building, SovereignTramai.verificationReceipts() returns an immutable list of VerifiedLocalModelArtifact entries — one per local-model route that was verified at build time. Artifact verification covers both primary AND fallback routes.

val tramai = SovereignTramai.builder()
    .profile(profile)
    .modelRegistry(registry)
    .auditStore(store)
    .provider(ollamaProvider, name = "ollama", default = true)
    .model("llama3.2", "ollama")
    .modelArtifactVerifier(verifier)
    .modelArtifactVerificationSettings(
        ModelArtifactVerificationSettings(enabled = true)
    )
    .build()

tramai.verificationReceipts().forEach { receipt ->
    println("${receipt.modelName}: ${receipt.manifestDigest}")
}

SovereignTramaiRuntime

For longer-lived sessions with approval-resume support:

val runtime = tramai.runtime()

// Register services needed for resume
runtime.registerService<InvoiceIntelligenceService>()

// Resume an approval-suspended tool execution
val result = runtime.resumeApprovalTyped<InvoiceAssessment>(command)

runtime.close()

SovereignTramaiRuntime wraps TramaiRuntime to prevent unsafe standalone methods from leaking into the sovereign API. It exposes:

  • create(serviceType) — create a service proxy
  • registerService(serviceType) — register a service without creating a proxy (needed after runtime restart before resumeApproval)
  • resumeApproval(command) — resume approval-suspended tool execution
  • resumeApprovalTyped<R>(command) — typed overload
  • close() — close the runtime

Limitations

  • No nested approval in v1ConfigurationException is thrown if a tool execution inside an already-suspended workflow triggers another approval gate
  • BEFORE_WORKFLOW_RESUME is allowed by policy — resume authorization is delegated to the ApprovalGateCoordinator, not the policy engine
  • Verification receipts are immutable — once built, the list cannot be modified
  • Security profile is immutableSovereignProfileConfiguration is a data class; changes require rebuilding
  • Evidence packs are snapshot-only — they capture a point-in-time view of deployment state

Next Steps