Arazzo Workflow Authoring Skill
Arazzo describes end-to-end API workflows. This skill generates comprehensive test coverage for ALL API operations.
References: expressions | validation | spec
GENERATION PROCESS (MANDATORY)
Phase 1: Discovery
# 1.1 Find OpenAPI spec
find . -name "*.yaml" -o -name "*.json" | xargs grep -l "openapi\|swagger" 2>/dev/null
# 1.2 Analyze repo structure
ls -la && ls -la src/ lib/ api/ 2>/dev/null
# 1.3 Extract ALL operations - list every path + method, note auth requirements, map CRUD patterns
Phase 2: Plan ALL Workflows
| Category | Workflows to Generate |
|---|---|
| CRUD (per resource) | create{R}, get{R}ById, update{R}, delete{R}, full{R}Lifecycle |
| Auth | login, register, tokenRefresh, logout |
| Lists | list{R}s, search{R}s, paginated{R}List |
| Relationships | create{Parent}Then{Child}, get{Parent}With{Children} |
| Errors | unauthorized{R}, notFound{R}, validationError{R} |
| Edge Cases | duplicate{R}, boundary{R}Values |
Phase 3: Generate Single Comprehensive File
arazzo: 1.0.1
info:
title: Complete API Test Suite
version: 1.0.0
sourceDescriptions:
- name: api
url: ./openapi.yaml
type: openapi
workflows:
- workflowId: loginWorkflow
# ... ALL workflows from Phase 2
SUCCESS CRITERIA (ALL must pass)
| Check | Command | Pass |
|---|---|---|
| 1. OpenAPI found | ls -la <spec> | Spec exists |
| 2. Ops identified | grep -E "^\s+(get|post|put|patch|delete):" <spec> | wc -l | All counted |
| 3. File exists | ls -la <arazzo> | Size > 0 |
| 4. YAML valid | python -c "import yaml; yaml.safe_load(open('<arazzo>'))" | Silent success |
| 5. Arazzo valid | openapi arazzo validate <arazzo> | Exit 0 |
| 6. Coverage | grep -c "workflowId:" <arazzo> | Covers all ops + errors |
ONLY mark complete when ALL 6 checks pass.
Quick Reference
Workflow: workflowId (required), summary, inputs (JSON Schema), steps (required), outputs, dependsOn, failureActions
Step: stepId (required), ONE of operationId/operationPath/workflowId, parameters (need in), requestBody, successCriteria, outputs
Critical Syntax
operationPath
"{$sourceDescriptions.<name>.url}#/paths/~1<escaped-path>/<method>"
Escaping: / → ~1, ~ → ~0
# /api/users → POST
operationPath: "{$sourceDescriptions.api.url}#/paths/~1api~1users/post"
# /users/{id} → GET
operationPath: "{$sourceDescriptions.api.url}#/paths/~1users~1{id}/get"
JSONPath (RFC 9535)
# WRONG
condition: $.user != null
# CORRECT - must use $[?(@...)]
condition: $[?(@.user != null)]
Outputs (expressions only, no literals)
# WRONG
outputs:
success: true
# CORRECT
outputs:
userId: $response.body#/id
Workflow Templates
Auth
- workflowId: loginWorkflow
inputs:
type: object
properties:
email: { type: string }
password: { type: string }
steps:
- stepId: login
operationPath: "{$sourceDescriptions.api.url}#/paths/~1auth~1login/post"
requestBody:
contentType: application/json
payload:
email: "{$inputs.email}"
password: "{$inputs.password}"
successCriteria:
- condition: $statusCode == 200
- context: $response.body
type: jsonpath
condition: $[?(@.token != null)]
outputs:
token: $response.body#/token
outputs:
token: $steps.login.outputs.token
Full CRUD Lifecycle
- workflowId: fullUserLifecycle
inputs:
type: object
properties:
token: { type: string }
steps:
- stepId: create
operationPath: "{$sourceDescriptions.api.url}#/paths/~1users/post"
parameters:
- name: Authorization
in: header
value: "Bearer {$inputs.token}"
requestBody:
contentType: application/json
payload:
name: "Test User"
email: "test@example.com"
successCriteria:
- condition: $statusCode == 201
outputs:
userId: $response.body#/id
- stepId: read
operationPath: "{$sourceDescriptions.api.url}#/paths/~1users~1{id}/get"
parameters:
- name: Authorization
in: header
value: "Bearer {$inputs.token}"
- name: id
in: path
value: $steps.create.outputs.userId
successCriteria:
- condition: $statusCode == 200
- stepId: update
operationPath: "{$sourceDescriptions.api.url}#/paths/~1users~1{id}/put"
parameters:
- name: Authorization
in: header
value: "Bearer {$inputs.token}"
- name: id
in: path
value: $steps.create.outputs.userId
requestBody:
contentType: application/json
payload:
name: "Updated"
successCriteria:
- condition: $statusCode == 200
- stepId: delete
operationPath: "{$sourceDescriptions.api.url}#/paths/~1users~1{id}/delete"
parameters:
- name: Authorization
in: header
value: "Bearer {$inputs.token}"
- name: id
in: path
value: $steps.create.outputs.userId
successCriteria:
- condition: $statusCode == 200
Error Workflows
- workflowId: unauthorizedAccess
steps:
- stepId: noAuth
operationPath: "{$sourceDescriptions.api.url}#/paths/~1users/get"
successCriteria:
- condition: $statusCode == 401
- workflowId: notFound
inputs:
type: object
properties:
token: { type: string }
steps:
- stepId: getMissing
operationPath: "{$sourceDescriptions.api.url}#/paths/~1users~1{id}/get"
parameters:
- name: Authorization
in: header
value: "Bearer {$inputs.token}"
- name: id
in: path
value: "nonexistent-id"
successCriteria:
- condition: $statusCode == 404
- workflowId: validationError
inputs:
type: object
properties:
token: { type: string }
steps:
- stepId: badData
operationPath: "{$sourceDescriptions.api.url}#/paths/~1users/post"
parameters:
- name: Authorization
in: header
value: "Bearer {$inputs.token}"
requestBody:
contentType: application/json
payload:
email: "invalid"
successCriteria:
- condition: $statusCode == 400 || $statusCode == 422
List/Pagination
- workflowId: listWithPagination
steps:
- stepId: firstPage
operationPath: "{$sourceDescriptions.api.url}#/paths/~1users/get"
parameters:
- name: page
in: query
value: "1"
- name: limit
in: query
value: "10"
successCriteria:
- condition: $statusCode == 200
Common Errors
| Error | Fix |
|---|---|
operationPath must contain json pointer | Use #/paths/~1<path>/<method> |
must reference the url | Use .url not .name |
invalid jsonpath | Use $[?(@.field op value)] |
must begin with $ | No literals in outputs |
parameter missing 'in' | Add in: path/query/header/cookie |
exactly one of operationId... | Use only ONE per step |