When to use AgentStateGuard
Use AgentStateGuard when your AI agents maintain structured state (such as task lists, workflow progress, or configuration) and you need guarantees that:- State payloads conform to a strict schema before they are persisted
- State transitions follow monotonic, immutable, or ordered-enum constraints
- Writes to disk are atomic — either fully committed or not written at all
AgentStateGuard operates entirely in-process. It does not require network access or an API key. All verification is deterministic and fail-closed.
How it works
AgentStateGuard uses a three-phase approach:- Structural verification (Phase 1) — Validates that a proposed JSON state payload conforms to a strict schema. Rejects duplicate keys, non-standard JSON constants (
NaN,Infinity), and unexpected fields. Numbers are parsed asDecimalto preserve deterministic numeric semantics. - Semantic transition verification (Phase 2) — Given a current state and a proposed state, verifies that the transition satisfies configured rules: immutable paths cannot change, integer paths must increase monotonically, enum paths must advance forward, and keyed arrays must preserve order.
- Governed atomic commit (Phase 3) — After verification passes, writes the normalized state to disk atomically using
tempfile+os.replace. The write target must be within configured allowed roots and must end in.json.
Usage
Phase 1: structural verification
Phase 2: transition verification
Phase 3: atomic commit
API reference
AgentStateGuard(required_schema, transition_rules, allowed_commit_roots)
Creates a new AgentStateGuard instance. The schema and transition rules are frozen on construction — later mutations to the original dicts have no effect.
A strict JSON schema definition. Must include a
type field (object, array, string, integer, number, boolean, or null). Object schemas must define properties and may include required and additionalProperties (boolean). Array schemas must define items. Enum constraints use the enum key with a non-empty list.Semantic transition rules. At least one rule must have a non-empty value for transition verification to be enabled. Supported keys are described in the transition rules section.
List of absolute directory paths where atomic commits are permitted. Required for
verify_transition_and_commit_state. Each entry must be an absolute path string.verify_state_payload(proposed_state_json)
Validates a proposed state payload against the configured schema.
A JSON string representing the proposed agent state. Must be a non-empty string containing valid JSON.
| Key | Type | Description |
|---|---|---|
verified | bool | True if the payload passed all structural checks |
status | str | "VERIFIED" or "BLOCKED" |
proof | str | Explanation of the verification result (on success) |
normalized_state | dict | The payload with keys sorted deterministically (on success) |
error_code | str | Error code (on failure) |
message | str | Human-readable error description (on failure) |
verify_state_transition(current_state_json, proposed_state_json)
Validates a state transition against both structural and semantic rules.
JSON string representing the current agent state.
JSON string representing the proposed new agent state.
verify_state_payload, plus:
| Key | Type | Description |
|---|---|---|
normalized_previous_state | dict | The canonicalized current state (on success) |
verify_transition_and_commit_state(current_state_json, proposed_state_json, target_path)
Verifies the transition and atomically writes the normalized state to disk if verification passes.
JSON string representing the current agent state.
JSON string representing the proposed new agent state.
Absolute path to the target
.json file. The parent directory must exist, and the path must fall within a configured allowed_commit_roots directory.verify_state_transition, plus:
| Key | Type | Description |
|---|---|---|
committed_path | str | Absolute path where the state was written (on success) |
committed_bytes | int | Number of bytes written (on success) |
Transition rules
Transition rules define semantic constraints that must hold between the current and proposed state. All paths use dot-style JSON path notation starting with$..
immutable_paths
A list of paths whose values must not change between states.
monotonic_integer_paths
A list of paths whose integer values must never decrease.
ordered_enum_paths
A dictionary mapping paths to ordered lists of allowed values. The value at each path must advance forward (or stay the same) in the list — it cannot move backward.
keyed_object_array_paths
A dictionary mapping array paths to rules for keyed object arrays. Each rule specifies:
| Key | Type | Required | Default | Description |
|---|---|---|---|---|
key | str | Yes | — | The field used to identify each object in the array |
monotonic_boolean_fields | list[str] | No | [] | Boolean fields that can transition from false to true but never back |
allow_new_items | bool | No | true | Whether new items can be appended to the array |
Error codes
| Code | Phase | Description |
|---|---|---|
QWED-AGENT-STATE-101 | 1 | Input is not a non-empty JSON string |
QWED-AGENT-STATE-102 | 1 | Invalid JSON (syntax error, duplicate keys, or non-standard constants) |
QWED-AGENT-STATE-103 | 1 | Schema validation failed (missing keys, wrong types, unexpected fields) |
QWED-AGENT-STATE-104 | 2 | Transition rules not configured or all rules are empty |
QWED-AGENT-STATE-105 | 2 | Current state failed structural verification |
QWED-AGENT-STATE-106 | 2 | Transition rule violation (immutable path changed, value regressed, etc.) |
QWED-AGENT-STATE-107 | 3 | Commit target validation failed (no allowed roots, invalid path, outside roots) |
QWED-AGENT-STATE-108 | 3 | Atomic file write failed |
Security considerations
- Strict JSON parsing: Duplicate keys and non-standard constants (
NaN,Infinity,-Infinity) are rejected. Numbers are parsed asDecimalto avoid floating-point non-determinism. - Frozen configuration: Schemas and transition rules are deeply frozen on construction using
MappingProxyTypeand tuples. Callers cannot mutate the guard’s configuration after initialization. - Fail-closed design: Every method returns a
BLOCKEDdecision object on failure — no exceptions leak past the public API unless the constructor arguments themselves are invalid. - Path traversal prevention: Commit targets are resolved to absolute paths and validated against the
allowed_commit_rootsallowlist. Only.jsonfile extensions are permitted. - Atomic writes: State files are written via
tempfile.NamedTemporaryFilefollowed byos.replace, which is atomic on POSIX systems. The temporary file is cleaned up even if the rename fails. - Depth limit: Schema validation enforces a maximum recursion depth of 64 to prevent stack overflow from deeply nested payloads.
Next steps
StateGuard
Workspace rollback using shadow git snapshots
Agent verification
Pre-execution verification for AI agents
SDK guards
All available security guards
Attestations
Cryptographic proof of verification