Skip to content

[Bug]: After a usage limit, the user moves the parent thread to another account, but the agent keeps resuming its delegated children on the limited account #31057

Open

Description

@genesiscz

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

All times UTC, 2026-11-04. Instance ids are replaced: work-a is the account that hits its limit,
work-b, work-c, work-d and work-e are other Claude accounts of the same user, each its own
claudeAgent provider instance. Thread ids are shortened to <parent>, <p56>, <p8>, <p9>,
<p10b>. Message text is shortened with …. Settings: "Auto-resume limited threads" is on.

Steps to reproduce

What the parent agent did, step by step, from its transcript.

  1. The parent runs on work-a and delegates on work-a. At 13:50:46 the parent agent called
    orchestrator_capabilities. The result lists 13 Claude instances with providerInstanceId,
    displayName, models and constraints, and nothing about usage or limits:

    {"parentThreadId":"<parent>","inheritedProviderInstanceId":"work-a","inheritedModel":"claude-opus-5-5", …,
     "providers":[…, {"providerInstanceId":"work-a","driverKind":"claudeAgent","displayName":"Claude Code (work-a)",
     "models":[…],"canRunChildTask":true,"canRunCrossProviderChildTask":true,"constraints":[]}, …]}

    From 13:51:35 to 13:51:52 it started four children on the same instance as itself:

    delegate_task {"title":"Mobile lane P8: talk to a session","role":"implementation",
      "target":{"providerInstanceId":"work-a","model":"claude-opus-5-5","options":{"effort":"high"}},
      "task":"Read <brief> first and follow it. …"}
    → {"taskId":"node:delegated-task:…:<p8>", "childThreadId":"<p8>", …}
  2. work-a hits its 5-hour limit while everything runs. The children worked for about 30 minutes.
    At 14:21:39 to 14:21:46 the parent and all four children failed. The parent's own failed turn showed
    the Claude CLI text with a reset time (4:20pm local is 15:20Z):

    You've hit your 5-hour limit · resets 4:20pm
    

    The parent then received one completion message per child, with no instance and no reset time:

    Delegated task node:delegated-task:…:<p8> (Mobile lane P8: talk to a session) [failed]:
    Claude API rate limit reached. Try again later.
    

    The child's own failed item had more (read from statev2.sqlite, turn-item.updated 14:21:41):

    {"type":"error","title":"Usage limit reached","failure":{"class":"usage_limit",
     "message":"Claude API rate limit reached. Try again later.","code":"api_error_429",
     "retryable":true,"resetAt":"2026-11-04T15:20:00.000Z"}}

    About 3 s later the server armed a resume for each child (limit-arm: command receipts at
    14:21:39 to 14:21:44).

  3. The user switches the parent thread to the provider instance work-b. The parent's next run (14:22:16)
    ran on work-b and completed. The four children stayed on work-a.

  4. The user asks: "pls resume the agents". At 14:22:32 to 14:22:43 the agent sent one message to each
    child. It did not change the instance, because nothing told it that the child would run on work-a
    again:

    t3_thread_send {"threadId":"<p8>","mode":"auto","message":"Resume your lane (p8) where the rate limit stopped you. …"}
    → {"threadId":"<p8>","runId":"…:ordinal:2","taskId":"…","status":"starting","delivery":"started"}

    Each new run started on work-a and failed in about 1 s (p8 run 2: 14:22:36.912 to 14:22:37.922):

    Delegated task node:delegated-task:…:thread-send:… (Mobile lane P8: talk to a session) [failed]:
    Claude API rate limit reached. Try again later.
    
  5. The agent restarts the work instead of resuming it. It ran tools ai usage limits (a local tool
    outside T3 Code) to find accounts with room, and at 14:23:29 to 14:23:45 started four NEW
    delegate_task children on work-d and work-e. These children had none of the old context. The
    user objected at 14:30:48: "i didnt want you to restart them but to RESUME THEM". The agent cancelled
    three of the copies with task_cancel.

  6. The user moves the parent again, to work-c (parent run at 14:32:29 on work-c), and says:
    "ok now i changed the account to ". The agent read the children's configuration, which still
    showed work-a:

    t3_thread_configure {"threadId":"<p8>"}
    → {"threadId":"<p8>","modelSelection":{"instanceId":"work-a","model":"claude-opus-5-5",
       "options":[{"id":"fastMode","value":false},{"id":"effort","value":"high"}]},"runtimeMode":"full-access", …}

    It still sent the resume messages unchanged (14:33:10 to 14:33:23). All four failed in about 1 s
    again (p8 run 3: 14:33:15.169 to 14:33:16.268). t3_thread_read on a child at 14:33:50 shows
    "status":"failed","providerInstanceId":"work-a" and three failed runs, but no failure class, no reset
    time and no armed resume.

  7. A fresh probe on work-a also fails at once (14:34:01, delegate_task with mode:"wait" and
    "Reply with the single word OK"). Nobody touched it, and at 15:20:01 the armed resume ran it and it
    answered "OK".

  8. The user asks: "isnt there like a delegate mcp tool that let you select the provider on resume?"
    Only then did the agent move each child and resend:

    t3_thread_configure {"threadId":"<p8>","modelSelection":{"instanceId":"work-c","model":"claude-opus-5-5","options":{"effort":"high"}}}
    → {"sequence":141507}
    t3_thread_send {"threadId":"<p8>","mode":"auto","message":"Resume your lane (p8) now; the account limit is fixed. …"}

    All four children then ran on work-c and work-d with their full history and completed.

Expected

  • When the parent hears that a child failed, it learns that the failure is a usage limit, on which
    instance, when it resets, and that T3 Code will resume the child by itself at that time.
  • The result, or the t3_thread_send and delegate_task descriptions, say that t3_thread_configure
    moves a failed child to another instance and keeps its history.
  • Optional: when the user moves the parent to another account, the agent can see that its children
    are still on the old one.

Actual

  • The parent only gets "Claude API rate limit reached. Try again later." The child's failed item has
    class, retryable and resetAt, and the server arms a resume, but the MCP results show none of it
    (limitRecovery and usageLimitResetAt do not appear under apps/server/src/mcp).
  • The agent retried the limited instance twice for each of the four children (8 runs that failed in
    about 1 s), then started four restarted copies without context, before the user pointed it at a tool
    that moves a thread.

How to test

apps/server/src/mcp/TaskCancelUsageLimit.integration.test.ts already drives a delegated child into a
usage_limit failure with a resetAt. A new row or case there can assert that the parent's delegated
result (and task_status) carries the instance id, the failure class and resetAt, and that the
child's t3_thread_send after a t3_thread_configure to another instance runs on the new instance while
the armed resume is dropped.

Impact

Major degradation or frequent failure. With several accounts, a usage limit stops every delegated child,
and the agent wastes runs on the limited account or restarts work without its context.

Version or commit

Desktop and server 0.1.5. Source read at main @ 9e85538.

Environment

macOS 27.2, T3 Code desktop 0.1.5, Claude Code 2.1.314 (claudeAgent driver), 13 Claude provider
instances (one per account), model claude-opus-5-5, "Auto-resume limited threads" on.

Workaround

t3_thread_configure the failed child to an instance with room, then t3_thread_send. The child keeps its
full history. The agent must find a free instance outside T3 Code.

Suggested fix

Three parts. The first one alone would have prevented the wasted runs.

1. Tell the parent what happened and what T3 Code already does. Carry the failure class, the instance
id, resetAt and the armed resume into the delegated completion message, task_status and
t3_thread_read. For example:

Usage limit on Claude Code (work-a), 5-hour window. T3 Code resumes this task at 15:20Z.
To continue now on another instance: t3_thread_configure with a new modelSelection, then t3_thread_send.

The data exists: the failed item's failure (class, retryable, resetAt) and the thread's
limitRecovery, which UsageLimitRecoveryWorker
arms a few seconds after the failure. Nothing under apps/server/src/mcp reads either of them today.

2. Say it in the tool descriptions. The delegate_task, task_status
and t3_thread_send descriptions do not say that t3_thread_configure moves a failed child to another
instance and keeps its history. One sentence there would have saved this run. Per AGENTS.md, a change to
this text comes with an eval case in evals/.

3. Show usage state in orchestrator_capabilities, and use it in delegate_task.

Related issues

Pull request

I can open a PR for part 1 (and part 2 with its eval case) once you agree on the direction. Part 3
touches the MCP contract, so I would wait for your call on its shape.


Investigated and written by Claude Opus 5.5 in Claude Code, driven from T3 Code. Instance names and
thread ids are anonymized.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions