Agentic flows

Write a step as a goal in plain English. A coding agent drives it the first time, the steps it took are recorded beside the flow, and from then on the step replays like any other — with no agent and no model turns.

One example

buy-usdt.yaml
flow: buy-usdtsteps:  - runFlow: { file: login.yaml }  - agent: buy 250 USDT  - assert: { visible: { text: Bought 250 USDT } }

The agent: step says what to achieve, not how. The assert: after it says how to tell it worked, and only that assertion decides whether the step is done. An agent can claim success; it cannot pass a step.

The first run hands the step to your coding agent — Claude Code, Copilot or Codex — which looks at the screen and answers with ordinary flow steps. When the assertion holds, those steps are saved to buy-usdt.agent.json. Every later run replays them and checks the assertion again. If the app has changed and the replay no longer gets there, the step goes back to an agent.

A flow with at least one agent: step is agentic; the rest are scripted. Both are the same YAML, run by the same engine, and an agentic flow can mix both kinds of step freely. Studio's Flows screen shows them in two tabs.

Writing one

The short and long forms

agent: <goal> is enough for most steps. The long form adds a budget and a hint for the agent:

YAML
- agent:    goal: set a price alert on SUI at ${PRICE}    rounds: 3          # agent answers before the step fails (default 5)    timeout: 120000    # ms for the whole step (default 180000)    hints: the alert form is behind the bell on the token screen- assert: { visible: { testID: alert-saved } }

What verifies a step

Every assert: step directly after an agent: step verifies it, and all of their assertions must pass. A step with nothing to verify it is a parse error, so a flow cannot record a drive nobody checked. The one other verifier is the flow's own goal:, for an agent step that is the last step of the flow:

YAML
flow: checkoutgoal: { route: order-confirmed }steps:  - runFlow: { file: login.yaml }  - agent: check out the cart with the saved card   # verified by the goal

Agent steps can sit inside runFlow and retry, but not inside repeat or a branch yet: a recording per iteration or per arm would have no stable identity.

Good and weak assertions

The assertion is the whole contract, so write it about the outcome. visible: { text: Bought 250 USDT } is good: only a completed purchase shows it. route: token after “buy 250 USDT” is weak: the agent could reach that screen without buying anything, the step would pass, and that drive would be recorded. A weak assertion does not fail; it records the wrong thing.

Test data and secrets

Use ${VAR} in a goal for anything that varies, exactly as in any other step. When the agent types a value that equals one of the flow's variables, the recording stores ${NAME}, never the value. If it types a literal into a field that looks like a password and no variable matches, the recording is refused, and the run names the variable to add. Put credentials in the flow's secrets: and they never reach a committed file.

Running one with an agent

Squiggle never calls a model. Your coding agent does, through Squiggle's MCP server, so it uses the model and the account you already have. Register the server once:

Terminal
# register Squiggle's MCP server with the agent you usesquiggle init --agent claude     # .mcp.jsonsquiggle init --agent copilot    # .vscode/mcp.jsonsquiggle init --agent codex      # ~/.codex/config.toml

Each is a merge into a file that is yours: a server already registered as squiggle is left exactly as it is. squiggle doctor reports which agents are set up. Then ask your agent to run the flow, or paste the prompt a run gives you (below).

The agent calls run_flow. When the run reaches an agent step with no recording, it parks and hands the agent an escalation packet with the reason agent_step: the goal, the assertions that will verify it, what is on screen, and, when the app has screen memory, the known taps toward the screens the goal names. The agent looks with describe and answers with resume_intent { runId, patch: [...] } — a list of ordinary steps with selectors, never coordinates. The run executes them through the same deny rail and settle gates as any step, then checks the assertions. A miss is another round, up to rounds. While the run is parked, the one-off tools (tap, swipe, and so on) are refused, so the answer is the only thing that can move the app, and therefore the only thing recorded.

run_flow takes recordAgentSteps: false for a try-it run that saves nothing, and redrive to drive steps again even though they have recordings. See Agents & MCP for the server itself.

Recordings

<flow>.agent.json sits beside the flow and is meant to be committed: it is what lets a teammate's run, or CI, replay the step with no agent. Each entry holds the goal, the steps that ran, the screen it started from, who recorded it and when, and how many model turns it took. The steps are plain flow steps, so a recording reads in a pull-request diff like any YAML change: if an agent took a strange path, you can see it.

Saved only when verified
A drive is written only when its assertions held. A stopped or failed run saves nothing.
Replays do not write
A replay that changed nothing leaves the file byte-identical, so CI never produces a diff by running. Only a new drive, or a heal that rewrote a replayed step, changes it.
Keyed by the goal
A recording belongs to its goal text, ignoring spacing and case. Reword a goal and it is a new step with no recording; the same goal twice in one flow is two steps.
Re-recording
squiggle flow <file> --redrive "<goal>" (or all) ignores the recording for that run. In Studio, an agent step's Re-record deletes it, so the next run with an agent drives it fresh.

Running without an agent

Terminal
squiggle flow buy-usdt.yaml#   agent  REPLAYED  buy 250 USDTsquiggle flow price-alert.yaml#   agent  NEEDS AGENT  set a price alert on SUI at 3.25#   (then the prompt to give your agent; exit 6)squiggle flow price-alert.yaml --print-prompt | pbcopy

With no agent attached — a plain squiggle flow, a CI job, Studio's Replay — a recorded step replays and reports REPLAYED. A step with no recording, or one whose replay no longer reaches its assertion, stops the run at NEEDS AGENT. That is not a failure, because nothing failed: it is the same “no data” as a pending wait, and it exits 6, not 0 or 1. A real failure elsewhere in the run still wins and exits 1.

--print-prompt
Print only the words to paste into your agent — which flow, which goals, and how to answer. Studio's agent step has the same prompt behind a copy button.
--needs-agent fail
Exit 1 instead of 6, for a job that should go red.
--recordings-of <file>
For an --inline run of a saved flow: whose recordings to replay and update.

In CI

Terminal
# every agentic flow; red if any step still needs an agentsquiggle flows --agentic --needs-agent fail

squiggle flows takes --agentic or --scripted to run one kind, and its summary counts NEEDS AGENT separately from passes and failures. With committed recordings, an agentic suite runs in CI like a scripted one: no agent, no model, no API key. A step that needs an agent there means a recording is missing or stale. Re-record it locally and commit the updated .agent.json with the change that broke it.

Find what to test

The Inspector's Screen map marks the screens no saved flow reaches. Select one and press New agentic flow here: you get a flow that starts on that screen with an agent step, ready for a goal.