Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Claude Code Auto-Continue (Windows)

Your turn died on an API error while you were away. This types continue for you.

Platform PowerShell Claude Code License

No tmux. No screen scraping. No stolen focus. No extra process running in the background.


The problem

Claude Code retries transient API failures on its own. When those retries run out, the turn is aborted and the session goes quiet at the prompt, waiting for a human to nudge it:

API Error: 529 overloaded_error - Retrying in 8s... (attempt 10/10)
x API Error
>

If you stepped away, or that session is one of a dozen terminal windows you are not looking at, a five-second network blip costs you an hour of wall-clock time. Every fix is the same fix: type continue.

What this does

turn dies (overloaded / server error / connection dropped)
        |
        +- StopFailure hook fires
        |
        +- wait 10s  ->  type "continue" + Enter into that session  ->  ding
        |
        +- died again? wait 30s -> one more try
                                        |
                                        +- still failing -> alert sound, stop, wait for a human

A turn that completes normally clears the streak, so "two in a row" really means in a row.

How it works

Two pieces, and the second one is the interesting one.

1. StopFailure - a hook that fires on exactly this event.

Since Claude Code 2.1.241 there is a StopFailure hook event, fired when a turn ends because of an API error. Its payload tells you what went wrong:

{
  "hook_event_name": "StopFailure",
  "session_id": "...",
  "error": "overloaded",
  "error_details": "...",
  "last_assistant_message": "..."
}

The matcher field filters on error, so you can react to a 529 without reacting to an expired login. What the hook cannot do is resume the turn - unlike Stop, its output and exit code are ignored (OnApiRetry, which would have allowed that, was closed as not planned).

2. WriteConsoleInput - putting the keystrokes back where they belong.

So the continue has to come from outside, as if you had typed it. The usual tricks are all bad: SendKeys needs the window focused, screen scraping needs tmux, and both need to figure out which of your terminal windows owns the session that failed.

None of that is necessary, because every child process a Claude Code hook spawns is attached to the same Windows console as the claude process that spawned it. Check for yourself - call GetConsoleProcessList from inside a hook and claude is right there in the list:

attached=3
7020    pwsh
2340    claude
6568    powershell

Which means a hook can open CONIN$ and call WriteConsoleInput to push synthetic key events straight into the input buffer its own session is reading from. The text appears in the prompt exactly as if it were typed:

  • no window hunting - the console is the session that failed;
  • no focus stealing - you can keep working in another window while it happens;
  • correct by construction with any number of parallel sessions;
  • works in Windows Terminal, conhost, the VS Code terminal, anything ConPTY-backed.

Requirements

OS Windows (uses the Win32 console API)
Claude Code 2.1.241 or newer - earlier versions have no StopFailure event
PowerShell 5.1 (built in) or PowerShell 7+

Install

git clone https://github.com/danvak/claude-code-auto-continue.git
cd claude-code-auto-continue
.\install.ps1

The installer backs up settings.json, keeps every other setting and hook you already have, and adds two entries:

"StopFailure": [{
  "matcher": "overloaded|server_error|unknown|max_output_tokens",
  "hooks": [{ "type": "command", "command": "& '...\\auto-continue.ps1'",
              "shell": "powershell", "async": true }]
}],
"Stop": [{
  "hooks": [{ "type": "command", "command": "& '...\\auto-continue.ps1' -Reset",
              "shell": "powershell", "async": true }]
}]

Restart your session afterwards - settings.json is read at startup, so a session that was already open will not have the hooks.

Scope it to a single repository instead of your whole account with .\install.ps1 -SettingsPath .\.claude\settings.json.

Verify

.\install.ps1 -Test

Feeds the hook a synthetic StopFailure payload in dry-run mode. Nothing is typed into your session; it just proves the wiring:

OK  hook parsed the payload correctly:
    2026-08-24 16:52:20  dry run  error=overloaded session=INSTALL-TEST attempt=1/2

You can also confirm the hooks are loaded with /hooks inside Claude Code.

To watch the real thing, tail the log: Get-Content .\auto-continue.log -Wait

Configuration

Copy config.example.json to config.json (git-ignored, so updates will not clobber it):

Key Default What it does
maxRetries 2 Auto-continues allowed per failure streak
delaysSec [10, 30] Seconds to wait before each attempt; the last value repeats
message "continue" What gets typed into the session
forgetAfterMinutes 30 Quiet period after which an old streak is forgotten
soundOnRetry Windows Balloon Played when a continue is sent; "" to disable
soundOnGiveUp Critical Stop Played when the budget is spent; "" to disable

Which errors trigger it

Claude Code classifies API failures into these error values. The default matcher covers the transient ones - the failures where retrying is the fix:

error Retried Why
overloaded yes 529, the model is busy - the canonical blip
server_error yes 5xx upstream
unknown yes where dropped connections and timeouts land
max_output_tokens yes the turn was cut off mid-thought; continue is literally the fix
rate_limit no retrying in 10s cannot conjure quota - wait for the reset
authentication_failed no needs a human to log in
account_on_hold, billing_error no needs a human with a credit card
invalid_request, model_not_found no deterministic; retrying reproduces it

Override with .\install.ps1 -Matcher 'overloaded|server_error'.

Files

Path
auto-continue.ps1 The hook: counts failures, waits, sends the keystrokes
inject-keys.ps1 Standalone WriteConsoleInput helper - usable on its own
install.ps1 Wires/unwires the hooks, plus -Test and -Uninstall
auto-continue.log What was sent and when
.state/<session-id>.txt Consecutive-failure counter, per session

inject-keys.ps1 is useful by itself if you want to script a session:

.\inject-keys.ps1 -Text 'run the tests' -Enter
.\inject-keys.ps1 -Text 'hello' -TargetPid 1234   # from outside that console

Uninstall

.\install.ps1 -Uninstall

Removes only the hooks this installer added, backs up settings.json first, and leaves the rest of your configuration alone.

Caveats

  • If you are typing in that window when the injection fires, your text and continue merge and get submitted together. Unavoidable - that is what writing into the same input buffer means. Shorten delaysSec if it bothers you.
  • Windows only. The StopFailure half is cross-platform; the CONIN$ half is not. A Linux or macOS port would write to the session TTY with TIOCSTI, or fall back to tmux send-keys.
  • Fires for the main agent only - subagent contexts are skipped by Claude Code itself.
  • Tested against a synthetic StopFailure payload and against live keystroke injection into a running session. Real outages are, thankfully, hard to schedule.

Related

Both watch Claude Code from the outside, on Unix. This one is driven by Claude Code's own hook system on Windows, so there is no wrapper process and nothing to keep running.

License

MIT - see LICENSE.

About

Auto-types 'continue' back into a Claude Code session when a turn dies on an API error. Windows, no tmux, no focus stealing - driven by the StopFailure hook + WriteConsoleInput.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages