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
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:
- 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:
flow: checkoutgoal: { route: order-confirmed }steps: - runFlow: { file: login.yaml } - agent: check out the cart with the saved card # verified by the goalAgent 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:
# 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.tomlEach 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>"(orall) 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
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 | pbcopyWith 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
--inlinerun of a saved flow: whose recordings to replay and update.
In CI
# every agentic flow; red if any step still needs an agentsquiggle flows --agentic --needs-agent failsquiggle 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.