Skip to main content

State & Variables

The state is how steps communicate. Every step writes its outputs and metrics to a shared key-value store. Other steps read from it via template variables.

Basics

After a step executes, its results are available to all subsequent steps:
{decompose.output} resolves to the JSON plan produced by the decompose step. No steps. prefix needed — variables use short names.

Fully-qualified keys

The state is a flat map[string]string with fully-qualified keys:
Examples:
  • decompose.output — the JSON plan
  • build/task-1/converge.output — the diff from task 1
  • build/task-1/converge.diff — the git diff
  • build/task-1/converge.agent — the agent that executed (e.g., claude-opus if escalated)
  • build/task-1/converge.cost — estimated cost USD
  • build/task-1/converge.tokens_in — input tokens
  • build/task-1/converge.status — pass/fail/fatal
  • build/task-1/converge.gate.compile — bool
  • build/task-1/converge.gate.review.comments — string

What each step writes

Every completed step writes these keys:

Task variables (each block)

Inside an each block, task-level variables are available:

Retry variables

On retry (attempt > 1), the failed attempt’s context is available:

Dynamic agent reference

{<step>.agent} returns the agent that actually executed a previous step. If the step was escalated (agent overridden in retry), the variable returns the final agent, not the declared one. This enables the idiom:

Scope resolution

Variables resolve by strict scope: step local → each scope → workflow scope. If a variable name is ambiguous (same step name in different scopes), --dry-run will reject the workflow with an error listing available paths. There is no implicit resolution by proximity. For cross-scope references, use the fully-qualified path: {build/task-1/converge.output}.

Run-level metrics

The {run.*} variables from v0.0.3 have been removed. Run-level metrics (total cost, duration, tokens) are in the ledger and accessible via gump report. The global bounds (max_budget, max_timeout, max_tokens) replace {run.*} for control purposes. If a prompt needs the cost of a specific step, use {<step>.cost}.

State persistence

The state is serialized to .gump/runs/<uuid>/state.json as a flat JSON dictionary. It’s reloaded on --resume and --replay. At retry, the previous iteration’s keys are copied under the prev namespace. The original keys are overwritten by the current iteration.