| 1 | # Workflow Authoring |
| 2 | |
| 3 | > **Ordinary multi-agent work does not require this file.** In Operate, send |
| 4 | > normal messages; Codewhale can work directly or prefer background workers |
| 5 | > when parallelism, isolation, or duration makes delegation useful. Use Workflow |
| 6 | > when ordered phases, gates, shared budgets, replay, or deterministic fan-in |
| 7 | > matter; Act/Agent may also use optional soft-auto launch. See |
| 8 | > [Automatic Workflows](AUTOMATIC_WORKFLOWS.md). |
| 9 | |
| 10 | Workflow has one runtime boundary: authored source lowers to typed |
| 11 | Rust `WorkflowSpec`, Rust validates the IR, and the scheduler/headless worker |
| 12 | runtime executes leaves. Authoring languages do not get hidden authority to own |
| 13 | files, shell, network, providers, cancellation, or TUI state. |
| 14 | |
| 15 | Compatibility launch paths on the `workflow` tool: |
| 16 | |
| 17 | | Input | When to use | |
| 18 | |-------|-------------| |
| 19 | | `plan` | Structured goal / phases / children (preferred agent path) | |
| 20 | | `script` | Short inline JS the model owns | |
| 21 | | `source_path` | Checked-in `.workflow.js` / `.workflow.ts` in the workspace | |
| 22 | |
| 23 | For a guided walkthrough from Fleet task specs to Workflow authoring and |
| 24 | monitoring, see [Fleet + Workflow Tutorial](FLEET_WORKFLOW_TUTORIAL.md). |
| 25 | |
| 26 | |
| 27 | ## Access model |
| 28 | |
| 29 | The Workflow script is a **coordinator only**. It has no filesystem or shell of |
| 30 | its own. Real work happens in sub-agents the script launches. |
| 31 | |
| 32 | | Layer | What it can access | |
| 33 | |-------|--------------------| |
| 34 | | Workflow script (JS VM) | Script variables, branching/loops, `task()` / `parallel()` / `pipeline()`, `phase` / `log`, `budget` / `args`. **No** direct FS, shell, network, env, imports, clock, or randomness. | |
| 35 | | Workflow-spawned sub-agents | Normal tool surface (read/search/edit/write, shell, web, MCP) subject to role posture, allowlists, and parent policy. File edits for write-capable roles auto-accept under Workflow; shell / web / MCP still require parent auto-approve or fail closed. | |
| 36 | | Parent session | Working directory, configured tools/MCP, permission mode, sandbox/network rules. | |
| 37 | |
| 38 | ### Scale |
| 39 | |
| 40 | - Up to **16 concurrent** live agents in one run (additional spawns wait for a slot). |
| 41 | - Up to **1_000 agents per run** (VM lifetime spawn cap). |
| 42 | - Soft auto-launch still uses a lower child soft-cap (`auto_start_child_limit`). |
| 43 | |
| 44 | See the Workflow JS sandbox tests for the fail-closed host surface inventory. |
| 45 | |
| 46 | ## Language Choice |
| 47 | |
| 48 | | Surface | Strength | Tradeoff | v0.8.60 stance | |
| 49 | |---|---|---|---| |
| 50 | | YAML / JSON IR | Simple, reviewable, no runtime | Verbose for generated workflows | Keep as interchange/debug format | |
| 51 | | JavaScript | Familiar object syntax and easy agent generation | Unsafe if executed as a general runtime | First-class authoring through declarative compile-only subset | |
| 52 | | TypeScript | Best editor/types story for workflow SDK | Needs stripping/typechecking if full TS is supported | Same compile-only subset for now; richer SDK later | |
| 53 | |
| 54 | The default high-capability path is TypeScript/JavaScript authoring, but only as |
| 55 | a compile step. The compiler accepts a JSON-compatible object inside |
| 56 | `workflow({...})` from `.workflow.js` or `.workflow.ts`, lowers it to |
| 57 | `WorkflowSpec`, and runs the Rust validation gate. (Starlark authoring was a |
| 58 | bootstrap reference and has been removed; Workflow authoring is JS-only.) |
| 59 | |
| 60 | ## Contract |
| 61 | |
| 62 | Accepted source shape: |
| 63 | |
| 64 | ```js |
| 65 | export default workflow({ |
| 66 | "id": "issue-audit-js", |
| 67 | "goal": "Audit an issue fix with parallel agents", |
| 68 | "nodes": [ |
| 69 | { |
| 70 | "branch": { |
| 71 | "id": "parallel-audit", |
| 72 | "children": [ |
| 73 | { "agent": { "id": "code-audit", "prompt": "Review code", "agent_type": "review" } }, |
| 74 | { "agent": { "id": "test-audit", "prompt": "Review tests", "agent_type": "verifier" } } |
| 75 | ] |
| 76 | } |
| 77 | }, |
| 78 | { "reduce": { "id": "summary", "inputs": ["code-audit", "test-audit"], "prompt": "Summarize" } } |
| 79 | ] |
| 80 | }); |
| 81 | ``` |
| 82 | |
| 83 | Supported node wrappers: `agent`, `branch`, `sequence`, `reduce`, |
| 84 | `teacher_review`, `loop_until`, `cond`, and `expand`. Raw `WorkflowNode` JSON IR |
| 85 | with `kind` / `spec` also remains valid. |
| 86 | |
| 87 | An `agent` node may declare `"profile": "reviewer"` to run as a named Fleet |
| 88 | roster profile. The name is trimmed and lowercased at compile time and must be |
| 89 | a single token (no whitespace, quotes, or `=`); the saved roster is resolved at |
| 90 | dispatch time, and explicit fields on the agent override profile defaults. |
| 91 | |
| 92 | The runtime `task()` surface also accepts `cwd` for an existing repository- |
| 93 | relative working directory. This is required when a workflow is launched from |
| 94 | a multi-repository workspace and the child needs shell or file access. `cwd` |
| 95 | is validated by the host, does not grant mutation authority, and should be |
| 96 | paired with `worktree: true` when the child needs an isolated checkout. |
| 97 | |
| 98 | The compiler rejects effectful constructs such as `import`, `require`, `fetch`, |
| 99 | `process`, `Deno`, `Bun`, `child_process`, file reads/writes, `eval`, `async`, |
| 100 | and `await`. This is intentionally stricter than JavaScript: workflow source is |
| 101 | a familiar declaration format, not a second execution runtime. |
| 102 | |
| 103 | ## Verification |
| 104 | |
| 105 | - `cargo test -p codewhale-workflow --locked javascript` |
| 106 | |
| 107 | Current example: `workflows/issue_audit.workflow.js`. |
| 108 | |
| 109 | ## Agent-Written Fleet Workflows |
| 110 | |
| 111 | The primary product flow is not "ask the user to write a script." The main |
| 112 | agent should decide when a task deserves workflow orchestration, draft the |
| 113 | Workflow source, show the plan for the current permission mode, and then let |
| 114 | the runtime compile and monitor it. |
| 115 | |
| 116 | Workflow owns the plan: phases, branches, loops, reducers, and intermediate |
| 117 | results. Fleet owns the durable sub-agent configuration: slots, profiles, |
| 118 | models, tool posture, launch concurrency, leases, heartbeats, logs, receipts, |
| 119 | and resume/stop/restart controls. In other words, a workflow can choose and |
| 120 | monitor Fleet slots, but it must not become a second executor with its own shell |
| 121 | or filesystem authority. |
| 122 | |
| 123 | Fleet launch validation applies a conservative default shape before any |
| 124 | Workflow IR is lowered to workers: |
| 125 | |
| 126 | - up to 1,000 total worker agents per Workflow run; |
| 127 | - up to 16 live worker agents at once; larger populations queue (block) on the |
| 128 | host's per-run concurrency gate until a live slot frees, then route through |
| 129 | Fleet; |
| 130 | - up to 5 recursive Fleet rings (the default user configuration is 2); |
| 131 | - loops require `max_iterations`; |
| 132 | - dynamic `expand` nodes require `max_children` and a template. |
| 133 | |
| 134 | Those limits distinguish population from instantaneous launch concurrency. A |
| 135 | valid 1,000-agent Workflow can still drain through a smaller Fleet |
| 136 | worker pool. Model selection stays per slot: a DeepSeek preset can suggest |
| 137 | `deepseek-v4-pro` for the orchestrator and `deepseek-v4-flash` for nearby |
| 138 | workers, but users and agents may override any slot when the task calls for it. |
| 139 | |
| 140 | ## Experimental search is a Workflow option |
| 141 | |
| 142 | Experimental search generalizes the existing best-of-N recipe without adding a |
| 143 | new product mode, scheduler, or sub-agent API. A provider-neutral |
| 144 | `WorkflowSearchSpec` freezes the objective, baseline, model request and resolved |
| 145 | version, public evidence, evaluator hash, hard gates, scoring rule, budgets, |
| 146 | write scope, rounds, and review-only integration policy before admission. |
| 147 | |
| 148 | The current JS starter supports structured generation and read-only review with |
| 149 | `strategy: "search"`. Runtime-owned command gates, hidden evaluation, benchmark |
| 150 | scoring, and clean-baseline replay are an explicit host seam still to wire; a |
| 151 | candidate's self-verdict must never be promoted into evaluator truth. See |
| 152 | [Workflow Experimental Search](WORKFLOW_EXPERIMENTAL_SEARCH.md). |
| 153 |