Skip to content

Session Steps

Sovereign
Sovereign tier required. Session steps launch agents and keep follow-up work inside the same inspectable workflow run.

A session step supports three actions:

ActionUse it to
launch_taskLaunch an agent with a Valdr task
launch_promptLaunch an agent from a prompt without requiring a task
inputSend a follow-up message to an existing session

Fields by action

Valdr supplies the run actor and a unique request ID. It can also supply taskKey from a task-scoped run. You author the fields that choose the work and the agent:

ActionRequired authored fieldsCommon optional fields
launch_tasktaskKey unless the run is task-scoped, agentHandle, launcherConfigKeyrole, additionalInstructions, capabilityKeys, worktree, provider, config, maxRuntimeSeconds
launch_promptprompt, launcherConfigKeycontextRef, role, worktree, provider, config, maxRuntimeSeconds
inputsessionUlid, promptexpectAgentHandle, expectTaskKey

The selected launcher preset provides the provider configuration. If you also set provider, it must match that preset.

Launch a task agent

- key: launch_executor
  name: Launch Executor
  kind: session
  session:
    action: launch_task
    taskKey: "${workflow.inputs.taskKey}"
    agentHandle: "${workflow.inputs.executorHandle}"
    launcherConfigKey: "${workflow.inputs.launcherConfigKey}"
    role: executor
  waitsFor:
    kind: workflow_input
    expected: [executor_completed, executor_blocked]
  outputs:
    sessionUlid: "$.normalized.session.sessionUlid"
    outcome: "$.normalized.input.outcome"

Provide a task key, registered agent handle, and launcher preset. A task-scoped run can supply the task key automatically.

The declared sessionUlid lets later steps wait for the session, launch a reviewer against its work, or send a follow-up turn.

Launch a prompt-only agent

- key: summarize_risk
  name: Summarize Risk
  kind: session
  session:
    action: launch_prompt
    prompt: "Summarize the release risk for ${workflow.inputs.releaseName}."
    launcherConfigKey: coder-codex
    contextRef: "release:${workflow.inputs.releaseName}"
  waitsFor:
    kind: workflow_input
    expected: [summary_ready]
  gates:
    - key: summary
      kind: session_output
      source:
        event: final_agent_message
      extract: { format: json, path: $.outcome }
      outcomes: { summary_ready: summary_ready }
      onInvalid: { action: block }
  outputs:
    sessionUlid: "$.normalized.session.sessionUlid"
    outcome: "$.normalized.input.outcome"

prompt and launcherConfigKey are required. Use contextRef when the session should join other taskless work under the same local context. This example expects the agent’s final message to contain JSON with "outcome": "summary_ready".

Interpret structured session output

A session-output gate maps a field from the final agent message into the step’s expected outcome. Put the gate on a start-and-wait Session or Review step, as above, or on a Session input step. Only one session-output gate is supported per wait.

For a start-and-wait launch, omit source.sessionUlid or bind it to that step’s own session. For a Session input gate, source.sessionUlid is required and must identify the session receiving the turn. onInvalid.action may be block, keep_waiting, or default; default also requires a defaultOutcome listed under waitsFor.expected. Use payload.includeParsed or payload.includeSession only when downstream work needs that data.

Launch steps should choose an explicit completion mode. Add waitsFor when the step owns completion, or set detached: true and join that exact turn with a later await_condition step. For launch_task only, use run: false when the workflow should create the task session without dispatching work. Prompt-only launches must run when created.

ModeConfigurationUse it when
Start and waitAdd waitsForThis step should wait for and own the agent outcome
Continue after dispatchSet detached: trueOther work can proceed before a later exact-turn join
Create session onlySet run: false on launch_taskA later step will send the first turn

Continue an existing session

- key: request_revision
  name: Request Revision
  kind: session
  needs: [launch_executor]
  session:
    action: input
    sessionUlid: "${steps.launch_executor.outputs.sessionUlid}"
    expectAgentHandle: "${workflow.inputs.executorHandle}"
    expectTaskKey: "${workflow.inputs.taskKey}"
    prompt: "Apply the latest review feedback and report when the revision is ready."
  waitsFor:
    kind: workflow_input
    expected: [revision_ready]

Use input when the same agent should preserve its existing conversation and worktree context. expectAgentHandle and expectTaskKey make Valdr verify that the target session belongs to the intended agent and task before sending the message. Declare the wait, gate, and outputs on the input step so it owns that follow-up turn before the workflow advances. A separate await_condition around exactly one non-detached Session input step is rejected as redundant.

Results to map

Launch actions expose the session identity under $.normalized.session. Map sessionUlid whenever another step needs to inspect, review, or continue that session. A start-and-wait launch also exposes the accepted outcome under $.normalized.input.outcome; a detached launch exposes turnClientRequestId for an exact-turn join.

Builder controls

The session card changes its fields when you choose an action. It offers current agents, launcher presets, workflow inputs, and outputs from upstream steps, then lets you map the results needed later.

Failure and recovery

If a launch cannot find the selected agent or launcher preset, the run blocks with a visible error. Restore or register the referenced agent or preset and use Retry step when Valdr offers it. To change the binding, update the definition and start a new run; a Session retry retains the run’s frozen binding.

Next step

Add an Await-Condition Step when later work must wait for the session’s result, or add a Review Step to evaluate its implementation.