Leaving Claude Code Running Overnight? 8 Settings to Check Before You Walk Away
Book: AI Agents Pocket Guide The series: Pocket Guides for Developers — 8 short books on agents, RAG, prompts, observability, events, databases and system design — the whole series My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools Me: xgabri

At 7 a.m. the terminal looks the way you left it at 11, apart from one line at the bottom: a permission prompt for a shell command, asked twenty minutes after you went to bed. You had handed the agent a refactor, added "run the tests when you're done", and walked away. It waited eight hours for an answer nobody was there to give.
That is one way an unattended run dies. The laptop going to sleep is another. So is a usage limit that resets on Thursday, or a run that reports "done" with the suite still red. Each of these has a setting you can change today. The eight below are checked against the Claude Code CLI reference and its changelog at 2.1.303, the newest release as I write this. Run claude -v first, because several need a recent version.
[ ] 1. caffeinate -i around the run [ ] 2. idle compaction: on or off, on purpose [ ] 3. retry watchdog, with a cap on usage-limit waits [ ] 4. --max-turns and --max-budget-usd [ ] 5. a permission mode nobody has to answer [ ] 6. one worktree per task [ ] 7. a Stop hook that sends it back while tests fail [ ] 8. a way to hear how it ended Enter fullscreen mode Exit fullscreen mode Keep the run alive while you sleep 1. Stop the Mac from idle-sleeping macOS ships caffeinate. With -i it creates an assertion that keeps the system from idle sleeping. Hand it a command and it holds that assertion only while the command runs:
caffeinate -i claude -p "Fix the flaky login test" Enter fullscreen mode Exit fullscreen mode For an interactive session, run caffeinate -i on its own in a second tab. It holds until you stop it or close that terminal. The -s flag blocks system sleep entirely, but the man page says that assertion is valid only on AC power, so plug the laptop in either way. Keep the lid open too: -i holds off idle sleep, not the sleep a MacBook goes into when you close the lid.
Since 2.1.299, Claude Code compacts a conversation of 200K tokens or more that has sat idle for about 54 minutes, before its one-hour prompt cache expires, so your next message doesn't reprocess the whole thing ( changelog ). That's a good trade for a session you come back to after lunch. For a run that finishes at 2 a.m. and then waits at the prompt, it means your first message at 7 continues from a summary, not the full conversation.
Choose on purpose. To keep the full conversation, turn it off in ~/.claude/settings.json:
{ "idleCompaction": false } Enter fullscreen mode Exit fullscreen mode Since 2.1.302 there is also an Idle compaction row in /config that does the same. If you want it on but later, CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS moves the threshold. The default is 200000, and anything under 100000 is raised to 100000 ( env-var reference ).
By default Claude Code retries a failed API request 10 times ( env-var reference ). For unattended sessions the same page points to CLAUDE_CODE_RETRY_WATCHDOG=1. It retries 429 and 529 capacity errors indefinitely, backing off up to 5 minutes between attempts, or until the limit resets when the response carries a reset time, "so a session that hits a usage limit waits out the remaining window." It still fails at once on a spend limit or exhausted usage credits.
Waiting out the window is right when the limit resets at 3 a.m. It is wrong when it resets in four days. Two newer variables limit the wait. CLAUDE_CODE_RETRY_WATCHDOG_MAX_WAIT_MS, added in 2.1.295, caps how long the watchdog waits out 429 and 529 errors, in plain-digit milliseconds. CLAUDE_CODE_RETRY_WATCHDOG_MAX_USAGE_LIMIT_WAIT_MS, added in 2.1.301, makes it end a request at a usage limit that resets too far away instead of waiting ( changelog ). The env-var reference has no row for that one yet and the changelog gives no unit, so the example below is my reading: milliseconds, going by the _MS suffix, and the value is how far off a reset may be before the watchdog gives up.
export CLAUDE_CODE_RETRY_WATCHDOG = 1 # stop waiting out capacity errors after 30 minutes export CLAUDE_CODE_RETRY_WATCHDOG_MAX_WAIT_MS = 1800000 # give up on usage limits that reset > ~2 hours out # (unit assumed to be ms, per the _MS suffix) export CLAUDE_CODE_RETRY_WATCHDOG_MAX_USAGE_LIMIT_WAIT_MS = 7200000 Enter fullscreen mode Exit fullscreen mode Without the watchdog, a long outage uses up the default retries and you wake up to a dead session. With the watchdog and no cap, a weekly limit can keep the run waiting long after you're back at your desk.
--max-turns limits agentic turns and exits with an error when the limit is reached. There is no limit by default. --max-budget-usd stops the run once estimated spend reaches the amount. It checks against a client-side estimate that can differ from your bill, and spend can pass the cap, so leave headroom ( CLI reference ). Both are print-mode only: they apply to claude -p, not to an interactive session.
If you run a mod that submits a prompt at the end of every turn, be on 2.1.299 or later. Before that release, such a mod could keep a headless run going past both caps ( changelog ), and you pay for every extra turn.
The scene at the top is a session in Manual mode: it reaches the first command that needs approval and waits. For an interactive session, start it with claude --permission-mode acceptEdits and add the commands it will need to permissions.allow in.claude/settings.json before you leave. For -p runs the headless docs say a run where nothing sets a permission mode takes the built-in starting mode, "which can be auto, so pass the one you want." The options they list:
Add --permission-prompts none (2.1.259 or later) and anything that would prompt is denied, Claude is told nobody can approve it and not to retry, and the run carries on. Put together with items 1 and 4:
TASK = "Fix the flaky login test. Run npm test until it passes." caffeinate -i claude -p " $TASK " \ --permission-mode acceptEdits \ --allowedTools "Bash(npm test *)" "Bash(git diff *)" \ --permission-prompts none \ --max-turns 40 \ --max-budget-usd 5.00 \ --output-format json > overnight.json Enter fullscreen mode Exit fullscreen mode --dangerously-skip-permissions skips the prompts altogether. I'd keep that for a container you can throw away, and read what it does and does not skip first.
claude -w fix-login starts Claude in its own git worktree at <repo>/.claude/worktrees/fix-login ( CLI reference ). Plain git does the same with git worktree add:
# from your main checkout, ~/code/app git worktree add -b agent/fix-login../fix-login cd../fix-login && npm ci && cp../app/.env. Enter fullscreen mode Exit fullscreen mode Without one, the agent edits the checkout you'll open in the morning, mixed in with your own uncommitted work, and a second agent in the same folder writes over the first. In a worktree, the night's work ends up on a single branch: git diff main...agent/fix-login shows what changed, and deleting the branch throws it away. A new worktree holds only tracked files, which is why the second line installs dependencies and copies the.env. Do that before you leave, or the first test run fails on something that isn't the agent's fault.
"Run the tests when you're done" is a request. A Stop hook is a rule. Claude Code runs Stop hooks whenever Claude finishes responding, and a command hook that exits with code 2 there "prevents Claude from stopping, continues the conversation" ( hooks reference ):
#!/bin/bash #.claude/hooks/gate.sh: no stopping while tests fail if! npm test > /dev/null 2>&1; then echo "npm test is failing. Fix it before you stop." > &2 exit 2 fi Enter fullscreen mode Exit fullscreen mode Register it in.claude/settings.json and make it executable with chmod +x:
{ "hooks": { "Stop": [ { "hooks": [ { "type": "command", "command": " \" $CLAUDE_PROJECT_DIR \" /.claude/hooks/gate.sh" } ] } ] } } Enter fullscreen mode Exit fullscreen mode The hooks guide version of this pattern reads stop_hook_active from the hook input and exits early when it is true, which sends Claude back only once. For an overnight run you want more than one try, so this script leaves that check out. It is still bounded: Claude Code overrides a Stop hook after it blocks eight times in a row with no tool call from Claude in between, so an agent that keeps fixing things keeps getting sent back, and one that is stuck gets let go.
CLAUDE_CODE_STOP_HOOK_BLOCK_CAP raises that cap ( env-var reference ). One more reason item 3 matters: Stop hooks don't fire on API errors, which fire StopFailure instead.
For interactive sessions, a Notification hook fires when Claude is waiting for input or permission. A small script keeps the JSON short; make it executable with chmod +x:
#!/bin/bash # ~/.claude/notify.sh MSG = " ${ 1:- Claude Code is waiting on you } " osascript -e "display notification \" $MSG \" with title \" Claude \" " Enter fullscreen mode Exit fullscreen mode { "hooks": { "Notification": [ { "matcher": "", "hooks": [ { "type": "command", "command": "$HOME/.claude/notify.sh" } ] } ] } } Enter fullscreen mode Exit fullscreen mode On Linux, swap the last line of the script for notify-send 'Claude Code' "$MSG". Two catches from the hooks guide: osascript fails silently if Script Editor doesn't have notification permission, so run osascript -e 'display notification "test"' once and then turn on Allow Notifications for Script Editor in System Settings > Notifications. And notify-send needs a notification daemon, which headless servers, SSH sessions and most containers don't have.
For the -p run from item 5, end the command with; ~/.claude/notify.sh "Run over" and read the JSON in the morning. The headless docs put the text in result and the estimated cost in total_cost_usd; jq pulls both out:
jq -r '.result' overnight.json jq '.total_cost_usd' overnight.json Enter fullscreen mode Exit fullscreen mode Where Hermes IDE fits I build Hermes IDE, so weigh this section with that in mind. It's a desktop app that runs Claude Code, Codex and other CLI agents, each in its own real terminal, and it isn't affiliated with Anthropic or any agent vendor. Because each agent runs its own interface, your settings.json (item 2) and the hooks from items 7 and 8 apply inside it unchanged. Variables you export in another terminal tab may not reach an agent the app starts, so put the item 3 variables in the env block of settings.json, where every session picks them up.
It takes work off two items. For item 6, ⌘N (Ctrl+Shift+N on Windows and Linux) starts each task on its own hermes/ branch in its own worktree, with the task as the agent's first prompt, and the approval mode is a chip on the same sheet. Its per-repo recipe file,.hermes/worktree.toml, can install dependencies and copy git-ignored files like.env into each new worktree, and takes a done_when list of checks. Hermes asks before it runs a recipe's setup commands, so start the task and approve them before you leave.
The ⌘N New task sheet: Claude Code, the orders-api project, a new hermes/ worktree, Accept edits, model and effort, and the claude command Hermes will run.
For item 8, Hermes sends a system notification when an agent is blocked on you or done, never for the session you're already looking at. Every session shows one status: working, needs approval, asked you, done, error or idle.
One failure none of the settings cover is closing the app itself. On macOS and Linux, agents keep working while Hermes quits, updates or crashes, and you reattach where they left off. If an agent hit its usage limit overnight, you can continue the task in another agent in the morning.
Codex and Claude Code side by side, each in its own hermes/ worktree, with status, context use, cost and branch per session in the sidebar.
None of this replaces item 1: an agent only works while the machine is awake. Hermes is free, source-available under BSL 1.1, and runs on macOS, Windows and Linux. Download it or read the code on GitHub.
Most of this list is guardrails for an agent nobody is watching: a turn cap, a budget, a permission boundary, a test gate at the point where it wants to stop. The AI Agents Pocket Guide is my short book on the patterns underneath those, for when you build agents of your own. It's one of the Pocket Guides for Developers, 8 short books on agents, RAG, prompts, observability, events, databases and system design: the whole series.