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
| Feature | How Sovereign Enables It |
|---|---|
| Policy enforcement | PolicyConfiguration.secure() deny-by-default is wired automatically. Every provider, model, tool, and permission must be explicitly allowed. |
| Model registry | ModelRegistry SPI is mandatory and always enabled (non-disableable). Builder validates every allowed model has a primary route. |
| Audit trail | AuditEngine with SHA-256 hash-chained events is wired automatically via AuditEnginePolicyDecisionAuditEmitter. |
| DLP | Optional .dlp(interceptor) — wires DlpInterceptor into the standalone builder with optional .dlpRedactionAudit(emitter). |
| Approval workflows | Optional .approvalGateCoordinator(coordinator) with lifecycle audit via AuditEngineApprovalLifecycleAuditEmitter. |
| Artifact verification | Optional .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 deployment | SovereignDeploymentMode.OFFLINE rejects any non-LOCAL provider at build time. |
Security Invariants
The sovereign builder enforces these invariants:
checkNotNullfor required inputs —SovereignProfileConfiguration,ModelRegistry, andAuditStoreare all required; missing any one throwsIllegalStateExceptionat build time.- Init validation on config —
SovereignProfileConfiguration.initrejects blanks, wildcards (^*+$), emptyallowedModels/allowedProviders, providers without trust zones, and fallback providers not inallowedProviders. .secure().copy()pattern —toPolicyConfiguration()starts fromPolicyConfiguration.secure()(all sets empty = deny-all) and overlays only explicitly allowed entries. No wildcard bypass.- Forced-enabled features —
ModelRegistrySettings(enabled = true)and classification-awareProviderRoutingConfiguration(enabled = true)are always set. BEFORE_WORKFLOW_RESUMEis allowed by policy — resume authorization is enforced by theApprovalGateCoordinator, 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/Denyis recorded in a SHA-256 hash-chained event stream - Trust-zone enforcement — classify each provider as
LOCAL,EU_CLOUD, orGLOBAL_CLOUDand enforce data-classification routing - Air-gapped deployments — use
SovereignDeploymentMode.OFFLINEto 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:
| Input | Required | Validated |
|---|---|---|
SovereignProfileConfiguration | Yes | Blanks, wildcards, missing trust zones, empty allowlists |
ModelRegistry | Yes | Every allowed model must have an approved model entry |
AuditStore | Yes | Hash-chained audit events emitted for every policy decision |
| At least one provider | Yes | Must be registered via .provider() |
| Provider trust zones | Yes | Every 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:
- Required inputs —
checkNotNullfor profile, modelRegistry, auditStore - Registered providers — at least one must be registered
- Cross-reference — every registered provider must be in
allowedProvidersand vice versa - Trust zones — every registered provider must have a zone in
providerZones - Model routes — every allowed model must have a primary route
- Primary route targets — every route targets a registered, allowed provider
- Fallback routes — source and target models are allowed, target provider is registered and in
allowedFallbackProviders - Default provider — registered and in
allowedProviders - Offline deployment — all providers/routes are
LOCAL(runs before registry lookup) - 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:
| Zone | Meaning |
|---|---|
ProviderTrustZone.LOCAL | Same-machine or local-network provider (Ollama, vLLM, llama.cpp) |
ProviderTrustZone.EU_CLOUD | EU-hosted cloud provider (GDPR-aligned) |
ProviderTrustZone.GLOBAL_CLOUD | Global cloud provider (standard SaaS) |
Classification-aware routing is always enabled in sovereign mode via ProviderRoutingConfiguration.sovereignDefaults():
| Classification | Allowed Zones | Fallback Zones |
|---|---|---|
RESTRICTED | LOCAL only | None (no fallback) |
CONFIDENTIAL | LOCAL, EU_CLOUD | LOCAL, EU_CLOUD |
INTERNAL | Any zone | Any zone |
PUBLIC | Any zone | Any 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
sequenceNumberper audit stream previousEventHash— SHA-256 of the preceding event (hash-chained)enforcementPoint,decision,actor,reasonCodeeventHash— 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 proxyregisterService(serviceType)— register a service without creating a proxy (needed after runtime restart beforeresumeApproval)resumeApproval(command)— resume approval-suspended tool executionresumeApprovalTyped<R>(command)— typed overloadclose()— close the runtime
Limitations
- No nested approval in v1 —
ConfigurationExceptionis thrown if a tool execution inside an already-suspended workflow triggers another approval gate BEFORE_WORKFLOW_RESUMEis allowed by policy — resume authorization is delegated to theApprovalGateCoordinator, not the policy engine- Verification receipts are immutable — once built, the list cannot be modified
- Security profile is immutable —
SovereignProfileConfigurationis a data class; changes require rebuilding - Evidence packs are snapshot-only — they capture a point-in-time view of deployment state
Next Steps
- DLP — add data loss prevention to your sovereign runtime
- Approval Workflows — add human-in-the-loop gates
- Artifact Verification — verify model integrity at build time
- Evidence Packs — generate deployment attestation evidence
- Offline Deployment — deploy in fully air-gapped environments
