Skip to main content
After an optimizer tunes a module, the improved instructions and demos live only in memory. ModuleState snapshots the mutable state of every Predict leaf in a module into a serializable value, so an optimized program can be saved to disk and reloaded in production without re-running optimization.

ModuleState

A ModuleState holds one PredictState per predictor, keyed by the dotted path the optimizer walker discovers (predictors: BTreeMap<String, PredictState>). The BTreeMap keeps JSON output stable across runs. Paths follow the module structure: struct fields join with dots (inner.predictor), list elements append an index (steps[0]), and map entries append an escaped key (stages['draft']).

PredictState and the JSON shape

PredictState is the serializable snapshot of a single predictor’s mutable state. A saved file therefore looks like:

The mutation seam

Internally, both state loading and optimizers reach predictors through one type-erased trait, DynPredictor (crate-private). Its apply_update method is the single mutation seam: every write to a predictor’s optimizable state flows through it, including optimizer candidate set and restore, ModuleState::apply, and the fx::Params overlay. An update is partial: None fields are left untouched, instruction: Some(None) clears the override back to the signature default, and Some(demos) replaces the demo set. load_state (used by apply) delegates to apply_update with both fields set. This is also the single place where prompt caches are invalidated: a candidate is data applied through the seam, never ad hoc field mutation.

Compatibility behavior

There is no version field in the format. Compatibility is field level and structural:

See also