Guides/Playbook

Claude adds dynamic workflows: Verify every review result

8 min read
On this page
Expected review sheets aligned with returned results, with one missing result left visibly open

Verify every workflow result

General Analysis

On October 9, 2026, Anthropic added dynamic workflows to Claude Managed Agents, in beta. An agent can now write a program that delegates work across agents in the background. A security review can therefore return a combined answer while leaving some of the requested work unresolved.

Anthropic documents that a workflow can finish with completed even when a thread failed or could not be created. Treat that result as a reason to inspect the batch, not permission to mark its security review passed. Workflow result semantics.

Consider a hypothetical review of access-policy files before a release. The application knows which file revisions need review. Keep that inventory outside the agent's writable environment, then reconcile the returned evidence against it. This guide provides a local coverage check and a cleanup procedure. General Analysis has not tested a live Managed Agents integration for this article.

Set the delegation scope before starting#

Managed Agents uses the managed-agents-2026-04-01 beta header. The multiagent_20261001 configuration enables both subagents and dynamic workflows by default. Inline agents are also enabled by default; a predefined agent uses its own configuration. Anthropic documents how to restrict delegation to a reviewed list.

For this review, choose which agents may read the policy files and which tools they need. Disable unused delegation paths explicitly. Give the review environment no release credential: discovering a problem and approving a deployment are separate responsibilities. The coding-agent security baseline covers the surrounding access controls.

Attach a budget when creating the session. A session created without one cannot acquire a budget later. The cap stops new model requests, but in-flight requests can finish. This is a spending control; it does not validate the review. Session budgets.

Save the session ID, reviewed agent configuration, environment, expected input revisions, and acceptance criteria in your application's job record. Decide in advance what a failed review should block.

See how your AI systems hold up under real attacks

General Analysis maps AI applications and agents, red teams prompts, retrieval, tools, MCP servers, browser actions, permissions, and business workflows, then turns findings into evidence your team can reproduce and retest.

Reconcile the run history#

Track every workflow_run.created through its workflow_run.status_ended. Wait for a subsequent session idle with end_turn that your own interrupt did not cause. After interrupting, count only an idle following your next user.message or user.define_outcome. A paused run remains open, and the agent can start another run after reading a result. Completion conditions.

After a disconnect, open a new stream before listing the full event history. Reconcile the history and buffered live events by event ID, processing each once. Follow pagination through the complete history; opening the stream alone does not recover missed events. Keep the job unresolved if history retrieval fails. Reconnect procedure.

Inspect the child threads too. The primary stream is a condensed view; individual threads hold their own activity. Thread records identify their workflow_run_id, while the primary thread has no parent. Use those identifiers to connect evidence to the correct run. Session threads.

Then compare the results with the work you asked for.

Match results to the original inputs#

A count is a weak acceptance check. Three returned records could include the same file twice and omit another. A record could also describe yesterday's revision.

Create an expected-input manifest before starting. Give each input a stable ID and a digest of the exact bytes being reviewed. Require each result to name that ID and digest, describe its outcome, and point to retained evidence. These are application-defined fields, not Managed Agents API fields.

In the example below, reviewed means the reviewer produced evidence for that input. A reviewed file may still contain serious findings.

Returned evidenceRecommended acceptance decision
An expected input has no resultKeep the batch incomplete and identify the missing input.
Two results claim the same inputReconcile the attempts; do not silently keep the last one.
The digest differs from the expected revisionReject the stale result and review the intended bytes.
The result reports an error or lacks evidenceKeep that input unresolved.
Every input has a matching reviewed recordInspect the evidence and findings before accepting the review.

The following Python function checks that record structure. Its inputs are an application-owned dictionary of input IDs to digests and schema-validated result dictionaries. Run it outside the agent's writable sandbox. It makes no network requests and cannot establish that an agent actually read a file.

Code source: illustrative

Python
from collections import Counter def coverage_errors(expected, results): counts = Counter(row["input_id"] for row in results) errors = [] for input_id in sorted(expected): if counts[input_id] == 0: errors.append(f"missing: {input_id}") for input_id, count in sorted(counts.items()): if input_id not in expected: errors.append(f"unexpected: {input_id}") if count > 1: errors.append(f"duplicate: {input_id}") for row in results: input_id = row["input_id"] if input_id not in expected: continue if row["input_sha256"] != expected[input_id]: errors.append(f"revision mismatch: {input_id}") if row["status"] != "reviewed": errors.append(f"unresolved: {input_id}") if not row["evidence_refs"]: errors.append(f"missing evidence: {input_id}") return errors

This synthetic fixture expects two inputs but returns only one. Run it after the function above; it prints ['missing: policy-b'].

Code source: illustrative

Python
from hashlib import sha256 expected = { "policy-a": sha256(b"synthetic policy A").hexdigest(), "policy-b": sha256(b"synthetic policy B").hexdigest(), } results = [{ "input_id": "policy-a", "input_sha256": expected["policy-a"], "status": "reviewed", "evidence_refs": ["fixture-review-a"], }] print(coverage_errors(expected, results))

Validate the JSON schema before calling the function: IDs, digests, and status must be strings; evidence_refs must be a list of nonempty strings. Reject an empty expected manifest for a job that was supposed to review files. Store raw attempts separately so a deliberate retry does not erase its predecessor.

An empty error list means the records match the expected coverage. It says nothing about the truth of the findings. Resolve each evidence reference through your own artifact store, check its provenance and access scope, and review its contents. Do not let an arbitrary agent-supplied URL instruct the verifier to fetch private network resources.

For the access-policy example, the release reviewer should inspect the cited policy clauses and unresolved findings. A self-reported digest binds a claim to a revision; it is not proof of execution. Keep the actual input snapshots and independently retained tool evidence available for that review.

Close unfinished work without losing the record#

An interrupt does not end dynamic workflow runs, and targeting one of their threads stops nothing. Do not use a successful interrupt response as the incident's shutdown evidence. Interrupt behavior.

Use this procedure when abandoning a batch:

  1. Stop your application from authorizing new downstream effects. Preserve its pending-operation records and apply the sensitive-tool approval procedure.
  2. Resolve outstanding tool requests. Deny calls awaiting confirmation; return an error for a custom call you cancel. A pending requires_action can prevent the agent from accepting your stop message. Pending calls after interruption.
  3. Ask the agent to stop its runs, then verify that they ended. Archive the session once it is idle and the runs are closed. Archiving with an open run may fail, even if the session is idle. Session cleanup.
  4. Retain the event history and review artifacts. Deleting a session permanently removes its record, events, and associated sandbox. Download required outputs first. Deletion consequences.

There is a budget trap in step 3. At budget_reached, a new user.message is rejected until the budget changes. Raising or removing the cap resumes work paused by the budget; runs paused by an interrupt stay paused. Treat a budget change as an operational decision with possible resumed activity, and keep downstream authorization closed while reconciling it. Events accepted at the cap and resumption.

If a run remains unresolved, report it that way. Do not convert a pause, failed cleanup request, or missing event into a successful shutdown.

Exercise the acceptance decision before relying on it#

Use synthetic input records to check the verifier: remove a result, duplicate one, change a digest, return an error status, and remove evidence references. Each case should prevent acceptance. A complete matching fixture should reach evidence review, without automatically approving the release.

For a staging integration, separately check recovery after a stream disconnect and the stop procedure with a pending tool request. Record expected and observed behavior, including unresolved downstream effects. The local function cannot test those API interactions.

The release owner should receive the original manifest alongside the reconciled history, result evidence, and unresolved findings. Record who accepted the review and why; a green workflow status cannot supply that decision.

Browse all