Dynamic agent workflows are available for internal use and private beta. For stable production extraction, use structured extraction or built-in invoice workflows.
Overview
Dynamic agent workflows let you express a document workflow as plain JavaScript:agent()runs one prompted agent call and requires a JSON Schema return contract.parallel()runs multiple agent calls behind a fan-out barrier.pipeline()maps work across pages, files, rows, providers, or other input arrays.phase()marks a named stage boundary for traceability and review.
When to use it
Use dynamic agent workflows when a single extraction prompt is not enough:| Pattern | Example |
|---|---|
| Provider A/B tests | Run text layer, VLM OCR, and a vendor parser on the same pages, then judge discrepancies. |
| N-provider fan-out | Compare multiple extraction providers against one typed schema. |
| Risk-controlled OCR | Probe the same page under multiple views and accept only consensus outputs. |
| Human review splits | Run detect, emit review artifacts, then apply changes in a second phase after approval. |
| Policy-controlled runs | Enforce user budget, privacy, provider, and mutation limits around every agent/tool call. |
Authoring grammar
Every script is a JavaScript controller. It can include loader-readable metadata, controller variables, loops, branches, andreturn.
meta must be a pure object literal when present. Use it for human-facing names and phase descriptions; do not put runtime logic in it.
Every real unit of work should be an agent() call with a task prompt and a JSON Schema under the schema key.
schema. Do not use returns, output_schema, or json_schema.
Controller API
| API | Shape | Notes |
|---|---|---|
args | const docId = args.document_id | Run inputs passed from run_workflow or POST /v1/runs. |
phase(label) | phase("Extract") | Marks the current stage for events and UI traces. |
agent(prompt, options) | await agent("Extract rows.", { label, schema }) | Runs one schema-contracted worker agent. |
agent(options) | await agent({ prompt, label, schema, phase }) | Object style, useful for generated scripts. |
parallel(items) | await parallel([() => agent(...), () => agent(...)]) | Fan-out barrier. Prefer thunks so the parallel group owns when work starts. |
pipeline(items, mapper, options) | await pipeline(pages, page => agent(...), { concurrency: 4 }) | Sequential by default. concurrency is capped at 16. |
log(...items) | log("judge input", summary) | Adds trace logs without becoming a workflow step. |
return value | return judged | Becomes controller_output on the run. |
Readiness model
There are two workflow types:| Type | How readiness works |
|---|---|
| Finite catalog definitions | Okra can recompute readiness from definition.steps, so validateWorkflowDefinitionReadiness(...) applies. |
| Agent workflow scripts | Okra treats the script as code. Readiness is ready or parse_error, based on the loader/analyzer result. There is no valid or invalid verdict from a finite-DAG validator. |
planned field is only an estimate from AST analysis. It can count literal phase(), agent(), and parallel() calls, but loops and pipeline() can emit more or fewer agents at runtime.
Run failures are execution state, not blueprint validity. If the controller throws before any agent() starts, the run can fail with no completed agent steps. If an agent returns invalid JSON, the run records the agent failure and schema errors.
Run from MCP
Connect your client to the OkraPDF MCP server, then use:| Tool | Purpose |
|---|---|
draft_workflow | Save the workflow source and return its workflow id, readiness, AST, visualization, and static agent analysis. |
run_workflow | Start a run for a saved workflow. |
view_workflow_run | Read run status, controller output, per-agent outputs, events, logs, and errors. |
view_workflow | Inspect a workflow blueprint before running it. For agent scripts, validation is null and readiness comes from the script analysis. |
Run from the API
Create a workflow resource from a JavaScript source file:Run trace
Runs return both final output and a trace of agentic events. The event stream is the product-level provenance layer for debugging and review.run.started, phase.entered, parallel.started, agent.started, schema.validated, agent.completed, agent.failed, log, run.completed, and run.failed.
Parallel patterns
For simple fan-out, pass agent promises:Current boundary
Dynamic agent workflows are ready for internal workflows, demos, MCP-driven authoring, and playground A/B tests. They are not yet the public untrusted-user sandbox for arbitrary long-running code. Under the hood, Okra stores the author-facing script, analyzes its AST for visualization, runs host-managed agents with strict JSON contracts, and returns traceable events. The next production-hardening step is lowering eachagent() call into durable Cloudflare Workflow step.do() boundaries while keeping the same authoring grammar.