Let Astro script it
Ask Astro which nodes are suitable to script. It writes the script from what the workflow already did, attaches it to the node, and runs it.
Why script a node?
An agent node normally calls an AI model at each step to decide what to do. The model reads the page and picks each action from your instructions. That is useful when the page is very different each time, regularly changes or requires AI decision making. It is often waste to always use an agent on a page that doesn’t have these characteristics. In that case, you should convert the node into a script.When should I script a node?
Most nodes should eventually be scripted if you’re working on a website, rather than a Windows or Linux desktop. To start with, it’s convenient to have a node be agentic. This way, the agent can interact with the website for a few executions and you can find failure cases and improve your instructions. After a few successful runs, it’s a good time to start scripting the node. Astro is able to do this for you, or you can do it from your coding agent. Astro or your agent might look at the previous executions or spin up a live environment in order to view the website in real time to understand how to script it effectively. Once the scripts are written, ensure you run test runs with realistic data in order to identify failure modes of the new script.How to add a script
Open the node’s Instructions tab. The Script field sits at the top. Select a.js file from the node’s shared directory. The node becomes a scripted node, and an “If the script fails” picker appears beside the field. Remove the script and the node goes back to running turn by turn agentically.
Astro does the same thing from the chat. Ask it to script a node and it writes the file, sets the field, and picks a failure action.
Nodes covers where a script file lives and how the runtime resolves its path.
What happens when the script runs
The script runs against the live browser session. After the script finishes, the runtime picks the next node in this order.
The first three paths skip the model. Rows 1 and 3 are automatic. Row 2 is the one you drive from inside the script, and it is the only path that lets a script choose between several branches. See Route to the next node yourself.
What the script returns
Route to the next node yourself
A node with one outbound transition takes it automatically (row 3 above). A node that branches has more than one, so the runtime cannot guess. Return a handoff and the script names the branch itself. Callrequire('asteroid').handoff(...) and return the result.
The target slug
to is the slug of the target node’s display name. The slug is the name in lowercase, with every run of non-letter, non-digit characters turned into a single _, and any leading or trailing _ removed.
A handoff to a name that is not a live target fails the script. The error lists the valid targets, so a wrong slug is easy to fix.
Handoff targets are the node’s AI transitions only. You never hand off to a selector transition. A selector is matched automatically, at higher precedence than a handoff (row 1 above).
Carrying data on the handoff
Pass eitheroutput or variables, never both.
- Use
outputwhen the transition has a schema. The object is validated against that schema and arrives at the next node as{{.output}}, exactly as an AI transition’s payload would. - Use
variables(an array of{ name, value }) when the transition has no schema. Each entry becomes a named output variable.
What happens when the script fails
The picker beside the Script field has two settings.Fall back to AI
The failure context joins the model’s turn. The workflow recovers and finishes the task from the instructions.
Cancel
The execution cancels at once with the reason
script_failed. No model call. This also fires when the script file is missing.Pass data into a script
Data that changes per execution reaches the script asargs. Declare an input schema on the node, then read each input by name.
async ({ page, args }) => { ... } signature. The plain async (page) => { ... } form fails validation.
Tell Astro which values change per execution and it declares the schema and wires the args for you.
By default, each args value comes from an exact-name match against the workflow inputs and the outputs of upstream nodes. When nothing matches a name, the model composes that value. The next section pins a value to an exact source instead, so no model call is needed.
Pin a script’s inputs
Addx-source to a property in the node’s input schema to say exactly where its value comes from. A pinned value is filled with no model turn, so a script that reads only pinned inputs runs model-free from end to end.
A few rules around pins:
- The property’s own name is the source name. To pin
patient_id, there must be a workflow input, or an upstream output, calledpatient_id. You cannot rename across the pin. nodemay be a list of nodes. When several have emitted the same name, the most recent one wins.- In a workflow’s files,
nodeis the referenced node’s directory name. In the API and MCP graph form, it is that node’s id. This is the same reference you already use to point a transition at a node. - If a pin has no value at run time, that property falls back to the model. The pin never blocks the run.
- A schema-shaped handoff
outputis stored as oneoutputvariable. You can also pin to any of its top-level fields by their own name.
Inputs and outputs
How inputs reach a node and how outputs travel between nodes
Credentials in a script
##CREDENTIAL## tokens are replaced at the tool boundary, straight from the credential store. They never pass through the model.
##. Store the values on the Agent profile. See Credentials for the full model.
Patterns for coding agents
These recipes combine handoffs, pinned inputs, and the workflow filesystem into whole paths that need no model.The filesystem as loop memory
A node can loop back to itself to work through a list one item at a time. That keeps each pass’s context small, which matters on a long list. Record finished items inworkspace/ so a loop-back never redoes one. If the session drops and the run re-logs in, the same run picks up where it left off.
workspace/ is scratch for the current execution. It survives every step and loop-back inside that run, then is cleared when the run ends. So this is within-run memory only: a fresh execution starts the list over. (Do not use shared/ for this: a running script’s writes to shared/ are not saved back. See the Script runtime.)
Verify against a file before you submit
Read a reference file the caller staged inuploads/. Check the page against it. Submit only on a match, and route to review on a mismatch. The guardrail is deterministic, so it costs nothing and never drifts.
A document that arrives as a PDF or a print-only page
The sandbox has no PDF library, so you cannot parse a PDF with a Node module. Parse it inside the browser page instead. Keep apdf.js build in shared/, inject it with page.addScriptTag, then read the text in the page context.
Script runtime
The runtime contract: timeouts, the sandbox, the filesystem,
require, and credentialsNext
Script runtime
Timeouts, sandbox limits, and the runtime contract
Improve your workflows
The rest of the ways to make a workflow faster
Nodes
Where a script lives, and the rest of a node’s settings
Agent profiles
Store the credentials a script fills in

