[FEATURE] Let in-flight subagents resume from their own checkpoint after a usage-limit interruption, instead of restarting from scratch
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
Summary
When a session hits the usage limit while a Workflow (or several background Agents) is running, every in-flight subagent fails immediately. After the limit resets, Workflow({scriptPath, resumeFromRunId}) restores only the agents that had completed (their agent() calls hit the cache). Every agent that was mid-task is re-run from zero — its transcript, tool results and partially built outputs are discarded — even when it was a few tool calls away from finishing.
Because the caching unit is the whole agent() call, a limit that lands late in a long stage throws away most of the stage. In my case 12 of 14 agents were killed after ~22 minutes of work (~2.0M subagent tokens); on resume all 12 started over.
Environment
Claude Code 2.1.257 (Windows 11, 10.0.26200; Git Bash + PowerShell)
Model: claude-fable-5-1 (main loop and subagents)
Workflow tool with parallel() fan-out of 10 agents, then sequential stages
Steps to reproduce
Launch a Workflow whose first phase fans out ~10 long-running agents (each 20–60 min of tool use: reading files, running local scripts, fetching URLs).
Let the session reach the usage limit while they are running.
Observe every running agent fail with: [probe:...] failed: You've hit your session limit · resets 5:10pm (Asia/Shanghai) (agents_done: 2, agents_error: 12 in the completion notification).
After the reset, call Workflow({scriptPath, resumeFromRunId}).
Observe: the 2 completed agents return cached results instantly; the 12 failed agents restart with a fresh context and redo all of their work.
Expected behavior
A failed/interrupted agent() call should be resumable from its last state, not only replayable from its cached final result. Its transcript (agent-<id>.jsonl) already exists on disk; on resume the harness could re-enter that transcript (continue the conversation) instead of starting a new one.
At minimum: when the failure reason is a rate/usage limit (not an error inside the agent), the harness should pause the agent and resume it after the reset, rather than turning it into a hard failure that the script must handle.
Ideally the same applies to background Agent tasks (they are simply marked failed/stopped today).
Why it matters
Long multi-agent runs are exactly the ones that hit limits. Losing partial progress makes the cost of a limit proportional to elapsed work, not to remaining work.
The work is not actually lost on disk: in my run the interrupted agents' scripts, intermediate JSON and mid-term reports all survived in their output directories. Only the agent's own context was lost. A resume-from-transcript would recover that context for free.
Proposed Solution
Workarounds I use now (so the request is not "please do my checkpointing for me")
Every subagent prompt carries a "resume clause": check your output directory for partial artifacts from a previous attempt and continue from them; save reusable intermediate results early; write the final report last.
Keep agents small (one deliverable, ~30 min) so agent()-level caching has finer granularity.
On resume, keep prompts of completed agents byte-identical (to hit the cache) and edit only the prompts of the agents that must re-run.
These help, but they rely on the model re-discovering its own half-finished work through the file system, which is slower and less reliable than the harness re-entering the saved transcript.
Alternative Solutions
_No response_
Priority
High - Significant impact on productivity
Feature Category
API and model interactions
Use Case Example
Workarounds I use now (so the request is not "please do my checkpointing for me")
Every subagent prompt carries a "resume clause": check your output directory for partial artifacts from a previous attempt and continue from them; save reusable intermediate results early; write the final report last.
Keep agents small (one deliverable, ~30 min) so agent()-level caching has finer granularity.
On resume, keep prompts of completed agents byte-identical (to hit the cache) and edit only the prompts of the agents that must re-run.
These help, but they rely on the model re-discovering its own half-finished work through the file system, which is slower and less reliable than the harness re-entering the saved transcript.
Additional observations from the same incident (minor, separate issues if you prefer)
agent() resolves to null on a terminal failure. If a script does parallel(items.map(x => () => agent(...).then(r => ({key: x, ...r})))), the spread of null yields a non-null object, so .filter(Boolean) does not remove it and a later v.verdicts.map throws TypeError: undefined is not an object. A note in the authoring reference ("guard r before spreading") or having the harness resolve failed calls to a sentinel object with error would prevent this.
The persisted script path returned by the tool encodes the shell's working directory at launch time. After the working directory changed, Workflow({scriptPath: <that path>}) was rejected with "scriptPath must be a script path this tool returned, or a file you can already read", even though the tool itself had returned that exact path. Copying the file under the current working directory was the only way to resume.
Editing the persisted script on Windows (Python text mode) introduced \r; the resume was then refused with "script contains control characters that would be hidden in the approval dialog". Tolerating CRLF (or normalizing it) would avoid a confusing failure on Windows.
Additional Context
Additional observations from the same incident (minor, separate issues if you prefer)
agent() resolves to null on a terminal failure. If a script does parallel(items.map(x => () => agent(...).then(r => ({key: x, ...r})))), the spread of null yields a non-null object, so .filter(Boolean) does not remove it and a later v.verdicts.map throws TypeError: undefined is not an object. A note in the authoring reference ("guard r before spreading") or having the harness resolve failed calls to a sentinel object with error would prevent this.
The persisted script path returned by the tool encodes the shell's working directory at launch time. After the working directory changed, Workflow({scriptPath: <that path>}) was rejected with "scriptPath must be a script path this tool returned, or a file you can already read", even though the tool itself had returned that exact path. Copying the file under the current working directory was the only way to resume.
Editing the persisted script on Windows (Python text mode) introduced \r; the resume was then refused with "script contains control characters that would be hidden in the approval dialog". Tolerating CRLF (or normalizing it) would avoid a confusing failure on Windows.
Ask
Agent-level checkpoint/resume for Workflow and background Agent tasks, at least for usage-limit interruptions: re-enter the existing agent transcript on resume instead of discarding it.