Arazzo workflows
How an Arazzo 1.1.0 workflow is an agent plan, and how permdock simulate pre-flights every step by resolving its operationId to the operation's x-permdock-permissions and returning one Decision per step before anything executes.
Status: planned Phase: 4
What it is
The Arazzo Specification 1.1.0 (released 17 May 2026, announcement) describes workflows: sequences of API calls with dependencies between them, inputs, outputs and success criteria. An Arazzo document has:
| Field | Meaning |
|---|---|
arazzo | The Arazzo specification version, 1.1.0 |
info | Title and version of the workflow document |
sourceDescriptions | The API descriptions the workflows call into: type: openapi, type: arazzo (another workflow document) and, since 1.1, type: asyncapi |
workflows | Named workflows, each with inputs, ordered steps, outputs and success criteria |
steps[] | Each step points at one operationId or operationPath in a source description, or at another workflowId; it declares parameters, requestBody, successCriteria, outputs and what to do on success or failure |
1.1 adds AsyncAPI sources (send / receive style steps with correlation), typed parameters on actions that call another workflowId, and better data selection (Selector Object, JSONPath). 1.0.x documents remain valid.
Why it matters for PermDock
An Arazzo workflow is a plan: an ordered list of operations somebody intends to call, with the data flowing between them. That is exactly what an agent produces before it acts, and exactly what permdock.simulate was designed to evaluate (decisions, for AI agents). Today simulate takes an array of [permission, data] pairs the caller assembles by hand. An Arazzo document assembles them for free: each step names an operationId, the referenced OpenAPI description carries x-permdock-permissions on that operation (OpenAPI 3.2), and the permission keys resolve to leaves in the catalog.
The result is a pre-flight for a whole workflow, not a single call: before an agent (or a workflow runner, or a CI job) executes step one, PermDock reports which steps would be granted, which denied and with what alternatives, and which would stop at approval-required, so the approval can be requested up-front instead of halfway through a plan with side effects already committed. This is the OWASP ASI02 "bound the plan before the first side effect" control applied to a standard workflow format (OWASP agentic).
How PermDock uses it
A workflow is an agent plan
import { readFile } from 'node:fs/promises'
import { PermDockDeniedError } from 'permdock'
import { createPermDock } from 'permdock/node'
import { policy } from './policy'
const arazzo = JSON.parse(await readFile('./workflows/publish-post.arazzo.json', 'utf8'))
const openapi = JSON.parse(await readFile('./openapi.json', 'utf8')) // after the Overlay is applied
const permdock = createPermDock(policy, { subject }) // subject: the principal (and actor) the plan runs for
const plan = await permdock.simulate({ arazzo, openapi, subject, workflowId: 'publishPost' }) // subject shape: see open questions
// {
// workflowId: 'publishPost',
// outcome: 'approval-required', // worst outcome across steps: denied > approval-required > granted
// steps: [
// { stepId: 'loadDraft', operationId: 'getPost', permissions: [permissions.post.read], decision: { outcome: 'granted', ... } },
// { stepId: 'editDraft', operationId: 'updatePost', permissions: [permissions.post.update], decision: { outcome: 'granted', ... } },
// { stepId: 'publish', operationId: 'publishPost', permissions: [permissions.post.publish], decision: { outcome: 'approval-required', reason: 'human', ... } },
// ],
// }
const blocked = plan.steps.filter((s) => s.decision.outcome !== 'granted')
if (blocked.some((s) => s.decision.outcome === 'denied')) throw new PermDockDeniedError(blocked[0].decision)
for (const step of blocked) await requestApproval(step) // approval-required steps, before step one runsWhat simulate({ arazzo, openapi, subject }) does, step by step:
- Validates the Arazzo document (
arazzo: 1.1.0or1.0.x) and finds thesourceDescriptionsoftype: openapi. Theopenapiargument supplies the resolved description for those sources; a workflow with several OpenAPI sources takes a map keyed by sourcename. - For each step of the selected workflow, resolves
operationId(oroperationPath) to an operation in the description and reads itsx-permdock-permissions. Steps that reference aworkflowIdare expanded recursively; cycles are an error. - Each permission key is looked up with
findPermissionin the catalog. An operation with nox-permdock-permissionsproduces a step withpermissions: []anddecision.outcome: 'denied'with reasonundocumented; a workflow cannot be cleared through a hole in the description (fail closed). - For
actionspermissions (those that take an instance), the step'sparametersand the workflowinputsare used to build the resource identifier; when the instance cannot be loaded ahead of time (it is produced by an earlier step'soutputs), the decision is evaluated with the instance-independent part of the grant and markedprovisional: true, meaningprotectwill decide again at execution time with the real row. - All
[permission, data]pairs are passed to the existingsimulatebatch, so the semantics are unchanged: noon('decision')events per step (onesimulateevent for the plan), no approval tokens issued, no quota consumed. - The result lists one
Decisionper step in workflow order plus the worstoutcomeacross steps.
Where the documents come from
simulate reads the applied description: the producer's output with PermDock's Overlay merged, not the source before it. Without the Overlay no operation carries x-permdock-permissions and every step is denied with reason undocumented (OpenAPI Overlay). Arazzo documents themselves come from wherever the team writes them; two producers worth naming because they share the operationId join key with PermDock:
- next-openapi-gen compiles an
arazzoblock into workflow files after the spec write, against the generatedoperationIds, and applies Overlay files first, so its output is already the applied description. - Redocly CLI's
generate-arazzodrafts a workflow from an OpenAPI description andrespectexecutes one (commands);simulatesits between the two as the authorization pre-flight.
PermDock composes with these rather than wrapping them (ADR 0023); none is a dependency, and none moves simulate earlier than Phase 4.
Surfacing approval-required steps
An approval-required step tells the caller that executing it will stop for a human (or a policy-defined approver) unless approval is obtained first. Because simulate issues no tokens, the caller uses the step list to request approval before running the workflow; the approval flow and the binding of an approval token to permission key, resource id, subject and actor are described on approvals. Whether one approval can cover a whole plan is an open question on that page; until it is decided, each approval-required step needs its own approval and the step's decision carries what to ask for.
permdock arazzo check (later)
A CLI command, planned for Phase 4 and not yet listed in the CLI command table, that runs the resolution half of simulate without a subject:
permdock arazzo check --doc workflows/publish-post.arazzo.json --openapi openapi.jsonIt fails (exit 1) when a step's operationId does not exist in the referenced description, when the operation has no x-permdock-permissions, or when a key does not exist in the catalog. It is the workflow counterpart of permdock openapi --check: the document says what each call requires, and the workflow must only call documented operations.
Out of scope
- AsyncAPI steps. Arazzo 1.1 allows
sourceDescriptionsoftype: asyncapiand send / receive style steps. PermDock has no AsyncAPI adapter and does not emitx-permdock-permissionsinto AsyncAPI documents, so those steps are reported asunsupportedand the plan's outcome isdenieduntil an adapter exists. This is not a Phase 4 deliverable. - Executing workflows. PermDock pre-flights and guards; it does not run steps. Runners keep calling the API, where
protectdecides for real. - Import from Arazzo. Generating permission definitions from a workflow document is not planned; permissions come from the OpenAPI description or the catalog (CLI: openapi).
Mapping table
| Arazzo concept | PermDock concept |
|---|---|
| Workflow | A plan passed to simulate({ arazzo, openapi, subject }) |
Step with operationId / operationPath | One [permission, data] entry per key in the operation's x-permdock-permissions |
Step with workflowId | Expanded into that workflow's steps |
sourceDescriptions[type=openapi] | The openapi argument (one description or a map by source name) |
sourceDescriptions[type=asyncapi] | Unsupported until an AsyncAPI adapter exists; step denied |
inputs, step parameters | Resource identifier for instance-level permissions |
outputs feeding a later step | provisional: true decision; re-decided by protect at execution |
successCriteria | Not evaluated; PermDock decides authorization, not success |
Operation without x-permdock-permissions | denied, reason undocumented (fail closed) |
| Whole workflow | outcome = worst step outcome; one simulate audit event |
Sources
- Arazzo Specification 1.1.0.
- Arazzo announcement, OpenAPI Initiative.
- Agent standards research: the "workflow-step permission requirements" item, previously not pursued and now scheduled for Phase 4.
- OpenAPI ecosystem research: the producers that emit Arazzo files and the applied-description rule.
Related
- Decisions:
simulatesemantics. - OpenAPI 3.2 and OpenAPI Overlay: where
x-permdock-permissionscomes from. - OpenAPI registries: the extension namespace.
- Approvals: what happens to
approval-requiredsteps. - OWASP agentic: plan bounding as an ASI02 control.
- AuthZEN: the boxcar wire form
simulatealready uses. - For AI agents.
Open questions
- The exact
simulateoverload: an object argument on the instance as shown, or a separatepermdock/arazzoentry, and whethersubjectis taken from the instance or passed explicitly for pre-flighting on behalf of another principal. - How
provisionaldecisions should be presented so an agent does not treat them as final grants. - Whether
permdock arazzo checkbelongs underpermdock openapias a subcommand, since it reads the same description. - Whether a plan-level approval token (one approval for all
approval-requiredsteps) is acceptable; tracked on approvals.
OpenAPI Overlay
How permdock openapi --format overlay emits an Overlay 1.1.0 document (or, behind --overlay 1.2, the pinned Overlay 1.2 draft with reusable actions) that adds security, securitySchemes and x-permdock-* fields to an OpenAPI description without mutating it, how to apply and check it in CI, and why the Overlay never removes security.
OpenAPI registries
The OpenAPI Initiative registries, the x-permdock- namespace PermDock emits, which registered x-oai-* and x-agent-trust extensions it reuses, and the rule for never inventing names in someone else's namespace.