State Machines

State machines define named types with explicit allowed transitions between states.

Syntax

state StatusName {
  StateA -> StateB -> StateC
  StateA -> StateD
}

Each transition chain (->) declares that transitions between adjacent states are valid. Multiple chains can share states to express branching.

Example

module TaskTracker

state TaskStatus {
  Open -> InProgress -> Done
  Open -> Cancelled
  InProgress -> Blocked -> InProgress
}

entity Task {
  id: UUID
  title: String
  status: TaskStatus
}

action StartTask {
  task: Task

  requires {
    task.status == Open
  }

  ensures {
    task.status == InProgress
  }
}

This defines TaskStatus as a type with five states (Open, InProgress, Done, Cancelled, Blocked) and these valid transitions:

  • OpenInProgress
  • InProgressDone
  • OpenCancelled
  • InProgressBlocked
  • BlockedInProgress

Type Registration

A state name registers as a type, just like entity. You can use it as a field type, action parameter type, or quantifier binding type.

Documentation

State machines support doc blocks:

--- Tracks the lifecycle of a customer order.
state OrderStatus {
  Pending -> Confirmed -> Shipped -> Delivered
  Pending -> Cancelled
}

Code Generation

intent codegen produces language-idiomatic enums with transition validation:

LanguageEnum typeValidation method
Rustpub enumis_valid_transition(&self, to: &Self) -> bool
TypeScriptUnion typeisValidXxxTransition(from, to): boolean
PythonStrEnumis_valid_transition(from_state, to_state)
Gotype X string + constantsIsValidTransition(to X) bool
JavaenumcanTransitionTo(Target target)
C#enum + extensionsCanTransitionTo(this X from, X to)
Swiftenum: String, CodablecanTransition(to:) -> Bool

Cross-Module Imports

State machines are included when importing a module with use:

module Types

state OrderStatus {
  Pending -> Confirmed -> Shipped
}
module Main

use Types

entity Order {
  id: UUID
  status: OrderStatus
}