[Workflow tool] resumeFromRunId does not restore nested workflow() child runs — in-flight children restart from scratch
Summary
With the Workflow tool (multi-agent orchestration, CLAUDE_CODE_WORKFLOWS=1), resuming a
parent run via Workflow({ scriptPath, resumeFromRunId }) does not restore nestedworkflow(name, args) child runs. A child that was in flight at interruption restarts from
its first agent(), discarding every completed agent inside it. For dispatcher/fleet
patterns (a parent that calls a child workflow per work-item) this throws away the bulk of a
long run.
Pattern / environment
- Parent
fleetworkflow processes N items via a bounded pool; per item it calls
await workflow('child', { ... }) (one level of nesting).
- Each child runs ~25–30
agent()/parallel()calls (e.g. lock → context → … → verify).
Repro
- Run the parent; 3 children are ~28 agents deep each.
- Pause (or hit a session limit / the ~13-min background timeout, cf. #64627).
- Resume with
Workflow({ scriptPath, resumeFromRunId }).
Expected: completed work inside the children replays from the journal; in-flight children
continue near where they stopped.
Actual: the parent's own agent() calls replay from cache, but every workflow() child
re-invokes from scratch (the child's first phase runs again). ~84 agents of progress
(28 × 3) are discarded. Worse, re-running a child whose first attempt already committed work
can mis-fire downstream gates (e.g. a TDD RED test re-runs against an already-green branch and
fails for the wrong reason).
Mechanism (best understanding)
The resume journal caches the parent run's own agent() calls keyed by (prompt, opts). A
nested workflow() spins up a child run with its own journal that the parent'sresumeFromRunId does not extend into. Child agents share the parent's concurrency cap /
agent counter / token budget, but not the resume journal — so there is no observed way to
resume an in-flight (or even a completed) nested child.
Proposed fix
- Journal nested child runs under the parent runId — give each
workflow()call a stable
sub-run id (call-site index + args hash) and record its child agent() results in the
parent's journal namespace. On resume, completed child agents replay from cache; an
in-flight child resumes at its last completed agent().
- At minimum, cache the return value of a fully-completed
workflow()call so a child
that finished before the interruption is not re-run.
- Document the resume semantics for nested workflows either way.
Broader principle (the real ask)
Resume today behaves like "re-run the orchestrator with a result cache," not "continue where
it paused." For long autonomous runs that is fragile: an interrupted agent loses its in-flight
context and re-runs. The transcripts already persist
(~/.claude/projects/<project>/<session-id>.jsonl, agent-*.jsonl). It would be far more
robust if Workflow resume could continue in-flight agents session-style — the wayclaude --resume reattaches to a CLI conversation — rather than discard and re-run them.
Resume should feel like reattaching to a terminal, not restarting a script.
Related
#65796, #67488, #16607 (resume re-runs completed agents / pick up where interrupted),
#63102 (resume cache unreachable when args aren't byte-exact), #64627 (background runs killed
at ~13-min timeout — a common trigger).
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗