Running workflows
Workflow input envelopes, execution, and targeted diagnosis for SDK, API, CLI and MCP agents.
Both run helpers accept the same workflow argument: an inline Workflow
object or a string reference to a published workflow —
"<id>@<version>", where the id is the published
<org-slug>/<workflow-slug> address (preferred, e.g.
"acme/sprite-pack@2.1.0") or the workflow's internal UUID (see
Versioning).
run() — run to completion
The simple path: streams events internally and resolves with the final outputs, or throws if the run fails.
import { BlitClient } from "@blitflow/sdk";
const client = new BlitClient({ apiKey: process.env.BLITFLOW_TOKEN });
const outputs = await client.run("acme/sprite-pack@2.1.0", {
prompt: { value: "isometric stone tower" },
photo: { ref: "https://example.com/tower.jpg" },
});
// outputs: Record<string, Artifact>
console.log(outputs.image); // { kind: "image", ref: "https://…", … }Inputs are Artifacts keyed by the workflow's declared input names.
Input formats across clients
Workflow execution accepts an envelope for every supplied input, including
text, numbers, booleans and structured JSON. kind is optional because the
workflow input declares its type. For a TEXT input named texto:
{ "inputs": { "texto": { "value": "hola beta" } } }{"inputs":{"texto":"hola beta"}} is invalid for a workflow run. Wrap the
value; do not change the workflow's connections or replace its code with a
constant. Binary inputs use { "ref": "…" }; code-node binary ports require
an owned Artifact.
| Client | How to supply that text input |
|---|---|
SDK run() / startRun() | Second argument: { texto: { value: "hola beta" } } |
REST POST /v1/runs / MCP runs_create | inputs: { texto: { value: "hola beta" } } |
Studio agent run_workflow | inputs: { texto: { value: "hola beta" } } |
| CLI | blitflow run workflow.yaml --input 'texto=hola beta'; the CLI wraps the value |
Use the workflow's declared input identifier as the key. A code node's internal
port name is not necessarily the workflow's input identifier. Inside the code
function, BlitFlow unwraps inline Artifacts: a TEXT port receives a string, not
an object with a value property.
Standalone runs.node / MCP runs_node / Studio run_node have a different
contract: value ports accept bare scalars and data ports accept Artifacts.
Use the node spec to choose inputs. Code nodes run inside workflows, not through
the standalone node endpoint.
Diagnose a run without repeated searches
Inspect the existing run and its first failed step: SDK getRun(), REST
GET /v1/runs/:id, MCP runs_get, CLI blitflow runs <id>, or Studio
get_run. A structural validation result checks nodes, ports, types and wiring;
it does not execute code or validate the values supplied by a later run request.
Choose the next action from the observed error:
| Failure | Check first |
|---|---|
Missing ref / value, or code input "…" must be inline | Compare the execution request with the input envelopes above. Check whether a scalar port received a reference instead of an inline value. Keep a valid graph connected. |
| Missing input or structural error | Inspect the workflow's declared inputs and validate its structure. |
| Invalid node parameter, enum or bound | Read that node's spec once and compare the rejected parameter with its accepted values. |
| Code syntax, import, output or descriptor error | Inspect the source and the exact code-node contract. Read the runtime reference for packages or binary ports. |
| Missing Sandbox snapshot or unavailable execution service | Report an environment configuration problem; graph edits cannot supply a server snapshot. |
| Provider rate limit or outage | Report the provider failure. Do not restructure the graph to address service availability. |
Use the tool schema and error before searching docs. If a page is already named, read it directly and reuse it during the investigation. Search only for a missing fact; do not repeat searches or reread unchanged pages without new evidence. A failed attempt does not authorize another paid run. Correct the diagnosed cause, then retry only within the user's requested scope and required approval. When a client presents a run approval, that approval is the confirmation; an agent does not ask a second conversational yes/no question for the same run.
Keep the run ID and inspect its terminal status and actual outputs before claiming success. If a request was interrupted or its outcome is uncertain, reconcile the existing run before starting another. Do not include tokens, private input values, or raw logs in documentation searches or feedback reports.
startRun() — observe progress
Returns immediately with a handle; iterate events() for per-step progress:
const handle = await client.startRun("acme/sprite-pack@latest", inputs);
for await (const event of handle.events()) {
switch (event.type) {
case "step.started":
console.log(`▶ ${event.nodeId}`);
break;
case "step.progress":
console.log(` ${event.nodeId}: ${event.message}`);
break;
case "step.completed":
console.log(
`✔ ${event.nodeId} ($${event.usage.costUsd}, ${event.usage.ms}ms)`,
);
break;
case "run.completed":
return event.outputs;
case "run.failed":
throw new Error(`${event.error.code}: ${event.error.message}`);
}
}The event union is documented in Runs & streaming.
Running an inline definition
Pass a Workflow object instead of a ref for one-off runs — nothing needs to
be published:
const outputs = await client.run(
{
version: 2,
nodes: [
{ id: "prompt", uses: "input", outputType: "TEXT" },
{
id: "gen",
uses: "rd-fast",
inputs: { prompt: "${prompt.value}", seed: 7 },
},
{ id: "image", uses: "output", inputs: { value: "${gen.image}" } },
],
},
{ prompt: { value: "a brass key" } },
);See Building workflows for constructing these programmatically with validation.
getWorkflow() — fetch a published definition
const { id, version, sequence, workflow } =
await client.getWorkflow("acme/sprite-pack@2");
// version: "2.4.1" — the resolved highest 2.x.xUseful for auditing what a ref resolves to, diffing versions, or grabbing a definition to modify and re-run inline.