Files
cleveragents-core/docs/reference/invariants.md
T
freemo 2d4b330f75
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Failing after 14s
CI / build (pull_request) Successful in 16s
CI / quality (pull_request) Successful in 17s
CI / typecheck (pull_request) Successful in 30s
CI / coverage (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Has been skipped
CI / security (pull_request) Successful in 33s
CI / integration_tests (pull_request) Successful in 2m49s
CI / unit_tests (pull_request) Successful in 5m25s
CI / docker (pull_request) Has been skipped
feat(invariant): add invariant models and enforcement
2026-02-22 09:23:35 +00:00

4.3 KiB

Invariants

Invariants are natural-language constraints on plan execution. They flow into the decision tree during Strategize and are reconciled by the Invariant Reconciliation Actor before any strategy work begins.

Scope Hierarchy

Scope Description
GLOBAL Applies to every plan in the system
PROJECT Applies to plans targeting a specific project
ACTION Defined in an action template; promoted on plan use
PLAN Attached directly to a specific plan

Merge Precedence

When computing the effective set of invariants for a plan, the precedence chain is:

plan > project > global
  • Plan-level invariants take highest precedence.
  • Project-level invariants apply next.
  • Global-level invariants are lowest precedence.
  • Action-level invariants are promoted to plan scope when plan use is called.

De-duplication

Invariants are de-duplicated by text (case-insensitive). When the same constraint text appears at multiple scopes, only the highest-precedence copy is kept.

Merge Example

Given:

  • Global: "Never delete production data", "Log all changes"
  • Project (myapp): "All API changes need tests", "Log all changes"
  • Plan: "Use Python 3.13 only"

The effective set for a plan targeting myapp would be:

  1. "Use Python 3.13 only" (plan)
  2. "All API changes need tests" (project)
  3. "Log all changes" (project — shadows the global duplicate)
  4. "Never delete production data" (global)

Enforcement

At the start of the Strategize phase, the Invariant Reconciliation Actor:

  1. Collects the effective invariant set for the plan.
  2. Evaluates each invariant against the current plan context.
  3. Creates an InvariantEnforcementRecord for each invariant.
  4. Records an invariant_enforced decision in the decision tree.

Enforcement Record

Each record contains:

Field Description
invariant_id ULID of the invariant
enforced Whether the invariant was successfully enforced
actor_response Response text from the reconciliation actor
decision_id ULID of the associated decision node

Violation Model

When an invariant is violated during execution, an InvariantViolation is created:

Field Description
invariant_id ULID of the violated invariant
violated_text The invariant text that was violated
severity error, warning, or info
details Additional violation context

CLI Usage

Add an invariant

# Global invariant
agents invariant add --global "Never delete production data"

# Project-scoped invariant
agents invariant add --project myapp "All API changes need tests"

# Plan-specific invariant
agents invariant add --plan 01HXYZ... "Use Python 3.13 only"

# Action-scoped invariant
agents invariant add --action local/code-coverage "Minimum 80% coverage"

List invariants

# List all active invariants
agents invariant list

# Filter by scope
agents invariant list --global
agents invariant list --project myapp

# Show merged effective set for a project
agents invariant list --effective --project myapp

# Filter by regex
agents invariant list "data.*safe"

# JSON output
agents invariant list --format json

Remove an invariant

# With confirmation prompt
agents invariant remove 01HXYZ...

# Skip confirmation
agents invariant remove --yes 01HXYZ...

Relationship with PlanInvariant

The existing PlanInvariant model in plan.py represents invariants already attached to a plan with an InvariantSource provenance tag. The new Invariant model in invariant.py is the standalone storage model used by InvariantService for cross-scope management. When a plan is created via plan use, action invariants are converted to PlanInvariant entries on the plan itself.