Skip to content
Loops
AGH RuntimeLoops

Goal node reference

The exact agh.loop/v1 Goal action schema, judge contract, session and retry rules, lint codes, and approval grants.

Audience
Operators running durable agent work
Focus
Loops guidance shaped for scanability, day-two clarity, and operator context.

A goal action advances a durable convergence cycle: one managed agent session works toward an objective, one or more judges evaluate the current result, and AGH either completes the node, starts another turn, or records a typed control boundary. Use this page when you author or review a Goal node. For the rest of the Loop document, see the agh.loop/v1 DSL reference.

Complete shape

- id: converge_fix
  class: action
  kind: goal
  session:
    mode: continuous
  retry:
    max_attempts: 2
    on_failure: fresh_session
  params:
    agent: "{{ .inputs.implementer }}"
    objective: "Make `make verify` pass without changing unrelated packages."
    judge:
      - id: checks_green
        type: command
        check: make verify
        expect: exit_zero
      - id: scope_is_clean
        type: agent-judge
        agent: "{{ .inputs.reviewer }}"
        rubric: "The change satisfies the objective and stays inside the requested scope."
    max_turns: 20
    on_exhausted: escalate
    output_schema:
      type: object
      required: [status]
      properties:
        status:
          type: string
          enum: [complete, blocked]

session defaults to { mode: continuous }. params.on_exhausted defaults to halt. The compiler materializes both defaults in the executed-definition snapshot, so restart and recovery use the same resolved values that the Run started with.

Fields

PathRequiredValuesContract
idyesLoop node IDLowercase snake case. Continuous handle labels must remain unique across Goal nodes.
classyesactionA Goal is a reserved first-party action kind.
kindyesgoalSelects the durable Goal executor rather than a tool-registry action.
params.agentyesAgent name or templateResolves the managed worker profile.
params.objectiveyesNon-empty stringThe convergence objective supplied to work and judge prompts.
params.judgeyesOne or more supported criteriaEvaluates each completed work turn. Criterion IDs are required and unique.
params.max_turnsyesPositive integerInitial turn limit. An approved turn extension adds this pinned amount; it does not reset the counter.
params.on_exhaustednohalt or escalatehalt ends the Run exhausted; escalate parks the Run in needs-approval. Default: halt.
params.output_schemayesJSON SchemaIts status property must include blocked, so the action can represent a truthful blocked result.
session.modenocontinuousReuses one durable binding across turns. Default when session is absent.
session.isolatednotrueSelects an isolated session instead of continuous mode. The two session strategies are mutually exclusive.
session.handlenoDisplay labelContinuous binding identity is hashed with node and fan-out item identity; the label is display metadata.
retry.max_attemptsnoPositive integerTotal pre-submission attempts, including the first. This is not retry.max.
retry.on_failurenofresh_sessionValid only with continuous mode and max_attempts >= 2.

Judge criteria

Goal v1 accepts three criterion types:

TypeRequired fieldsBehavior
commandid, type, checkRuns the exact authored command. expect defaults to exit_zero.
agent-judgeid, type, agent, rubric/promptAsks the selected judge to return a structured verdict and blocking issues.
extensionid, type, tool, optional inputsCalls the configured extension judge through the pinned executed-definition tool snapshot.

human criteria are unsupported for a Goal node. A Goal cannot keep its worker lease while waiting for a human criterion. Use on_exhausted: escalate or another typed Goal boundary when an operator decision is required.

check belongs only to command criteria. It is an authored shell command in a Loop definition. Text entered through a conversational /goal verify: clause is different: AGH adds that text to the synthetic agent-judge rubric and never converts it into a command. See Operate a Goal from a session.

Session and retry semantics

Continuous mode preserves the same durable binding across work turns. When the provider reports context usage, the checkpoint records known; absent telemetry is unknown; a compaction attempt that still needs a newer report is pending. These states are runtime evidence, not authored values.

retry.on_failure: fresh_session is a bounded pre-submission policy. It applies only when AGH proves that the external prompt effect did not start, such as a failed session preparation or prompt-slot admission. Each rejection consumes one attempt and advances prompt_attempt. Once the durable work claim starts, AGH never retries or replays that prompt. Recovery after context exhaustion creates a new continuation turn that inspects current state.

Continuous Goal nodes cannot run beneath a fan-out ancestor whose max_parallel is greater than one. A collect boundary ends that ancestor check. This prevents concurrent branches from claiming one continuous binding.

Exhaustion and approval grants

Approval grants are checkpoint-local and monotonic. They authorize one specific re-entry; they are not a general budget override.

BoundaryGrant kind / scopeWhat approval authorizes
Turn limit with on_exhausted: escalateturn-extension / turn-limitAdds the node's pinned max_turns to the current limit and enqueues one successor segment.
Budget crossed after work startedbudget / settle-currentCloses only that turn: required compact/judge/persist work. It cannot start another work prompt.
Budget crossed before workbudget / work-and-settleAllows one recorded candidate turn plus the compact/judge/persist work required to settle that same turn.
Session-origin reseed confirmationreseed / rotate-bindingCreates and activates one successor binding while the origin session remains the Goal owner.
Boundary-safe pauseplain-resume / reactivateEnqueues one successor segment without changing the turn limit or budget.

The base Loop budget remains authoritative. on_exceeded: halt is terminal exhausted and cannot receive a budget grant. on_exceeded: escalate selects settle-current or work-and-settle from the durable checkpoint phase. See Loop guardrails.

Lint codes

The shared daemon linter returns these Goal-specific codes:

CodeMeaning
goal_objective_requiredparams.objective is empty.
goal_judge_requiredJudge list, ID, supported type, or type-specific required field is missing.
goal_human_judge_unsupportedA human criterion was authored.
goal_max_turns_requiredparams.max_turns is below 1.
goal_output_status_missing_blockedThe output schema cannot represent status: blocked.
goal_on_exhausted_invalidExhaustion policy is neither halt nor escalate.
session_spec_ambiguousSession does not select exactly isolated or continuous mode.
continuous_forbids_parallelA continuous Goal sits beneath parallel fan-out without a collect boundary.
continuous_handle_reusedTwo continuous Goal nodes reuse one display handle label.
retry_max_unsupportedRetired retry.max was used; author retry.max_attempts.
retry_fresh_session_requires_continuousFresh-session retry lacks continuous mode or at least two total pre-submission attempts.

Validate before publishing:

agh loop validate --file .agh/loops/my-loop.yaml -o json

The visual editor uses the same validate route and linter codes. It does not maintain a separate Goal schema.

On this page