Repository navigation
An agent stopped by a usage limit is continued once the limit resets - #93
Merged
Merged
Conversation
When a limit runs out, Claude Code ends the turn and waits for a person, so an agent working on its own stopped and stayed stopped after the reset. Nothing inside Claude can undo that: the StopFailure hook fires with matcher rate_limit, but its output and exit code are ignored. The server now does it. session/resume.ts looks at every running Claude's transcript every 15s. When the newest record is a limit stop, it parks a todo, "continue", queued with notBefore set to the reset. The dispatcher types it the way it types any todo: into a Claude at rest with an empty input box, claimed on disk first. The server types nothing outside that path. - The stop is read from the transcript. Measured in a live one: an assistant record with "error":"rate_limit" and "isApiErrorMessage":true, text "You've hit your session limit · resets 4:10pm (UTC)", then turn_duration. This needs no hook and writes nothing into anyone's settings, the same rule attention follows. - The reset comes from that sentence, or from /usage when the sentence cannot be read. The wait adds 2 minutes for rounding and is never less than 5 minutes from the stop. Without that floor, an early continue that stops again would be retried every 15s. - Answered stops are kept in state.json (limitStops). Otherwise a deleted todo, or a restart, would park the stop again. - The continue goes ahead of todos queued before the stop and holds them back. If the human types first, it is dropped. - A top-bar switch, "continue automatically", turns it off. The setting is passed on to every linked machine, since the limit is the account's. The usage readout keeps two rows of limits, the two most used; on a tie the earlier one in /usage's order wins, so fable never wins a 0% tie. Also: `claude -p /usage` now runs with --no-session-persistence. Every reading had left a transcript behind: 1,077 of them (12MB) in ~/.claude/projects/-home-andrin--config-switchboard. With the flag, a reading writes none (checked by listing the directory after a reading). Measured on a scratch instance, with a stand-in agent that writes the measured stop and logs its input. Four stopped agents each got a parked continue. One key typed into one of them dropped its todo. The other three got the paste and a separate Return at 14:11:16, against a notBefore of 14:11:14.9. In the browser the switch is hit by elementFromPoint at every rung, and switching it off at a gateway set a linked peer to false. Each new guard was broken once and its test watched to fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When a usage limit runs out, Claude Code ends the turn and waits for a person, so an agent working on its own stayed stopped after the reset. Claude cannot undo this itself: the
StopFailurehook's output is ignored.server/src/session/resume.ts): reads the stop from the transcript ("error":"rate_limit", the record measured in a real stop) and parks a queuedcontinuetodo withnotBeforeset to the reset. The dispatcher types it the way it types any todo. The wait is the reset plus 2 min, and at least 5 min after the stop. Answered stops are kept instate.json. The todo goes ahead of todos queued before the stop. If the human types first, it is dropped.PUT /api/auto-continue). It is passed on to every linked machine. The readout shows the two most-used limits; a tie goes to session or week.claude -p /usagenow runs with--no-session-persistence. Every reading had left a transcript behind (1,077 of them, 12MB).Verified on a scratch instance with a stand-in agent that writes the measured stop: four agents parked, one taken over by a keystroke and dropped, three resumed at 14:11:16 against a
notBeforeof 14:11:14.9. The switch is hit byelementFromPointat every rung, and it reached a linked peer.Not verified: what a real Claude's screen shows at a limit stop. If it shows a dialog, the
continuewaits rather than being typed into it.🤖 Generated with Claude Code