Quick Start: Author Your First UWS Workflow
This guide is for authors who need to hand-write a UWS document without reading the full specification first. It focuses on the common path: bind existing OpenAPI operations, put them in a workflow, pass values between steps, and leave concrete credentials to the runtime.
UWS is a workflow overlay. OpenAPI owns HTTP methods, paths, schemas, servers, and security. UWS owns operation binding, workflow structure, request values, outputs, triggers, and control flow.
Start With Three Files
Keep the API contract, workflow, and runtime configuration separate:
openapi/
support.yaml
workflow.uws.yaml
runtime-config.json # runtime-owned, not UWS core
The UWS document points to OpenAPI. It does not copy endpoint URLs, schemas, or credentials out of the OpenAPI document.
Minimal Workflow
uws: "1.1.0"
info:
title: Support Ticket Workflow
version: "1.0.0"
sourceDescriptions:
- name: support_api
url: ./openapi/support.yaml
type: openapi
operations:
- operationId: create_ticket
sourceDescription: support_api
openapiOperationId: createTicket
request:
body:
subject: "Example ticket"
priority: normal
outputs:
ticket_id: "$response.body.id"
- operationId: get_ticket
sourceDescription: support_api
openapiOperationId: getTicket
dependsOn: [create_ticket]
request:
path:
ticketId: "$steps.create.outputs.ticket_id"
outputs:
status: "$response.body.status"
workflows:
- workflowId: main
type: sequence
steps:
- stepId: create
operationRef: create_ticket
- stepId: verify
operationRef: get_ticket
This document declares:
- One OpenAPI source named
support_api. - Two UWS-local operations,
create_ticketandget_ticket. - One workflow named
main. - Two sequence steps, where
verifycan refer to the output of stepcreate.
Step 1: Declare OpenAPI Sources
Use sourceDescriptions for every OpenAPI document the workflow references:
sourceDescriptions:
- name: support_api
url: ./openapi/support.yaml
type: openapi
Rules of thumb:
nameis the stable local handle used by operations.urlcan be a local path or reviewed remote location, depending on the runtime.type: openapikeeps the source explicit.
Step 2: Bind Operations
The most common operation binding uses sourceDescription plus openapiOperationId:
operations:
- operationId: create_ticket
sourceDescription: support_api
openapiOperationId: createTicket
operationId is local to the UWS file. openapiOperationId is the operation ID from the referenced OpenAPI document.
Do not add HTTP method, path, server URL, or security configuration here. Those belong to OpenAPI and the bound runtime.
Step 3: Add Request Values
Request values are grouped by OpenAPI location:
request:
path:
ticketId: "$steps.create.outputs.ticket_id"
query:
includeHistory: "true"
header:
X-Request-Source: review
body:
priority: normal
Use runtime expressions when a value comes from a previous step, workflow input, trigger, variable, or response.
Step 4: Name Outputs
Outputs turn response values into stable handles:
outputs:
ticket_id: "$response.body.id"
status: "$response.body.status"
Common expression roots:
$response.body: response body from the current operation.$response.headers: response headers from the current operation.$steps.<stepId>.outputs.<name>: output from a previous step in the same workflow.$inputs.<name>: workflow input.$variables.<name>: reusable document variable.$trigger: trigger payload during trigger dispatch.
Keep expressions simple unless your runtime documents extensions beyond UWS core.
Step 5: Compose Workflows
A sequence workflow runs steps in order:
workflows:
- workflowId: main
type: sequence
steps:
- stepId: create
operationRef: create_ticket
- stepId: verify
operationRef: get_ticket
Use the six structural types when needed:
sequence: run steps in declaration order.parallel: run independent steps concurrently.switch: choose a branch.loop: repeat over items.merge: join control-flow branches.await: wait until a runtime expression becomes true.
Start with sequence. Add other constructs only when the workflow needs them.
Add A Branch
workflows:
- workflowId: classify_ticket
type: switch
cases:
- name: closed
when: "$steps.verify.outputs.status == \"closed\""
steps:
- stepId: archive
operationRef: archive_ticket
default:
- stepId: notify_owner
operationRef: notify_owner
Switch cases contain branch steps. Keep branch conditions in the core expression grammar when portability matters.
Add A Trigger
triggers:
- triggerId: new_ticket
outputs:
- accepted
routes:
- output: accepted
to: [main]
Trigger ingress, authentication, hosting, output classification, and persistence are runtime-owned. UWS only describes declared output labels and route dispatch after a trigger event has been accepted.
Extension-Owned Operations
If a step is not an OpenAPI operation, make that explicit with an extension profile:
operations:
- operationId: render_message
x-uws-operation-profile: uws.runtime.1.0
x-uws-runtime:
type: fnct
function: render_message
arguments:
- template: "Ticket {{ticket_id}} is ready"
UWS validates the shape and references. The bound runtime decides whether it supports the named extension profile.
When you use the public uws.runtime.1.0 supplement, x-uws-runtime.type is required and must be one of the supplement's non-HTTP runtime selectors. Use OpenAPI operation bindings for HTTP calls; do not model HTTP as x-uws-runtime.type: http.
Validation Checklist
Before handing a workflow to a runtime:
- Every
sourceDescriptionname is unique. - Every OpenAPI-bound operation names an existing source.
- Every local
operationId,workflowId, and stepstepIdis unique where required. - Every
operationRef,workflow, trigger route, and dependency target resolves. - Request values do not contain secrets.
- Credentials and endpoint policy are supplied by the runtime, not embedded in UWS.
- Extension-owned operations declare an explicit
x-uws-operation-profile. uws.runtime.1.0operations includex-uws-runtime.type; HTTP calls remain OpenAPI-bound.