Skip to documentation
Documentation navigation

Documentation navigation

Documentation / guides

Modes

Describe Loop execution modes and their configuration.

developer

A mode is a named, predeclared alternative to a loop’s base model, effort, tools, limits, and instructions:

type Mode struct {
	Name         ModeName
	Model        model.Model
	Effort       model.Effort
	Tools        []tool.Definition
	ToolLimits   ToolLimits
	Instructions string
}

type BoundMode struct {
	Name         ModeName
	Model        model.Model
	Effort       model.Effort
	Tools        []tool.InvokableTool
	ToolLimits   ToolLimits
	Instructions string
}

func WithModes(modes ...Mode) Option
func WithInitialMode(name ModeName) Option

The empty ModeName is the implicit base mode. Declared mode names must be nonblank and unique. If any mode is declared, WithInitialMode is required and must name one of them. Setting an initial mode with no declared modes is an DefinitionInvalidInitialMode error.

Resolution

At bind time Harness always creates a base BoundMode, then one bound mode for each declaration. A mode with no model uses the base model. A mode with EffortNone uses the base effort. A mode with no tools uses the base tool definitions. Positive mode limits override only that field of the base limits; zero means inherit. The selected mode’s Instructions is combined with the base system text by EffectiveSystem.

review := loop.Mode{
	Name:         "review",
	Effort:       model.EffortLow,
	ToolLimits:   loop.ToolLimits{Calls: 20},
	Instructions: "List risks before edits.",
}
definition, err := loop.Define(
	loop.WithName("assistant"),
	loop.WithInference(client, selectedModel),
	loop.WithModes(review),
	loop.WithInitialMode("review"),
)

Definition.Modes and BoundDefinition.Modes return defensive copies. BoundDefinition.Mode(name) returns (BoundMode, bool) and also copies its model and tool slice. Mutating a returned mode cannot change future turns.

Live selection

The initial mode is design-time policy. A live controller can select only the predeclared names with SetMode(ctx, name). An unknown name returns a typed ChangeError with Kind: ChangeInvalidMode; the definition and active runtime remain unchanged. Selection is committed at the next actor turn boundary, so a step already in flight continues under its starting mode.

%%{init: {"theme":"dark"}}%%
stateDiagram-v2
    [*] --> base
    base --> review: SetMode("review") at boundary
    review --> base: SetMode("") at boundary
    review --> review: SetMode("review") is idempotent
    base --> [*]: shutdown
    review --> [*]: shutdown

Source and proof

← back to documentation