Skip to main content
AgentRuntime uses one workflow engine for fixed pipelines and dynamic multi-agent runs. An episode is a single workflow run where some steps are gated (they wait for permission to start) and agents can route work to each other at runtime. You do not pick a separate “episode workflow type.” Episode behavior is controlled by per-step flags — mainly no_auto_start, terminal, and handoff routing on agent_call steps.
Episode mode activates when any step in the graph has no_auto_start: true. If no step uses that flag, the run uses classic connected finalize: every step in the graph must complete.

Connected vs episode mode

Mixed graphs combine both: a connected spine (fetch → report) plus optional gated agents on the side. Always provide an explicit exit on mixed graphs (see Avoid stuck runs).

Two axes: when vs what

Every step has two independent concerns. Do not mix them.
depends_on controls order only — it does not pass values. Data flows through templates, trigger_steps, and handoff payloads merged into run.input._steps[step_id].

Key fields

no_auto_start — require entry grant

When true, a step does not run at workflow start even if it has no depends_on. It starts only when:
  1. Its id appears in trigger_steps at start or resume (key presence = grant), or
  2. Another agent hands off to it at runtime.
Chat session workflows use this pattern: the chat_agent step is gated and receives a new trigger_steps entry on each user message. In Workflow Studio, enable Require entry grant under Episode scheduling on the step config panel.

trigger_steps — grant + per-step input

  • Key presence → entry grant for that step (when it has no_auto_start)
  • Value → per-step input overlay merged before the step runs
At t=0, auto-start roots and granted gated steps can run (additive union).

input_allowlist — who may send to this step

ACL on the receiver: which step ids (or "human") may route input or a handoff to this step. Empty = unrestricted. Configure in Studio under Accepts input from on any step type.

Handoff — dynamic routing between agents

When an agent_call completes, its result can include:
The engine:
  1. Validates ACL (input_allowlist on the target must include the sender)
  2. Adds a runtime dependency (sender → target)
  3. Brings the target into scope
  4. Merges payload into run.input._steps[target] for the next execution
No static depends_on edge is required between choosable agents.

terminal — close episode when this step completes

When true on any step type, completing that step closes the episode. No agent JSON required. Typical pattern: a mandatory tail step — e.g. report with terminal: true and depends_on: ["coordinator"]. In Workflow Studio, enable Episode terminal under Episode scheduling.

done: true — agent signals episode end

An agent_call can end the episode by including done: true in its structured reply (see How episode close works).

Runtime state (custom.episode)

During a run, the engine tracks episode bookkeeping in run context (not visible in Studio):
The scheduler’s readiness check (CanExecuteStepEffective) requires all of the following:
  1. Step is in scope
  2. All effective deps are satisfied (published depends_on ∪ runtime_depends_on from handoffs)
  3. If no_auto_start with no deps → must have an entry grant

Lifecycle walkthrough

1. Start

2. Agent completes with handoff

3. Agent completes with done (or terminal step completes)

Closing the episode does not instantly set the run to completed. The engine still waits for in-scope steps to finish (for example a mandatory terminal tail) before finalizing.

4. Chat session

Chat uses the same episode machinery:
Platform template (workspace-copilot-session):
  • One step: chat_agent with no_auto_start: true, input_allowlist: ["human"]
  • agent_id injected per tenant at run start

How episode close works

Both paths converge when any step completes — the engine calls applyRuntimeRoutesAndClose:
Then maybeFinalizeRun checks that all in-scope steps are completed or skipped before setting run status to completed.

Path A: Agent emits done: true

1. Agent reply shape For workflow agent_call steps, the agent’s final text can be JSON:
With an optional handoff instead of closing:
2. Turn runner parses JSON When the LLM finishes (no more tool calls), the agent turn runner parses the reply and extracts done into step metadata. 3. Step result stored
4. Engine reads done The workflow handler checks result.done or result.result.done. If true and the graph is in episode mode → closeEpisode().
Chat session caveat: When a turn is bound to a chat conversation (observation_conversation_id), the turn runner may not parse done from JSON in the agent’s text reply. For chat copilot sessions, prefer a terminal: true step on the session graph, or ensure done is present in step result metadata through your integration path. Headless workflow agent_call steps (no conversation binding) get full JSON parsing.

Path B: Step has terminal: true

1. Authoring Mark the step in graph JSON or Studio:
Works on any step type — lua_script, mcp_call, llm_call, not only agents. 2. On step complete When that step completes, senderDef.Terminal == true sets shouldClose = true — no done in the result needed. 3. Same closeEpisode path Identical to the done: true path from there.

Comparison

Both require episode mode (no_auto_start on at least one step).

Chat session behavior

Three graph modes (same engine)

Mixed is the tricky one: a connected spine can finish while gated agents never ran. If nothing calls done or hits a terminal step, the run stays running forever — the C3 anti-pattern (see below).

Visual summary

Avoid stuck runs (C3)

A common authoring mistake: a connected spine completes while gated episode agents never run and nothing closes the episode. The run stays running forever. Fixes:
  • Add terminal: true on the last spine step (e.g. report)
  • Add a coordinator agent that emits done: true after the spine
  • Split into separate workflows (connected pipeline vs autonomous episode)
Workflow Studio dry-run reports episode_c3_spine_without_close as an error (publish is blocked). Use the Mixed episode coordinator template or add terminal: true on a spine sink.

Practical authoring rules

  1. Use no_auto_start on agent roots that should not fire until a human or another agent invites them.
  2. Set input_allowlist on receivers so handoffs are ACL-controlled.
  3. Always provide an exit: terminal: true on a sink step, or an agent that emits done: true.
  4. For mandatory tails (e.g. “report must always run”), use static depends_on — do not rely on handoffs alone.
  5. For chat bots, use the session workflow pattern: gated chat_agent, pause between turns, same run_id.