# Claude Code Dynamic Workflows *May 2026* [Dynamic workflows](https://claude.com/blog/introducing-dynamic-workflows-in-claude-code) in Claude Code are one of the best production-shaped executions of [Recursive Language Models](https://arxiv.org/abs/2512.24601) that I have seen in the wild. These are some technical notes from probing, runtime observation, and workflow transcripts of the closed-source Claude Code (version `2.1.156`) on May 31, 2026. ![[dynamic-workflows.png]] ## A concrete example Dynamic `Workflow` tool calls look like this: ```js export const meta = { name: "tracker-decouple-phase1", description: "Refactor MCP tracker tools into a per-kind dispatcher", phases: [ { title: "Implement", detail: "one agent implements Tasks 1.1-1.3 with TDD" }, { title: "Verify", detail: "parallel adversarial review of the refactor" }, ], } const IMPL_SCHEMA = { type: "object", additionalProperties: false, properties: { commits: { type: "array", items: { type: "string" } }, checkPassed: { type: "boolean" }, contractSuitePassed: { type: "boolean" }, notes: { type: "string" }, }, required: ["commits", "checkPassed", "contractSuitePassed", "notes"], } const VERDICT = { type: "object", additionalProperties: false, properties: { dimension: { type: "string" }, passed: { type: "boolean" }, findings: { type: "array", items: { type: "string" } }, blocking: { type: "boolean" }, }, required: ["dimension", "passed", "findings", "blocking"], } const SHARED = "Repo: Symphony TS monorepo. Read the plan and design first." phase("Implement") const impl = await agent( SHARED + "\\nImplement only Phase 1: move Linear tools, add dispatcher, wire server names.", { schema: IMPL_SCHEMA, phase: "Implement", label: "implement:phase1" }, ) phase("Verify") const reviews = await parallel([ () => agent(SHARED + "\\nRead-only review: linear contract preserved.", { schema: VERDICT, phase: "Verify", label: "verify:contract" }), () => agent(SHARED + "\\nRead-only review: dispatcher correctness.", { schema: VERDICT, phase: "Verify", label: "verify:dispatch" }), ]) return { impl, reviews } ``` ## Agent orchestration From the client side, a dynamic workflow looks less like "a prompt that calls tools" and more like a model-authored coroutine program that runs inside a dedicated Node/Bun `vm` context. The script describes dependency shape first: independent branches, staged item flows, joins, retries, and synthesis, through `parallel` and `pipeline`. ![[dynamic-workflow-parallel-vs-pipeline.svg]] `parallel()` is a barrier shape: launch independent thunks, then wait until the set resolves. `pipeline()` is a conveyor shape: each item advances through ordered agent stages while other items enter earlier stages. Both feed the same bounded scheduler. These primitives are mainly dependency declarations, not a promise of raw parallelism. The call that exposes the runtime boundary is `agent(prompt, opts)`. It behaves like the suspension point in the VM: the JavaScript script runs until it awaits a host promise, then the host decides whether this call can be replayed, must be rejected, should be scheduled, needs schema validation, should be written to the journal, or can be resumed from a prior result. ![[dynamic-workflow-agent-call-flow.svg]] Static inspection points to a VM boundary with 2 responsibilities. First, it gives workflow code an explicit context: `agent`, `parallel`, `pipeline`, `log`, `phase`, `workflow`, `args`, `budget`, `console`, and timer shims. I did not see ordinary `require`, `process`, `fs`, credentials, or the host's full tool registry injected there. Second, it protects replay. Runtime probes and strings show `Math.random()`, `Date.now()`, bare `Date()`, and argless `new Date()` being trapped because nondeterministic call order would make cached `agent()` results unsafe to reuse. The same boundary appears to freeze major intrinsic constructors and prototypes, remove `ShadowRealm` and `WebAssembly`, and track workflow `setTimeout` handles so abort can clean them up. Resume appears to be prefix-deterministic rather than globally memoized. Each `agent(prompt, opts)` is keyed from the prior key plus the prompt and normalized options. If the journal has a completed result and no earlier miss occurred, the host can return the cached value. After the first miss, later calls appear to execute normally so edited control flow does not accidentally consume stale results from a different branch. Fresh work then appears to enter a semaphore-shaped scheduler, with concurrency computed as `min(16, max(2, cpuCount - 2))`. ## Runtime state Runtime state seems to exist for 3 practical reasons: visibility, resumability, and failure handling. Visibility starts with a task-registry-shaped object. In the observed client, it carries script text, args, workflow name, phases, run id, progress version, agent count, token totals, tool-call totals, logs, abort controller, and per-agent controllers. For local workflows, `/workflows` appears to read that state to render live progress, stop work, skip agents, retry attempts, and deliver final notifications. `phase()`, `opts.phase`, `opts.label`, `log()`, and `console.*()` look like small APIs, but they are really visibility writes. `phase()` sets the current grouping, `opts.label` names a row, and `log()` / `console.*()` append user-visible progress lines. Failure handling also seems admission-based where possible. Budgets gate new launches. In-flight agents are allowed to finish and preserve results. Per-slot failures in `parallel()` and `pipeline()` can be represented as `null`, which lets the parent script synthesize around missing branches instead of collapsing the whole run. Resumability is baked in because it's common to hit usage limits between workflow runs. ## Recursive language models Recursive Language Models and dynamic workflows can be read as decompositions of the same pressure: a single model call is too small a container for the computation we want. RLMs as [originally described](https://alexzhang13.github.io/blog/2025/rlm/) are context-centric. The environment is a REPL over external text: inspect, slice, search, summarize, recursively call models over selected spans. The correctness pressure sits on selection and compression. Did the root model choose the right evidence? Did the child calls preserve the relevant facts? Did the synthesis keep enough structure from the source context? Dynamic workflows take that recursive shape and spend most of their complexity budget on task-centric hardening: scheduling, isolation, structured returns, journaling, progress visibility, and recovery from partial failure. That is what makes adoption practical.