Invariants
Declarative business rules that prevent your system from entering invalid states
What are Invariants?
Invariants are business rules that must always hold. "No two users can share the same email address." "Invoice amounts must be greater than zero." "A workspace cannot have more than one active subscription." These are not validation hints — they are hard constraints. When an invariant is violated, the system rejects the operation.
By declaring invariants in YAML alongside entities and capabilities, you make your business rules visible to AI agents, the compiler, and the Change Protocol. An agent can read an invariant spec and know exactly what rule it must preserve when modifying related entities or capabilities.
InvariantSpec Structure
interface InvariantSpec {
name: string; // unique invariant name, e.g. "email_must_be_unique"
description: string; // human-readable explanation of the rule
entity: string; // the entity this invariant constrains
rule: string; // human-readable rule description
severity: 'error' | 'warning';
enforcement: 'runtime' | 'compile' | 'both';
} Enforcement Modes
Each invariant declares when it is checked:
| Mode | When Checked | Use Case |
|---|---|---|
runtime | During capability execution, before the operation completes | Data integrity rules that depend on current state (uniqueness checks, foreign key validation) |
compile | During sysmara compile and sysmara check | Structural rules that can be verified from specs alone (field existence, type compatibility) |
both | At both compile time and runtime | Critical rules that benefit from early detection and runtime enforcement |
Severity Levels
| Severity | Behavior |
|---|---|
error | Violation blocks the operation. At compile time, this prevents compilation from succeeding. At runtime, this rejects the capability execution. |
warning | Violation is reported but does not block the operation. Useful for rules that should eventually be enforced strictly but currently need a grace period. |
How Invariants Bind to Entities
Each invariant declares the entity it constrains. This creates an enforces edge in the AI System Graph from the invariant node to the entity node. An entity can have multiple invariants, and the entity spec can also list its invariants in the invariants array for cross-referencing.
How Invariants Bind to Capabilities
Capabilities list invariants in their invariants array. This creates protects edges from the invariant to the capability. When the capability executes, the runtime checks all protecting invariants. This means a capability can be protected by invariants from different entities — for example, downgrade_subscription checks both subscription_must_have_workspace (on the subscription entity) and cannot_downgrade_with_unpaid_invoices (also on the subscription entity but involving invoice data).
YAML Example: SaaS Billing Invariants
invariants:
- name: email_must_be_unique
description: No two users can share the same email address
entity: user
rule: email must be unique across all users
severity: error
enforcement: runtime
- name: workspace_must_have_owner
description: Every workspace must be linked to a valid existing user as its owner
entity: workspace
rule: owner_id must reference a valid user.id
severity: error
enforcement: runtime
- name: no_duplicate_active_subscription
description: A workspace cannot have more than one active subscription at a time
entity: subscription
rule: workspace_id must be unique among subscriptions where status is active or trialing
severity: error
enforcement: runtime
- name: invoice_amount_must_be_positive
description: Invoice amounts must be greater than zero
entity: invoice
rule: amount_cents must be greater than 0
severity: error
enforcement: runtime
- name: cannot_downgrade_with_unpaid_invoices
description: A subscription cannot be downgraded if the workspace has unpaid invoices
entity: subscription
rule: no invoices with status open or past_due may exist for the subscription when downgrading
severity: error
enforcement: runtime Graph Relationships
Invariants create two types of edges in the AI System Graph:
invariant:email_must_be_unique--enforces-->entity:user(constrains the entity)invariant:email_must_be_unique--protects-->capability:create_user(checked when the capability runs)
This dual binding lets AI agents trace invariants in both directions: "what rules constrain the user entity?" and "what rules must hold when create_user executes?"
Compiler Integration
The Capability Compiler generates test stubs for every invariant listed on a capability. Each stub is a placeholder test that reminds developers (and AI agents editing tests) that the invariant must be verified. The compiler also includes invariant details in the generated metadata JSON, so downstream tools have full context about which rules apply.
AI-Safe Change Workflows
Invariants receive special attention in the Change Protocol. When a change plan affects invariants, the plan generator automatically adds a human review flag: "Affects N invariant(s) -- verify constraints still hold." This is because invariant changes can silently weaken business rules, which is a category of error that AI agents should not make autonomously. The Change Protocol treats invariant modifications as inherently requiring human review.