SynapseOrch 2.0 is a release candidate; the stable release is 1.9.3. How to try 2.0

Step Types

Select a step on the canvas to open its configuration panel on the right. Shared settings come first, then the fields for that step type.

Common fields

Every step except End has these:

Name — the label shown on the canvas node.

Type — changing a step's type keeps the old type's settings in the definition but ignores them; change back to see them again.

Set as entry point — makes this the step a run starts at. The entry step shows an Entry point badge instead.

Input keys — the state keys this step reads. Click a suggested key or type your own. What a step does with them depends on its type: Agent, LLM and Tool steps get their values in the prompt as context, an Evaluator sees nothing else, Merge combines them, Extract JSON scans them.

Output key — the state key this step writes its result to.

Next step — where the run goes afterwards. Leave it blank and the run completes after this step. Evaluator, Loop, If / Else and Switch steps have their own routing instead, and a Loop's is called Done path.

Guardrails

FieldDefaultWhat it limits
Max turns15An Agent step's reasoning turns, or a Tool step's attempts. Other steps ignore it.
Timeout (s)300How long the step may run. A step that runs past it fails: at the top level the run fails; inside a Loop the loop fails, and the run with it; inside a Parallel the Parallel step fails once its running branches finish. A Loop or Parallel step is bounded by what is left of the run's own timeout instead. On an Agent step whose agent runs a workflow, 300 or blank waits on that workflow's own Timeout (minutes); another value caps it, and what is left of this run's timeout caps it too. The default comes from SYNAPSE_ORCH_STEP_TIMEOUT.
Max iterations3How many times the run may route into this step. One more fails the run — 'Draft' gave up after 3 attempts — raise its Max iterations (3) or give it a step for when it reaches the limit, then Replay. — unless When it reaches the limit names a step to go to instead (default Fail the run). Replay reruns the step that routed. Steps inside a Loop body or a Parallel branch are not counted.

Caching — Cache LLM responses skips the model call when an earlier run sent the same prompt. Semantic match also reuses near-identical prompts (self-hosted, it embeds with the Embedding model in Settings → Models and runs exact match only without one; in the cloud the platform embeds), with a TTL (default 3600 seconds) and a Similarity threshold (default 0.95). Only LLM and Evaluator steps use it, though the panel offers it on other step types too; an Agent step's panel says the response cache is off for agent steps, because skipping the agent's loop would change what it writes to state. Tool results are never cached. See Caching → Response cache.

The screens, step by step: Workflows, in the Guides.


Referencing state in text

Which references a text field fills in depends on the field:

Field{{ state.key }} and {{ global.key }}{state.key}
Agent, LLM and Tool Prompt template, Workflow Its inputYes, including nested paths such as {{ state.result.score }}Flat keys only
Human Prompt for humanNoFlat keys only
Print ContentNoYes, including {state.result.score}

A reference to a key that doesn't exist is left as written, so the gap shows. {{ … }} renders objects and lists as JSON. {{ global.key }} reads Variables. Typing {{ in a prompt template lists the workflow's keys, and @ inserts a vault file as @[path] — see Vault.

Conditions and expressions

If / Else conditions, Switch expressions and a Loop's collection, while and stop-early fields are all written in the same small, restricted subset of Python. Synapse reads it with its own small evaluator, which allows only what is listed here.

  • Read state with dots: state.status, state.result.score. A missing key is None, not an error.
  • Index lists and awkward keys with brackets: state.items[0], state.human_response['Priority (1-5)'].
  • Comparisons, and / or / not, in, arithmetic and x if y else z work.
  • Functions: len, int, float, str, bool, list, dict, abs, min, max, round.
  • The common string methods work: str(state.status).lower(), .startswith(…), .split(…), .replace(…) and similar.

Not allowed: state.get(…) (use state.key — a missing key is already None), f-strings (build text with str(…) and +), comprehensions, lambdas, keyword arguments, any name other than state and the functions above, and attributes starting with _.

An expression that is refused or fails doesn't stop the run. It logs a warning and falls back: If / Else takes the False path, Switch takes the default path (and fails the run if it has none), a while-loop stops, a collection runs zero iterations, and a stop-early check is ignored.


Agent

Runs an agent in its full reasoning loop, with its tools, and writes its final answer to the output key.

Agent (required) — what the step runs. The picker lists Agents, Teams and Workflows, and the step on the canvas says which it holds (Agent · Team). A Team agent works inside the step's time and the run's cap: see A team in a workflow. If it is an Orchestrator agent (listed under Workflows), the step runs that agent's workflow as a nested run, up to three levels deep:

  • The child's input is the step's rendered prompt template — the run's own input when the template is blank — and its Agent and LLM steps are told which workflow and step called them.
  • The step writes what the child made, as the value it is: the child workflow's Result key, or else the output of its last step that produced content. A person's answer, an Evaluator's label and an End never count.
  • Each time the step runs — every Loop iteration, every retry — is its own nested run, listed under this run.
  • A failed child fails the step, with the child's reason: Sub-orchestration 'Research' failed: …
  • The step's Timeout works as its guardrail says: 300 or blank waits on the child's own timeout.

To run a workflow with no agent around it, use the Workflow step.

Prompt template — the task. If it is blank, the task is the run's original input (user_input). Either way, the values of the step's input keys are added to the prompt as context, along with the answer from any Human step that has already run.

Restrict tools for this step — narrow the agent's tools for this step only. You can remove tools, never add them; until you tick at least one, the agent keeps its own set.

Include full revision history — on by default. When the step runs again — an Evaluator sent the run back, or a loop iteration — the prompt includes every earlier attempt. Untick it to include only the last one.

Sees attachments — off by default. When it is on, the images a person attaches in chat reach this step's model, so pick an agent whose model can read images. On a step whose agent runs a workflow, it passes them on to that workflow, whose own steps choose. Chat offers Attach for a workflow agent only when some step has this on and every step that does can read images. Changing the step to another type turns it off. A run that waits on a person keeps its images: steps after the answer see the images the run started with, and any that came with the answer.

Finishes — With its reply (the default): the agent's answer in words is the output. Or By calling a tool: pick one or more of the agent's tools, and the step ends when the agent calls one of them and the call succeeds. The output is then that tool's result, an object rather than prose: the way to hand the next step a report, a plan or a record. A failed call goes back to the agent as any failed call does. A reply in words is reminded once, This step finishes only by calling submit_report; a second one fails the step: Agent step 'Research' ended without calling submit_report, which is how it finishes: it answered in words instead, after being reminded. The choice is offered for an agent, not for a Team or a workflow.

The panel has no model control for an Agent step; the step uses the agent's own model. In the step's JSON, model overrides it.

If the agent's model call fails — the provider refuses the request, the key has no credit, the server cannot be reached, or the model sends back nothing usable — the step fails and the run stops, as for an LLM step. The run log shows the provider's error; it is never written to the output key as the agent's answer. When a Team agent's member's model fails, the lead is told the member failed and can decide what to do next.

Advanced: the step's JSON shape

{
  "id": "step-research",
  "type": "agent",
  "name": "Research",
  "agent_id": "agent-researcher",
  "prompt_template": "Research this topic thoroughly: {{ state.query }}",
  "input_keys": ["query"],
  "output_key": "research_results",
  "next_step_id": "step-writer",
  "allowed_tools": ["scrape_url", "search_codebase"],
  "pass_images": true,
  "model": "claude-opus-5"
}

finish_tools (a list of tool names) is Finishes: By calling a tool; it is refused on any step but an Agent step.

{ "type": "agent", "agent_id": "agent-researcher", "finish_tools": ["submit_report"] }

Workflow

Runs another workflow from the start, as part of this run, waits for it to finish, and writes what it made to the output key. On the canvas the step reads Run workflow: Weekly review.

Workflow (required) — the workflow it runs. The picker lists the workspace's workflows, never the one open.

Its input — what the other workflow gets as its input. Empty, it is this run's own input; otherwise a template, such as Summarise {{ state.notes }}.

  • What it made — the other workflow's Result key, or else the output of its last step that produced content — is written to this step's output key, as the value it is.
  • A question it asks is this run's question, answered where this run's questions are.
  • Each time the step runs — every Loop iteration, every retry — is its own nested run, listed under this run. A failed one fails the step, with its reason.
  • Up to three levels deep, as for an Agent step whose agent runs a workflow. A workflow that would run itself, or one that runs it, is refused when it is saved; so is a step whose workflow does not exist.
  • Deleting a workflow another runs is refused, in words: 'Weekly review' was not deleted: the workflow 'Monday digest' runs it. Point it at another workflow, or delete it, first.
  • On Cloud the step costs one credit, and the steps of the workflow it runs are billed on their own, with this run.

Advanced: the step's JSON shape

{
  "id": "step-review",
  "type": "workflow",
  "name": "Weekly review",
  "workflow_id": "orch_weekly_review",
  "prompt_template": "Summarise {{ state.notes }}",
  "output_key": "review"
}

LLM

One direct model call — no agent, no tools, no loop. Use it for classification, summaries and rewrites between heavier steps.

Prompt template (required) — the whole prompt. The values of input keys are added as context, as for an Agent step.

Model override — the model for this step; blank uses the default model.

Include full revision history — as for an Agent step.

If the model call fails — the provider answers with an error, or the model's server cannot be reached — the step fails and the run stops. The error is never written to the output key as if the model had said it.

Advanced: the step's JSON shape

{
  "id": "step-classify",
  "type": "llm",
  "name": "Classify Intent",
  "prompt_template": "Classify this text as: question, complaint, or feedback.\n\nText: {{ state.user_message }}\n\nRespond with a single word.",
  "input_keys": ["user_message"],
  "output_key": "intent",
  "next_step_id": "step-router",
  "model": "claude-haiku-4-5",
  "cache_responses_enabled": true
}

Tool

Calls one specific tool, without an agent, and writes its result to the output key. Its arguments are written by a model or set on the step (Arguments, below). If a model's reply doesn't parse or the call fails, the step tries again with the error in the prompt, up to Max turns times; after that the step fails and the run stops. A call fails when the tool reports an error: a Python tool that exits non-zero, an MCP tool whose result is marked as an error, or an HTTP tool that answers with a 4xx status. An HTTP 5xx fails the step at once and is not sent again, because the server may already have acted on it. A call that may have gone through is not sent again either — a timeout waiting for the answer, a cut-off answer, an MCP request that timed out — unless the tool only reads or is safe to repeat: the step fails with … — it may have run; check before running it again. A tool with no answers set follows its HTTP method (PUT and DELETE are safe to repeat). A refused connection and a 4xx are tried again as before. A Tool step with no tool selected fails the run.

Tool (required) — any tool this instance has, not only a particular agent's.

Arguments — Ask the model: a model call writes them as JSON from the prompt. Or Set here: fixed, or read from state, with no model call. Set here lists a row for each input the tool declares, with its name, whether it is required and its type, and Add an argument by name adds one it does not declare. A value is text, or {{ state.key }}:

  • A value that is only a reference keeps its type: a number stays a number, a list a list.
  • Inside text, a reference is written as text, and an object or a list as JSON.
  • A reference that finds nothing fails the step before the call and names it: Tool step 'Post summary' could not set its arguments: state.summary is not in the run's state.

The prompt and model below are for Ask the model only.

Prompt template — what the arguments should be. Reference state here, for example Scrape {{ state.target_url }}.

Model override — the model that writes the arguments.

Include full revision history — as for an Agent step.

Tool policy applies. The call is checked against tool policy — the workspace's, or the agent's when the step's JSON names one in agent_id:

  • A tool the policy blocks fails the step before any model call.
  • A tool the policy asks about pauses the run for a person — Run scrape_url? — and approving runs that exact call, once. A refusal fails the step with the person's reason.

The step runs only its chosen tool: a reply that names another is a failed attempt, and the model is told which tool the step calls.

Advanced: the step's JSON shape

{
  "id": "step-scrape",
  "type": "tool",
  "name": "Scrape URL",
  "forced_tool": "scrape_url",
  "prompt_template": "Scrape this URL: {{ state.target_url }}",
  "input_keys": ["target_url"],
  "output_key": "page_content",
  "next_step_id": "step-parse"
}

Set here is tool_arguments, an object; null or absent is Ask the model:

{ "type": "tool", "forced_tool": "scrape_url", "tool_arguments": { "url": "{{ state.target_url }}" } }

Browser

Repeats a recorded task in the run's own browser, by code: no model calls while the pages still match. See Built-in browser.

FieldDescription
RecordingThe recording it repeats. Open it goes to the recording's page
InputsWhat it types for each of the recording's inputs, from the run: {{ state.key }} or text
SendsThe recorded steps that may send on their own. A run is never watched, so at any other send the run waits for a person
If a page changedPause for you (the default), or Let a Browser agent find the way with the agent you pick. Either way the way found waits on the recording as a fix to approve
Sessions for this stepThe sessions its browser starts signed in with, one per site

What the recording reads back is written under the step's output key. A payment, a permanent delete or closing an account is never replayed: the run waits for a person there.

Evaluator

A router that asks a model to pick one of several named routes, then jumps to the step mapped to it.

The model sees the Evaluator prompt, the values of the step's input keys, and each route's label and description — nothing else from the run's state. List everything it needs to decide in the input keys.

Evaluator prompt — how to decide.

Model override — a cheaper, faster model is usually enough for routing.

Routes — each has a Label, a target step (or End workflow), and a description that tells the model when to choose it. Add them with Add route.

The chosen label is written to the output key. If the model's reply doesn't name a valid route, the step takes fallback_route — a JSON-only field — or, if that is unset, the first route. "First" is not stable once a definition is stored in Postgres, so set fallback_route whenever the fallback matters. If the model provider returns an error, the run stops.

Advanced: the step's JSON shape

{
  "id": "step-route",
  "type": "evaluator",
  "name": "Route Request",
  "evaluator_prompt": "Based on the user's request, decide which department should handle it.",
  "route_map": {
    "billing": "step-billing-agent",
    "technical": "step-tech-agent",
    "general": "step-general-agent"
  },
  "route_descriptions": {
    "billing": "Payment, invoice, or subscription questions",
    "technical": "Bug reports, API issues, or technical problems",
    "general": "Everything else"
  },
  "fallback_route": "general",
  "input_keys": ["user_request"],
  "output_key": "department",
  "model": "claude-haiku-4-5"
}

Parallel

Runs several branches, then continues at its own Next step — usually a Merge step.

Branches — each branch picks an entry step. The branch follows that step's Next step chain until it reaches the Parallel step's own Next step, or a step with no Next step. In JSON, a branch that lists several step ids runs exactly those, in order.

What runs at the same time. Every branch runs at the same time, up to four at once (SYNAPSE_PARALLEL_MAX_BRANCHES). A branch runs after the others instead, one at a time and in order, when:

  • a step in it can ask a person — a Human step, an Agent or Tool step whose tool policy asks first, an agent that keeps memory, a Team agent, or a workflow that can ask;
  • it uses the browser, which has one tab;
  • it reads a key another branch writes;
  • its Loop uses the same index or item key as another branch's loop — two loops keeping the default loop_index run in turn, so rename one to run them together — or it reads _loop_current_iteration beside another loop.

A branch holding a Loop or a nested Parallel otherwise runs with the others. The parallel_start event's in_order lists each branch that runs in order, and why. Setting SYNAPSE_PARALLEL_BRANCHES=0 runs every branch one at a time.

When a branch fails. The branches already running finish, a branch still waiting for its turn does not start, and the Parallel step fails — and with it the run. A step in a branch that times out fails its branch the same way. Replay reruns only the branch that failed. A branch that names a step the workflow does not have fails the run.

Two branches writing one key. Branches that write the same output key fail the Parallel step before any of them runs, because only one value would survive. The editor marks the step, and Run is blocked until it is fixed; Save still saves.

A branch that asks. A branch that stops to ask a person — a Human step, or a call waiting for approval — pauses the run once the other running branches have finished. Once it is answered, its branch carries on after it, then the branches after that one, then the Parallel step's Next step; a question from a second branch is asked when the first is answered. Branches that had already finished do not run again.

Advanced: the step's JSON shape

{
  "id": "step-parallel",
  "type": "parallel",
  "name": "Research in Parallel",
  "parallel_branches": [
    ["step-web-research"],
    ["step-db-lookup"],
    ["step-doc-search"]
  ],
  "next_step_id": "step-merge"
}

Merge

Combines several state values into one. It reads its input keys — usually the output keys of the branches before it — and skips any that aren't set. Each value is labelled with the step that produced it, as Step name (step id).

Merge strategy

  • List — an array: [{"source": "Web research (step-web-research)", "data": …}, …]
  • Concat — one text: each value under a [Web research (step-web-research)]: line, separated by blank lines
  • Dict — an object keyed by that label: {"Web research (step-web-research)": …}

Advanced: the step's JSON shape

{
  "id": "step-merge",
  "type": "merge",
  "name": "Merge Research",
  "merge_strategy": "concat",
  "input_keys": ["web_results", "db_results", "doc_results"],
  "output_key": "combined_research",
  "next_step_id": "step-writer"
}

Loop

Runs a list of body steps repeatedly, then follows its Done path.

Repeat

  • A fixed number of times — Loop count (default 3).
  • Once per item — Collection is an expression over state that yields a list, such as state.items. Before each iteration the item is written to Item key (default loop_item). A collection that isn't a list, or is empty, runs zero iterations with a warning.
  • While a condition holds — While condition is checked before each iteration, for example (state.attempts or 0) < 5.

Every mode writes the iteration's 0-based position to Index key (default loop_index) before each iteration.

Stop early when — optional; checked after each iteration.

Max iterations (default 50) — a hard ceiling for every mode. A loop count or a collection larger than it fails the loop before the first iteration — 12 items exceed the 10-iteration cap of 'Summarise' — raise this loop's Max iterations; a while loop stops there with a warning.

Body steps — run in the listed order on every iteration. A body step's own Next step and routing are not followed. Prompt-driven steps in the body (Agent, LLM, Tool) see a short summary of the previous iterations.

Results. After the loop, each body step's output key holds a list with one entry per iteration in which that step completed: {"iteration": 1, "agent": "Writer", "result": …}. If the Loop step has an output key, it gets an object mapping each body step's name to that list.

A body step that times out fails the loop, and the run with it; Replay starts that iteration again. A Human step in the body pauses the run each time an iteration reaches it. Once it is answered, that iteration carries on after it and the loop runs its remaining iterations, so a loop over five items asks five times. The answers are collected in the Human step's output key like any body step's results. Loops nest up to three levels; a loop nested deeper fails the run, and so does a body that names a step the workflow does not have.

Advanced: the step's JSON shape

{
  "id": "step-loop",
  "type": "loop",
  "name": "Summarise each article",
  "loop_over": "state.articles",
  "loop_item_key": "article",
  "loop_step_ids": ["step-summarise"],
  "loop_break_condition": "state.stop == True",
  "loop_max_iterations": 20,
  "next_step_id": "step-finish"
}

Transform

Runs Python against the run's state. Read state as state.key or state["key"], and assign to result: the value of result is written to the output key. state is a copy — changing it saves nothing — and if result stays None, nothing is written.

Python code — edited in the panel's code editor.

The code runs in the Docker sandbox by default: 512 MB of memory, network access, and a timeout of the step's Timeout capped at 60 seconds. Run Transform steps on the host, under Transform step Python runtime in Settings → General, runs it as a process on the host instead, with no cap.

Anything the code prints replaces the result — the step reads result from the program's output — so don't print(). If the code raises or times out, the step fails and so does the run (Transform error: …). With no code, or a result of None, nothing is written.

On SynapseOrch Cloud, Transform steps need a plan that includes code execution.

Advanced: the step's JSON shape

{
  "id": "step-format",
  "type": "transform",
  "name": "Format Output",
  "transform_code": "result = state['raw'].upper().strip()",
  "input_keys": ["raw"],
  "output_key": "formatted",
  "next_step_id": "step-end"
}

If / Else

Evaluates a condition and routes to the True or False path. No model call.

Condition (required) — an expression that is true or false, such as state.result.approved == True. If it fails, the step takes the False path.

True path and False path — the steps to go to. If the True path is empty, a true result falls through to the False path; if both are empty, the run ends.

The output key, if set, gets True or False.

Advanced: the step's JSON shape

{
  "id": "step-check",
  "type": "if_else",
  "name": "Check Quality",
  "if_condition": "len(state.article or '') > 500",
  "if_true_step_id": "step-publish",
  "if_false_step_id": "step-rewrite",
  "input_keys": ["article"]
}

Switch

Evaluates an expression and routes to the case whose value matches. No model call.

Expression (required) — an expression, such as state.result.status.

Cases — each maps a value to a target step (or End workflow). The expression's result is converted to text and compared exactly: True matches the case True, and a missing key matches None.

Default path — taken when no case matches or the expression fails. With no default path, the run fails and says what it got: No case of 'Route by Status' matched 'archived' and it has no default path — add a case or a default, then Replay.

The output key, if set, gets the expression's value.

Advanced: the step's JSON shape

{
  "id": "step-switch",
  "type": "switch",
  "name": "Route by Status",
  "switch_expression": "state.status",
  "switch_cases": {
    "approved": "step-publish",
    "rejected": "step-archive",
    "pending": "step-review"
  },
  "switch_default_step_id": "step-end",
  "input_keys": ["status"]
}

Human

Pauses the run until a person answers. The run is stored as paused and survives a restart. Answer it on the workflow canvas (Waiting for your input → Answer), in Chat if the run was started from there, in the messaging channel the step names, or through the resume API endpoint.

Prompt for human — what to ask. Supports {state.key} for flat keys only.

Structured fields — optional, each with a name, a type (Text, Long text, Number or Yes / No) and a label. The canvas and Chat show them as a form, and the answer arrives as an object keyed by each field's name — numbers as numbers, a Yes / No as true or false. Without fields, the answer is the text typed.

Notify messaging channel — posts the prompt to that messaging channel when the run pauses; a reply there answers it. The first answer, from the channel or the app, resumes the run. See Human Gates → Messaging notification for where the prompt goes and which platforms take a reply. Timeout (seconds) appears when a channel is selected: how long a reply in the channel answers the question (default 3600). After it, a reply there is refused — That question timed out — answer it from the app instead. — and the run waits for an answer in the app.

Where the answer goes. It is written to the step's output key, and always to human_response as well. Give the step its own output key, such as review, and a later condition reads state.review for an answer without fields, or state.review.decision for the field named decision. Later steps see the answer only once it is given.

Advanced: the step's JSON shape

{
  "id": "step-approve",
  "type": "human",
  "name": "Manager Approval",
  "human_prompt": "Review the draft report and approve or reject it.\n\n{state.draft_report}",
  "human_fields": [
    { "name": "decision", "type": "string", "label": "Decision" },
    { "name": "comments", "type": "string", "label": "Comments" }
  ],
  "input_keys": ["draft_report"],
  "output_key": "approval",
  "next_step_id": "step-publish"
}

See Human Gates for the full walkthrough.


Extract JSON

Finds JSON in the text of its input keys and stores it parsed. It handles fenced ```json blocks, raw JSON and several objects in one text. One object is stored as is; several are stored as an array; none stores null with a warning. No model call.

Advanced: the step's JSON shape

{
  "id": "step-extract",
  "type": "extract_json",
  "name": "Extract Fields",
  "input_keys": ["raw_json_output"],
  "output_key": "parsed_data",
  "next_step_id": "step-next"
}

Retrieve

Searches up to 10 knowledge bases and writes the passages to the output key. No model call. Shown while Knowledge is on.

The Search the guides step (Retrieve) selected in Answer a customer question: the knowledge bases it searches, a query taken from the run's input, and how many passages it returns.

Knowledge bases — the bases to search. Query — what to search for, with state references: {{ state.user_input }} or {state.question}. Metadata filter — optional, a filter object such as {"doc_type": "contract", "year": {"$gte": 2024}}. Passages — 1–50; blank uses the bases' own. Rerank — the base's default, on or off. Index version — blank searches each base's index as it is when the step runs; a ksnap_… id pins the step to one version of one base, so a rebuild cannot change what it finds.

The output key holds context — the passages under their [K#] labels, fenced as untrusted content, to use in a later prompt as {{ state.key.context }} — chunks, citations, snapshot_ids and trace_id. A query rendered past 2,000 characters is cut, with a warning. A base that is gone or switched off fails the step and the run, naming it; so does a pinned version once its week is over.

Advanced: the step's JSON shape

{
  "id": "step-find",
  "type": "retrieve",
  "name": "Find clauses",
  "retrieve": {"kb_ids": ["kb_…"], "query": "{{ state.user_input }}", "filters": {"doc_type": "contract"}, "top_k": 8},
  "output_key": "clauses",
  "next_step_id": "step-answer"
}

Ingest

Adds each object in a state key to a knowledge base as a record. No model call.

Knowledge base — where the records go. Records from — the state key holding a list of objects, such as one an Extract JSON step wrote. Id field — names each record, so the same id replaces its record; blank makes an id from the record's content, so the same record twice is one. Text field — the field to index; blank indexes the whole object as JSON. Metadata fields — copied into each record's metadata, so a Retrieve step can filter on them.

Up to 1,000 records per step; split more with a Loop step. It is all or nothing, and it does not wait: records are indexed after the step, so a Retrieve later in the same run may not find them yet. The output key lists each document and its status. Indexing them is the base's spend, not the run's.

Advanced: the step's JSON shape

{
  "id": "step-index",
  "type": "ingest",
  "name": "Index tickets",
  "ingest": {"kb_id": "kb_…", "records_from": "tickets", "id_field": "key", "text_field": "body", "metadata_fields": ["priority"]},
  "output_key": "indexed",
  "next_step_id": "step-next"
}

While Knowledge is switched off, a run reaching either step fails: Knowledge is switched off, so Retrieve step 'Find clauses' cannot run. On SynapseOrch Cloud each costs 0.1 credit.


Print

Writes text or markdown to the output key, filling in state references. Use it to compose a final report. No model call.

Content — the template. It fills in {state.key} and nested {state.key.nested}; {{ }} references are not filled in here, and neither are @[path] vault mentions. A reference that doesn't resolve is left as written.

Advanced: the step's JSON shape

{
  "id": "step-report",
  "type": "print",
  "name": "Final Report",
  "print_content": "# Report: {state.topic}\n\n{state.article}\n\n---\nGenerated at {state.timestamp}",
  "input_keys": ["topic", "article", "timestamp"],
  "output_key": "final_report",
  "next_step_id": "step-end"
}

End

Ends the run as completed. It has no settings.

Advanced: the step's JSON shape

{
  "id": "step-end",
  "type": "end",
  "name": "Done"
}

An End step is optional. A run also completes when it reaches a step with no Next step, or a route whose target is End workflow. The run's final response is what it made: the workflow's Result key (Guardrails, in Workflow settings), or else the output of the last step that produced content — a person's answer, an Evaluator's label and an End never count. A run that made nothing answers The workflow finished without producing an answer.

End inside a Parallel branch or a Loop

An End reached inside a container ends the run — but not before the container has finished.

  • In a Parallel branch: the remaining branches still run, and the join still runs. Only then does the run end. Nothing after the Parallel runs.
  • In a Loop body: the iteration it is in finishes, and the loop stops there. Later iterations do not run, and the loop reports its stop reason as end.

This is deliberate: the other branches are work you declared alongside the End, so they are not skipped, while a loop's later iterations are repetitions that an End is plainly asking to stop.

On this page