UWS — Udon Workflow Specification
UWS is a compact, execution-oriented workflow specification that sits directly on top of source documents such as OpenAPI, Google Discovery, AWS Smithy, AsyncAPI, GraphQL, OpenRPC, Protocol Buffers, and OData. A UWS document describes how to orchestrate API, RPC, and event operations that source documents already describe without duplicating methods, paths, channels, messages, schemas, servers, or security schemes.
Source documents own the API or event contract. UWS owns the workflow overlay.
This is what distinguishes UWS from full client-side workflow tools such as Arazzo and IaC engines such as OpenTofu and Terraform. Arazzo describes full client-side action sequences and treats each step as a bespoke client action. OpenTofu and Terraform act as full client-side workflow engines for infrastructure: each resource and provider call is described in the client configuration and resolved against a provider plugin at apply time. Neither approach assumes the underlying operations are already defined by a server contract. UWS takes the opposite position: server actions are pre-defined by the source document, and UWS workflows reference those operations by ID rather than re-describing them. The result is a much smaller overlay: UWS does not duplicate request/response shapes, does not redeclare endpoints, and does not encode anything the source document already specifies.
UWS 1.6 keeps OpenAPI compatibility and adds first-class source descriptions for openapi, google-discovery, aws-smithy, asyncapi, graphql, openrpc, grpc-protobuf, odata, browser-profile, and ansible-module. Missing sourceDescription.type defaults to openapi; legacy OpenAPI selectors remain valid for OpenAPI sources. The browser profile sub-spec is published separately as versions/browser.1.5.{json,md} and the Ansible module sub-spec as versions/ansible.1.0.{json,md}.
Why UWS?
Many API providers already publish OpenAPI. Once those documents exist, a workflow layer should stay focused on workflow concerns:
- which operations participate
- how they depend on each other
- how values flow between them
- which structural constructs shape control flow
- which triggers start execution
- which semantics are portable across runtimes
UWS answers exactly those questions and nothing else.
Beyond document shape, UWS also defines a normative execution model: a clean split between an orchestrator that owns structural workflow execution (dependency resolution, control flow, retry, output propagation) and a bound runtime that owns leaf execution (API/event calls, expression evaluation, item resolution). This split is what makes UWS portable — any compliant runtime shares the same orchestration semantics while bringing its own transport, credentials, and extension-profile logic.
For non-source leaf work, UWS keeps the core document narrow. Extension-owned operations declare x-uws-operation-profile; the public uws.runtime.1.0 supplement optionally adds a small x-uws-runtime payload with a required non-HTTP type selector such as fnct, cmd, sql, or llm. HTTP and event calls still use source binding fields, not x-uws-runtime.
A Minimal Document
{
"uws": "1.6.0",
"info": { "title": "Weather Report", "version": "1.1.0" },
"sourceDescriptions": [
{ "name": "weather_api", "url": "./weather.openapi.yaml", "type": "openapi" },
{ "name": "gmail_api", "url": "./gmail.openapi.yaml", "type": "openapi" }
],
"operations": [
{
"operationId": "current_weather",
"sourceDescription": "weather_api",
"sourceOperationId": "getCurrentWeather",
"request": { "query": { "q": "Los Angeles", "units": "imperial" } },
"outputs": { "summary": "$response.body.summary" }
},
{
"operationId": "send_report",
"sourceDescription": "gmail_api",
"sourceOperationId": "sendMessage",
"dependsOn": ["current_weather"],
"request": { "body": { "userId": "me", "text": "$steps.get_weather.outputs.summary" } }
}
],
"workflows": [
{
"workflowId": "main",
"type": "sequence",
"steps": [
{ "stepId": "get_weather", "operationRef": "current_weather" },
{ "stepId": "send_email", "operationRef": "send_report" }
]
}
]
}
No HTTP method, no path, no server URL, no response schema — those live in the referenced source documents. UWS points at the operations and describes how the workflow uses them.
Executing a Document
A UWS document is not just a description — it is executable. Bind a runtime, call Execute, and UWS core orchestrates the entire workflow:
doc.SetRuntime(rt) // bind your source/extension runtime
if err := doc.Execute(ctx); err != nil {
log.Fatal(err)
}
records := doc.ExecutionRecords() // inspect what ran
The orchestrator owns all structural concerns: dependency resolution, parallel scheduling, conditional branching, loop iteration, retry counting, and trigger routing. The bound runtime owns only leaf work: making the actual source operation call, evaluating expressions, and resolving iteration items. This split gives compliant runtimes the same orchestration semantics while leaving transport and provider behavior runtime-owned.
Reference
- Specification:
versions/1.6.0.md - JSON Schema:
versions/1.6.0.json - Runtime supplement:
versions/runtime.1.0.md - Runtime supplement schema:
versions/runtime.1.0.json - Ansible module supplement:
versions/ansible.1.0.md - UWS 1.6 Ansible design: accepted design note
- Future source profiles: UWS 1.1 import/advisory features, UWS 1.4 source profiles, UWS 1.5 browser capability profiles, and UWS 1.6 Ansible module profiles
- Go package:
github.com/OpenUdon/uws - License: Apache 2.0
Start Authoring
If you need to hand-write a workflow, start with the practical workflow authoring guide. It shows the minimal YAML shape, operation binding, request values, output flow, workflow steps, triggers, extensions, and a validation checklist before the full specification.
The 10 Major Features
| # | Feature | Summary |
|---|---|---|
| 1 | Source Operation Binding | Strict binding to OpenAPI, Google Discovery, AWS Smithy, AsyncAPI, GraphQL, OpenRPC, gRPC/protobuf, OData, browser profiles, Ansible modules, or extension-owned operations |
| 2 | Six Structural Constructs | sequence · parallel · switch · loop · merge · await |
| 3 | Runtime Expression Grammar | Normative ABNF expression language for value flow |
| 4 | Triggers and Route Dispatch | Typed entry points with output-based routing |
| 5 | Structural Results | Named outputs linked back to their source construct |
| 6 | Success Criteria and Actions | Inline retry, goto, end with per-criterion scoping |
| 7 | Execution Model | Orchestrator/runtime split for portable semantics |
| 8 | Extension Profiles | Non-HTTP operations via x-uws-operation-profile |
| 9 | Validation | Two-layer structural + semantic validation |
| 10 | Interchange Formats | JSON, YAML, and HCL with round-trip guarantees |