You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I ran a structured audit of pi-dynamic-workflows against the behavior of Anthropic's integrated "dynamic workflows" Workflow tool in Claude Code (each gap was independently verified against source). This is a tracking issue for the faithfulness gaps — places where the API surface or README implies a behavior that the runtime doesn't actually deliver.
Several gaps are already well-tracked (linked below); this issue focuses on 6 that don't appear to have issues yet, while listing the full set for completeness.
Background
The repo is a faithful but minimal port. Three categories already have great coverage: resume/persistence (#1#3#7#8), per-agent model selection (#9), and the registry//workflows/background layer (#2#4#5#6). The items below are the remaining divergences from the reference tool, ordered by priority.
isolation: 'worktree' is a no-op (P1)
In the reference, this creates a fresh git worktree per agent so parallel file-mutating agents don't collide (auto-removed if unchanged). Here it only appends the prose line "Requested isolation: worktree" to the prompt; every subagent shares one cwd. The API and the README ("isolated subagents") promise isolation that isn't there. Acceptance: a workflow with two parallel agents that each write the same file produces no cross-contamination; an isolated agent that makes no changes leaves no leftover worktree; running in a non-git dir degrades gracefully with a log line instead of throwing. (Distinct from Support forked agents (fan-out from a shared parent context) #10, which is shared-parent-context fan-out.)
Token budget massively undercounts + no agent ceiling (P1) spent() is derived from JSON.stringify(result).length/4 — it counts only each subagent's returned value, ignoring all the reasoning/tool-call tokens the subagent actually burned (off by 1–2 orders of magnitude). tokenBudget is also never wired through from the tool, so budget.total is always null and the ceiling never engages. There is no lifetime agent cap, so a buggy/looping script can spawn agents unbounded. Acceptance:budget.spent() reflects real subagent token usage (not just the final value); a configured budget actually halts further agent() calls; an unbounded agent() loop is stopped by a hard agent-count ceiling.
No structured-output retry (P1)
When a subagent finishes without calling structured_output, the runtime throws once and the result becomes null. The reference re-prompts/retries on a missing or schema-invalid final output. Acceptance: a subagent that initially skips structured_output is re-prompted and can still succeed; only after N exhausted attempts does the agent resolve to null; the corrective re-prompt echoes the actual schema-validation error.
Determinism guard is bypassable (P1)
The guard is a source-text regex matching the literal tokens Date.now / Math.random / new Date(). Because Math is a live binding in the vm context, computed access like Math['random']() or Math['ra'+'ndom']() runs real nondeterminism while passing the regex. (Note: Date and Reflect are not exposed in the context, so those particular escapes throw — the genuinely-live hole is Math[...].) Acceptance:Math['random']() inside a workflow script is rejected (or cannot produce nondeterminism); the determinism contract holds against computed/indirect member access, not just literal spellings.
New — features (lower priority)
Nested workflow(nameOrRef, args) (P2)
The reference exposes a workflow() global that runs another workflow inline as a sub-step, sharing the parent run's concurrency limiter, agent counter, abort signal, and token budget — with exactly one level of nesting (calling it inside a child throws). Not present here. Acceptance: a workflow can invoke another by name/ref and get its result; the child draws from the same concurrency/budget/abort as the parent; a workflow() call inside a child throws.
Subagents can't reach MCP tools (P2)
Subagents are built with createCodingTools(cwd) only; session-connected MCP tools aren't forwarded. In the reference, workflow subagents can reach session MCP tools. Acceptance: a subagent can call an MCP tool that the parent session has connected.
Out of Scope
Implementation details / exact patches (happy to follow up with PRs).
The already-tracked items above (listed only for a complete picture).
Notes
Audit method: one analysis pass + one adversarial verification pass per finding, each reading the actual source. All 6 new findings verified high-confidence against current main.
Happy to split any of these into standalone issues or open PRs if that's more useful — just say the word.
Summary
I ran a structured audit of
pi-dynamic-workflowsagainst the behavior of Anthropic's integrated "dynamic workflows" Workflow tool in Claude Code (each gap was independently verified against source). This is a tracking issue for the faithfulness gaps — places where the API surface or README implies a behavior that the runtime doesn't actually deliver.Several gaps are already well-tracked (linked below); this issue focuses on 6 that don't appear to have issues yet, while listing the full set for completeness.
Background
The repo is a faithful but minimal port. Three categories already have great coverage: resume/persistence (#1 #3 #7 #8), per-agent model selection (#9), and the registry/
/workflows/background layer (#2 #4 #5 #6). The items below are the remaining divergences from the reference tool, ordered by priority.Findings
Already tracked (for completeness)
opts.modelis inert (prose-only; never threaded intocreateAgentSession;phase.modelparsed but unused) — see Support per-agent model selection in workflow scripts #9./workflowsmanager — see WorkflowTask registry + abort controllers #2, Saved workflow loader + /workflow:<name> commands #4, /workflows command (list, show, kill, pause) #5, Workflow usage consent prompt #6.New — correctness / safety
isolation: 'worktree'is a no-op (P1)In the reference, this creates a fresh git worktree per agent so parallel file-mutating agents don't collide (auto-removed if unchanged). Here it only appends the prose line
"Requested isolation: worktree"to the prompt; every subagent shares one cwd. The API and the README ("isolated subagents") promise isolation that isn't there.Acceptance: a workflow with two
parallelagents that each write the same file produces no cross-contamination; an isolated agent that makes no changes leaves no leftover worktree; running in a non-git dir degrades gracefully with a log line instead of throwing.(Distinct from Support forked agents (fan-out from a shared parent context) #10, which is shared-parent-context fan-out.)
Token budget massively undercounts + no agent ceiling (P1)
spent()is derived fromJSON.stringify(result).length/4— it counts only each subagent's returned value, ignoring all the reasoning/tool-call tokens the subagent actually burned (off by 1–2 orders of magnitude).tokenBudgetis also never wired through from the tool, sobudget.totalis alwaysnulland the ceiling never engages. There is no lifetime agent cap, so a buggy/looping script can spawn agents unbounded.Acceptance:
budget.spent()reflects real subagent token usage (not just the final value); a configured budget actually halts furtheragent()calls; an unboundedagent()loop is stopped by a hard agent-count ceiling.No structured-output retry (P1)
When a subagent finishes without calling
structured_output, the runtime throws once and the result becomesnull. The reference re-prompts/retries on a missing or schema-invalid final output.Acceptance: a subagent that initially skips
structured_outputis re-prompted and can still succeed; only after N exhausted attempts does the agent resolve tonull; the corrective re-prompt echoes the actual schema-validation error.Determinism guard is bypassable (P1)
The guard is a source-text regex matching the literal tokens
Date.now/Math.random/new Date(). BecauseMathis a live binding in the vm context, computed access likeMath['random']()orMath['ra'+'ndom']()runs real nondeterminism while passing the regex. (Note:DateandReflectare not exposed in the context, so those particular escapes throw — the genuinely-live hole isMath[...].)Acceptance:
Math['random']()inside a workflow script is rejected (or cannot produce nondeterminism); the determinism contract holds against computed/indirect member access, not just literal spellings.New — features (lower priority)
Nested
workflow(nameOrRef, args)(P2)The reference exposes a
workflow()global that runs another workflow inline as a sub-step, sharing the parent run's concurrency limiter, agent counter, abort signal, and token budget — with exactly one level of nesting (calling it inside a child throws). Not present here.Acceptance: a workflow can invoke another by name/ref and get its result; the child draws from the same concurrency/budget/abort as the parent; a
workflow()call inside a child throws.Subagents can't reach MCP tools (P2)
Subagents are built with
createCodingTools(cwd)only; session-connected MCP tools aren't forwarded. In the reference, workflow subagents can reach session MCP tools.Acceptance: a subagent can call an MCP tool that the parent session has connected.
Out of Scope
Notes
main.