codewhale-workflow-js 0.9.8

Dynamic Workflow runtime: sandboxed rquickjs scripts that dispatch Codewhale subagents
Documentation

Dynamic Workflow runtime for CodeWhale.

This crate is the imperative half of Workflow: a sandboxed QuickJS (rquickjs) runtime that executes a model-authored JS program which dispatches fleet-routed subagents via task(), fans out with parallel()/pipeline(), reports progress with log()/phase(), and scales itself to a token pool via the budget global. The static, declarative IR (record/replay, model policy) stays in codewhale-workflow; this crate only speaks to the outside world through the [WorkflowDriver] seam, so it is fully testable without spawning a real subagent (see [testing::FakeDriver]).

Script surface

Every script runs inside an async function with these globals:

  • args — the invocation input, verbatim.
  • await task(opts) — dispatch one subagent; resolves to the full result text, or to a parsed + schema-validated object when opts.responseSchema is set. Throws on rejection, failure, cancellation, budget exhaustion, or once [WORKFLOW_LIFETIME_CAP] spawn attempts have been made.
  • parallel(thunks) — all-settled fan-out; an ordinary failed slot becomes null; schema-contract failures and run cancellation still fail the run; at most [PARALLEL_MAX_ITEMS] items.
  • pipeline(items, ...stages) — per-item stage chains with no barrier between stages; an ordinary stage error drops that item to null, while schema-contract failures and cancellation still fail the run; same cap.
  • log(msg) / phase(title) — progress events forwarded to the driver.
  • budget.total / budget.spent() / budget.remaining() — live driver snapshots (total is null and remaining() is Infinity when no ceiling is configured).

Date.now(), new Date(), Date.parse/UTC, and Math.random() throw: runs must be deterministic so recorded traces can be replayed.

Ownership boundaries

Token accounting and admission belong to the driver; the VM only reads snapshots and fast-fails a spawn when the shared pool is already exhausted. Already-running parallel children can reconcile above the hint because provider usage arrives at response boundaries, not token-by-token. Fleet roster resolution for profile also happens driver-side; this crate normalizes and token-validates the profile string, nothing more.