A full development lifecycle for automation workflows — draft, validate, publish, and finalize immutable versions — plus an AI-assisted code editor and a line-by-line debugger for the languages Versus runs. Every run records exactly which version it executed.
The Workflow Builder is where you draw a workflow. Workflow Studio is everything around it that turns a drawing into a dependable, production-grade automation: a development lifecycle (draft → published → final), static validation that catches broken graphs before they run, an AI-assisted code editor for the script steps, and a line-by-line debugger that pauses a real run so you can step through it.
It exists to answer three questions every automation platform eventually has to: Which version of this workflow actually ran? Is this workflow safe to run before I run it? And when a step's code fails, why — and how do I fix it?
Introducing. Workflow Studio ships alongside the existing builder and is inert until enabled — with its features turned off, workflows behave exactly as they do today. Rollout is staged (see Safety & rollout), and every read-only capability (validation, dry-trace, the SDK reference) never touches a device.

Before Workflow Studio, a workflow was a single, mutable graph. Editing it changed the definition immediately — including for runs already in flight and for the history of past runs, which read the same live graph. There was no way to say "publish this version and leave it alone," no check that a graph was even runnable until a step failed mid-run, and when a Python or HTTP Request step raised, you saw the exception type and message but not the line, the traceback, or what the code was actually doing.
Workflow Studio closes each of those gaps:
| Gap | Before | With Workflow Studio |
|---|---|---|
| Which version ran? | Runs read the live graph; edits rewrote history | Runs pin to an immutable version snapshot |
| Is it runnable? | Discovered at runtime, as a failed step | Validated before publish, with a hard gate |
| Why did the code fail? | Exception type + message only | Full traceback, stdout, and a versus.* call trace |
| How do I fix it? | Read the docs, guess, re-run | Ask AI to fix — a grounded diff — or set a breakpoint and step through |
| Safe to change a production workflow? | An edit was a production change | Draft freely; publish and finalize deliberately; roll back |
Every workflow now has three states, mirroring how you'd release any piece of software:

The Versions page (opened from the Versions button in the editor) lists every published snapshot with its state, label, publish time, and how many runs pinned to it. From here you can promote any version to Set as Final, or Restore to draft to pull an old snapshot back onto the canvas as your new working draft — a one-click rollback.
The Compare panel diffs any two versions — or a version against the current working draft — and reports exactly what changed as a structured node diff: N added · N removed · N changed, with the specific nodes listed. Before you promote a version, you can see precisely how it differs from what's live today.

In the comparison above, the working draft has one edited step since v1 was published — the diff pinpoints exactly that node (Buggy Python Step, config changed) rather than leaving you to eyeball two graphs.
Because a run records the exact snapshot it executed, "which graph ran?" is always answerable. A run launched against a finalized workflow carries that version's frozen graph — editing the draft afterward has no effect on it, and re-opening a historical run shows the graph as it was, not as it is now.
Workflow Studio statically analyzes a graph and reports problems before a run — as you edit (soft, advisory) and again as a hard gate on publish (a graph with errors can't be published).

Click Validate in the lifecycle bar and the result appears as a pill — valid, or a count of errors and warnings. Open the issues panel and each finding is clickable: selecting it highlights the offending node on the canvas. Nodes with a problem also carry a small badge (a red ring for an error, amber for a warning) so you can spot them at a glance.
Validation catches the classes of defect that otherwise surface only at runtime:
| Check | Severity | What it means |
|---|---|---|
| No Start / multiple Start | Error | A workflow needs exactly one entry point |
| Unknown step | Error | A node references a step key that isn't installed |
| Missing required config | Error | A step is missing a value it can't run without |
| Dangling edge | Error | An edge points at a node that isn't there |
| Unreachable node | Error | Nothing connects to this node — it can never run |
| Unbound decision branch | Error | A Decision's yes/no path isn't wired |
| Dead end | Warning | A path that doesn't reach an End node |
| Cycle | Warning | The graph loops back on itself |
When a draft validates, Publish version freezes it into a new immutable snapshot. Publishing runs the full validation as a hard gate — if the graph has errors, publishing is blocked and the errors are shown, so a broken graph can never become a version.
Once you've published, Set vN as Final promotes that snapshot to the version production pins to. A finalized workflow shows a Finalized badge in the lifecycle bar; if you then edit the draft, the badge notes "draft has unpublished edits," so it's always obvious when what you're looking at differs from what's live. On production workflows, finalizing is where an approval step belongs — publish is the developer action, finalize is the release.
Rolling back is the same machinery in reverse: Restore to draft on an earlier version, re-publish, and finalize — or simply set an earlier published version as Final again.
Four step types run code you write — Python Script and HTTP Request (Python), Ansible Playbook (YAML), and structured payloads for Terraform, Rundeck, AS3, and Webhook steps. Workflow Studio gives all of them a proper editor, and gives the Python steps an AI collaborator and a debugger.

Select a script step and its panel opens on the right with a full Monaco editor (the same engine as VS Code): syntax highlighting, multi-cursor, find-and-replace. The panel is resizable — drag its left edge to give the code as much room as you need, and the width persists. Two tools sit above the code:
versus SDK available inside a Python step. It's generated by introspecting the actual SDK at runtime, so it never drifts from the code — every method the platform exposes is listed with its signature. That includes native per-vendor troubleshooting — versus.probe(device_id, kind), versus.available_probes(device_id), and versus.vendor_family(device_id) call the same read-only drivers Diagnostics AutoPilot uses (NetScaler, PAN-OS, FortiGate, Check Point, Cisco ACI/ASA/IOS-XE/NX-OS, Arista, AVI, Kemp, Alteon, NSX-T, Infoblox, Cloudflare, AWS/Azure LB, and more), so a workflow can pull HA state, virtual-server health, or config objects from any supported device in one call.The AI editor is grounded in two things at once: the live SDK reference (so it only calls methods that exist) and, when you invoke it from a failed run, that run's traceback (so a fix is aimed at the actual error). Under the hood it uses the platform's standard, governed LLM path — the same one the rest of Versus uses.
Autocomplete. As you type versus. in a Python step, the editor suggests every method on the SDK — name, signature, and documentation inline — drawn from that same live reference, so the completions never drift from the real SDK. Typing versus.integrations. narrows to the integration providers (Slack, Jira, ServiceNow, vSphere, IPAM, SIEM, SCM, Rundeck, AWX, …). Press Ctrl+Space to invoke it manually.
A workflow is a graph, not an event bus — there is no publish/subscribe or event-emitter in the SDK. Steps hand results forward through a run-scoped context: a shared key/value store that lives for the length of one run.
versus.set_output("key", value). (In an HTTP Request step it's http.set_output(...).)versus.get_input("key", default); the default is returned only if nothing upstream set that key.Because the context is snapshotted per step, the debugger's Locals panel and each step's recorded context show exactly what that step saw coming in and what it produced.
"Events" in the SDK. There is no event-subscription model — the graph is the control flow, and steps pass data with the outputs above. The one place the word appears is a vendor probe kind:
versus.probe(device_id, "events")fetches recent events/logs from a device that supports it — a read, not a subscription. (Workflows are triggered by schedules or webhooks, but that's a workflow-level trigger, not something a step's code subscribes to.)
When a script step fails, the run view tells you everything about why, not just that it failed.

Every failed script step captures:
<workflow-script>, line N) rather than the platform's internals — the traceback points straight at the line you wrote.stdout/stderr), interleaved into the step log with timestamps.versus.* call trace — every SDK call the script made, in order, with mutating calls, read-only calls, and errors marked. It's how you see what the code actually did before it broke.The step keeps the operational actions it always had — Mark Complete (accept it and move on), Redo step (retry it), and Back-Out on the run — so debugging and running are the same view.
Press Ask AI to fix on a failed step and Workflow Studio sends the AI editor the step's code and the captured traceback, and asks for a corrected version.

The suggestion appears right under the traceback as a diff — the fix in context, not a wall of new code. Review it, click Copy fixed code, and paste it into the step's code panel back in the editor. Because the fix is grounded in the real traceback and the live SDK, it targets the actual failure rather than guessing.
For anything a traceback alone won't explain, set a breakpoint and step through a real run. There are two kinds, and they work together:
Then press Debug in the lifecycle bar. With no breakpoints of either kind set, Debug pauses before every step instead, so you can walk the whole workflow one step at a time.
When a run is paused before a step, the run view shows the step as paused, the run context in a card at the top, and three controls: Continue (run on to the next breakpoint, or the end), Step (run just this step, then pause before the next one) and Cancel.

When the run hits a breakpoint it pauses and the run view shows:
The debugger drives a genuine execution — the same code, the same SDK, the same data a normal run sees — so what you observe is exactly what runs. Resume commands are delivered through the database, so stepping works even though the run executes on a different worker than the one you're clicking in.
A run doesn't have to touch production. Workflow Studio adds run modes alongside the normal live run:
Both are recorded distinctly on the run, so a dry-run or lab run is never mistaken for a production one.
Workflow Studio is built to be adopted gradually and to be invisible until you want it:
| Action | How |
|---|---|
| Validate a workflow | Validate in the lifecycle bar; issues panel highlights the offending node |
| Freeze the current draft | Publish version (blocked if validation fails) |
| Make production use a version | Set vN as Final |
| See every version + diff | Versions → Compare any two versions or the draft |
| Roll back | Restore to draft on an earlier version, or set it as Final again |
| Get AI help writing a step | AI Assist in a Python/HTTP step → review the diff → Accept |
| Look up the SDK | SDK Reference in a Python step (always current) |
| Autocomplete the SDK | Type versus. (or versus.integrations.) in a Python step; Ctrl+Space to invoke |
| Pass data to a later step | versus.set_output("k", v) upstream → versus.get_input("k") downstream |
| Understand a failure | Open the failed run → traceback, stdout, and versus.* call trace |
| Fix failing code | Ask AI to fix → review the diff → Copy fixed code |
| Pause before any step | Select the node → tick Breakpoint → Debug → Continue / Step / Cancel (nothing set = pause before every step) |
| Step through code | Click the margin left of the line numbers in a Python step to set a line breakpoint → Debug → Step Into / Step Over / Continue / Stop |
| Preview without side effects | Run in dry-run mode |
versus SDK a Python step can call.