OptimizeTarget; the engine handles candidate binding, rollout fan-out, caching, budget accounting, and score bookkeeping. Every optimizer in DSRs (COPRO, GEPA, MIPROv2, SIMBA, bootstrap, Structural) is a thin strategy over this one core.
There is one Engine. What varies is the target — the lane-erased pair of (thing under optimization, evaluation harness):
Because candidate injection is ambient in both lanes — nothing is ever applied to shared state during evaluation — rollouts for different candidates share one bounded-concurrency fan-out. All items on this page are exported from the crate root except where a feature gate is noted.
OptimizeTarget<'a>
The thing an optimizer optimizes: a module or a program, packaged with its example set (by reference) and metric.
ProgramMetric is the JSON-native sibling of TypedMetric: loaded programs have no static output type, so the metric scores the interpreter’s output JsonMap against a labeled DemoRow.
Engine
Owns the candidate registry, the score matrix, the rollout cache, and the budget meter. Strategies register candidates and call the evaluate methods against a target; the engine handles binding, fan-out, caching, accounting, and bookkeeping.
The metric runs outside the trace capture scope, so LM-as-judge metrics do not pollute the execution trace. If the uncached portion of a batch does not fit the remaining budget, the engine runs nothing, leaves spend unchanged, and returns
BudgetExhausted.
EngineConfig
Candidates
ACandidate is data: slots: BTreeMap<String, CandidateSlot> mapping leaf name (the Predictors contract name) to a partial per-leaf configuration, plus a stable content hash. It is cheap to clone, serializable, and never applied by mutation: the engine scopes it ambiently around each rollout (fx::with_params); the single mutating step is the caller-driven final OptimizeTarget::install. The empty candidate (Candidate::default()) is the baseline, the module exactly as it is.
CandidateSlot (instruction plus demos per leaf name) is a different type from the IR ir::Overlay, which maps ParamId to ParamValue over a compiled Program. The program lane consumes the IR type; Candidate::to_params() + Params::bind is the bridge between them.Budget and Spend
Budget sets hard caps on evaluation spend; None means unlimited.
Budget::allows(&spend, upcoming_rollouts) reports whether the batch fits. Zero upcoming rollouts always fit, so cache-only batches never stall. Call and metric caps are enforced prospectively (the batch must fit under the cap); the token cap is retrospective (a batch may overshoot, and the following batch is refused).
Spend is what the engine has consumed so far:
This
Budget is not the IR runtime Budget documented on Runtime. The runtime type caps one program execution: max_lm_calls: Option<u32>, max_tokens, and a deadline: Option<Instant>, enforced call by call inside the run by a BudgetMeter with parent chaining for nested agent loops. The optimizer type caps an entire optimization search across all rollouts: it adds max_metric_calls, has no deadline, and is checked per batch before anything runs, with consumption tracked in Spend. The program lane runs each rollout under the runtime Budget::unlimited() while the optimizer Budget governs the batch.RolloutCache
In-memory map from a rollout key to its Eval (score plus optional feedback). A candidate re-evaluated on a seen example returns the cached Eval with no LM call and no metric call.
The key recipe is (baseline, candidate, example, salt), formatted as four 16-digit hex hashes joined by colons:
Public surface:
get, insert, len, is_empty.
Score bookkeeping
ScoreMatrix is a per-instance matrix of candidates (rows, registration order) by examples (columns). Cells are None until scored. Methods: new(columns), candidates(), examples(), ensure_rows(n), record(candidate, example, score), score(candidate, example), row(candidate), mean(candidate), best_by_mean(), pareto(), pareto_over(columns). The column-restricted view supports GEPA-style setups where train and validation examples share one matrix.
ParetoView is a dominance snapshot computed from the matrix. best_scores() gives the best score per viewed column; wins(candidate) counts columns the candidate wins or ties on (tolerance 1e-6); frontier() lists candidates winning on at least one column; statistics() summarizes. A candidate with zero wins is dominated. GEPA samples parents proportional to their Pareto coverage directly from this view.
ParetoStatistics fields: num_candidates, num_examples_covered, avg_coverage: f32, max_coverage, min_coverage. A healthy search grows num_candidates slowly while avg_coverage rises; num_candidates == 1 means the search has collapsed.
Outcome types
Rollout mechanics
Each program-lane rollout runsinterp.run(input, Some(overlay), Budget::unlimited()) under its own capture scope with TraceMeta.candidate_hash set to the candidate’s hash and a program tag carrying the program hash. Each module-lane rollout scopes the candidate’s fx::Params ambiently around the whole traced rollout (rollout_traced), so every Predict leaf binds its own entry at call time. After the metric scores a module-lane rollout, any span-level evals it returns from TypedMetric::evaluate_spans are stamped onto the trace’s spans; demo-harvesting optimizers prefer these over the rollout score (see Evaluation). Every pending (candidate, example) pair — across all candidates, in both lanes — joins one buffer_unordered stream bounded by EngineConfig::concurrency.
See also
- Optimizers
- Evaluation
- Runtime for the IR
Budget,BudgetMeter, andInterpreter::run - Traces for
Trace,TraceMeta, andEval - Program and nodes for
Programandir::Overlay - COPRO, MIPROv2, GEPA
- Example: 04-optimize-hotpotqa.rs
- Example: 08-optimize-mipro.rs
- Example: 09-gepa-sentiment.rs
