Many automation setups rely on fragile selectors or brittle APIs that break when layout changes. The Coasty Workflow DSL lets you orchestrate a computer use agent with clear, versioned steps. You can run tasks, validate they succeed with assert, branch logic with if, iterate loops, and launch parallel jobs. Each task step costs $0.05. This DSL is versioned JSON that you submit to the /v1/workflows endpoint.
Workflow DSL structure
A workflow is a versioned JSON object. You POST it to /v1/workflows, then POST /v1/workflows/{id}/runs to start it. The workflow object contains a version, steps, and optional variables. Each step has a type and structured fields. The supported step types are task, assert, if, loop, parallel, human_approval, retry, succeed, fail. You can include hard guards such as budget_cents, max_iterations, and deadline_seconds.
Task steps
Task steps tell the agent to perform a computer use action. You provide a task string that can describe clicking, typing, scrolling, or using tools. Each task step is billed $0.05. Example fields include task, cua_version (default v3, v4 for autonomous verifier), and optional instructions that append to the base prompt. The agent captures screen, predicts, and acts until the task is done.
Assert steps
Assert steps validate that a condition holds after a preceding step. You can assert on a screenshot, element description, or result state. The assert step does not trigger actions. It checks the current state and if the assertion fails, the workflow fails. This allows you to verify results without writing brittle selectors. You can include an assert message for clarity.
If conditional branches
The if step lets you branch execution based on conditions. The condition is a structured object that can reference workflow variables. You can use double-brace syntax like {{inputs.username}} or stepId.field. If the condition is true, the if step runs its then steps; otherwise it runs its else steps. This lets you handle success paths, retry scenarios, or environment checks dynamically.
Loop steps
Loop steps repeat a block of steps until a condition is met or a max_iterations limit is reached. You can define a condition that evaluates to true to exit the loop. The loop counts iterations and stops after max_iterations. This is useful for polling until a page loads, retrying a login, or iterating over a list of items. Each iteration runs the loop body steps.
Parallel execution
Parallel steps let you run multiple workflows or tasks concurrently. Each parallel branch is a list of steps that run in parallel. The workflow waits for all branches to complete before proceeding. This is ideal for launching multiple agents at once, such as testing a feature across different browsers, or running independent validation jobs. Parallel branches do not share a single step ID.
import os, json, requests, time
def run_workflow():
api_key = os.getenv("COASTY_API_KEY")
url = "https://coasty.ai/v1/workflows"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
workflow = {
"version": "1.0",
"steps": [
{
"type": "task",
"task": "open https://example.com",
"cua_version": "v3"
},
{
"type": "assert",
"assert": {
"description": "page title contains example"
}
},
{
"type": "if",
"condition": {
"var": "titleMatches"
},
"then": [
{
"type": "task",
"task": "click id=submit"
},
{
"type": "assert",
"assert": {
"description": "success message visible"
}
}
],
"else": [
{
"type": "task",
"task": "report error"
},
{
"type": "fail",
"message": "assertion failed"
}
]
},
{
"type": "loop",
"max_iterations": 5,
"condition": {
"var": "dataLoaded"
},
"steps": [
{
"type": "task",
"task": "wait for element id=table"
},
{
"type": "assert",
"assert": {
"description": "table rows present"
}
}
]
},
{
"type": "parallel",
"branches": [
{
"steps": [
{
"type": "task",
"task": "verify mobile layout"
}
]
},
{
"steps": [
{
"type": "task",
"task": "verify accessibility"
}
]
}
]
},
{
"type": "succeed"
}
],
"hard_guards": {
"max_iterations": 20,
"deadline_seconds": 300
}
}
resp = requests.post(url, headers=headers, json=workflow)
resp.raise_for_status()
workflow_resp = resp.json()
workflow_id = workflow_resp["id"]
print("Created workflow", workflow_id)
runs_url = f"https://coasty.ai/v1/workflows/{workflow_id}/runs"
run_resp = requests.post(runs_url, headers=headers)
run_resp.raise_for_status()
run = run_resp.json()
print("Started run", run["id"])
while True:
time.sleep(5)
run_url = f"https://coasty.ai/v1/runs/{run['id']}"
run_status = requests.get(run_url, headers=headers).json()
print("Run state", run_status["state"])
if run_status["state"] in ("succeeded", "failed", "cancelled", "timed_out"):
break
if __name__ == "__main__":
run_workflow()Each task step costs $0.05. Use assert for validation, if for branching, loop for repetition, and parallel for concurrent jobs. Version your workflow JSON and POST it to /v1/workflows.
Where this beats brittle automation
Traditional automation often relies on fixed selectors that break when UI changes. The Workflow DSL lets the agent see the screen and act like a human. With task steps, assert steps, and real-time reasoning, you can build agents that adapt to layout changes. Conditional logic with if and retry loops handle transient failures gracefully. Parallel execution scales independent checks in parallel, reducing total runtime. You can version your DSL, replay runs, and integrate with webhooks. This approach replaces brittle selectors with robust, human-like computer use.
You now know how to compose a Workflow DSL with task, assert, if, loop, and parallel steps. Build reliable computer use agents that see, act, and validate like a human. Get a key and start building workflows at https://coasty.ai/developers.
Want to see this in action?
View Case Studies