Keep Your Mac Awake for the Whole Claude Code Session

Claude Code only holds your Mac awake while Claude is busy. Here is the one-line fix, a hook that holds the whole session, and what it still cannot solve.

You give Claude Code a real job. Refactor the module, run the suite, work through the backlog. You go and do something else for an hour.

You come back and nothing has happened since minute twelve. That is when Claude stopped to ask before running a command. You were not there to answer, and soon after, your Mac went to sleep with the question still on the screen. If you tried to answer from your phone, the Mac was not awake to hear it.

Recent versions of Claude Code do try to prevent this. While Claude is working in the terminal, Claude Code holds off idle sleep on its own, and the Claude desktop app has its own keep-awake settings. But the terminal app lets go about 30 seconds after Claude stops working, and Claude stops a lot: at the end of every reply, and every time it waits on you. Scripted claude -p runs got no such help at all in our tests.

This is a small problem with an annoying shape. The fix takes one line. Remembering to type that line every single time is the part that actually fails.

Here is the line, then a way to never think about it again.

The one-line fix

macOS ships with a command called caffeinate. It tells your Mac not to fall asleep on its own. You do not need to install anything.

Run your agent through it:

caffeinate -i claude

Your Mac stays awake as long as Claude Code is running, including every stretch where Claude is waiting on you. When you quit, everything goes back to normal. That is the whole trick. Arguments pass straight through, so caffeinate -i claude --resume works too.

The flags are worth knowing:

caffeinate -i   # do not fall asleep on its own     (what you want)
caffeinate -m   # keep the disk from idling         (does not stop sleep)
caffeinate -d   # keep the screen on too            (usually not what you want)
caffeinate -s   # stop sleep only while plugged in  (does nothing on battery)

Most people want -i. Skip -d unless you actually need the screen lit, because a lit screen overnight is just wasted power. -m and -s are rarely worth adding: one only keeps the disk from idling, and the other does nothing on battery.

If you only remember one thing from this post, remember caffeinate -i claude.

The problem with remembering

The command works. You will forget it.

You will forget it on the run that matters, the one you kicked off at 6pm before leaving. You will remember every other time, which somehow makes it worse.

So the better move is to make it automatic.

Making it automatic

Claude Code can run a command for you when a session starts, and another when it ends. You only need the first one.

Save this as ~/.claude/hooks/claude-awake.sh (create the hooks folder if it is not there yet):

#!/bin/bash
# claude-awake.sh: keep a Mac awake while a Claude Code session is open.
#
# Run it from a SessionStart hook. caffeinate -w waits on the Claude Code
# process itself, so the Mac is let go the moment that process exits: a
# normal quit, a closed terminal, or a crash. There is nothing to clean up,
# and it never touches a caffeinate you started yourself.

# The Claude Code process that ran this hook.
claude_pid="${CLAUDE_PID:-$PPID}"

# SessionStart fires again after /clear, /compact and /resume. Hold only once.
pgrep -qf "^caffeinate -i -w $claude_pid\$" && exit 0

# Detach from the hook's output so Claude Code does not wait for caffeinate.
caffeinate -i -w "$claude_pid" >/dev/null 2>&1 </dev/null &

Make it runnable:

chmod +x ~/.claude/hooks/claude-awake.sh

Then add this to ~/.claude/settings.json:

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/claude-awake.sh"
          }
        ]
      }
    ]
  }
}

If that file already has a "hooks" section, put the SessionStart entry inside it rather than pasting a second "hooks" block. To turn this on for one project only, use that project’s .claude/settings.json instead.

That is it. Start a new Claude Code session and your Mac stays awake until you quit. It covers scripted claude -p runs too. A session that was already open started before the hook existed, so open a fresh one. Type /hooks inside Claude Code to see it listed.

Here is how it works. Claude Code runs the script each time a session starts and tells it which process it is. The script starts caffeinate -w on that process, which keeps the Mac awake until Claude Code exits and then lets go by itself. It does not matter how Claude Code exits. Quit with /exit, close the terminal window, or have it crash, and the hold is gone either way.

Two details matter. The script sends caffeinate’s output to /dev/null, so Claude Code does not sit waiting on it at startup, and it prints nothing itself, so nothing is added to Claude’s context. And because SessionStart fires again after /clear, /compact and /resume, the script checks for its own caffeinate first and never starts a second one.

To check it is working, run pgrep -lf "caffeinate -i -w" in another terminal while a session is open. You should see one line per open session, something like 73622 caffeinate -i -w 73603, where the last number is the Claude Code process. After you quit, it prints nothing.

Do not rely on pmset -g assertions for this check. While Claude is working, Claude Code’s own caffeinate -i -t 300 shows up there too, so it can look like the hook is running when it is not.

The hook that looks right and is not

The obvious way to write this is to start caffeinate when the session starts and stop it on Claude Code’s Stop event. The name says stop.

Do not do that.

Stop fires every time Claude finishes a reply, not when you close the session. Hook your cleanup to it and your hold lasts for exactly one answer. For the rest of the session you are back to whatever Claude Code does on its own. It looks like it is working right up until the moment it matters.

The guides we found mostly avoid this by pairing Stop with UserPromptSubmit, which starts caffeinate again on every prompt. That is not wrong, but it only covers the time Claude is answering, which recent Claude Code already covers by itself. The Mac can still sleep while Claude waits for you.

SessionEnd is the event that fires when the session is over. It still cannot fire if Claude Code crashes or is force quit, and a caffeinate started by a hook then keeps your Mac awake until you notice. That is why the script above has no cleanup step at all. caffeinate -w follows the Claude Code process and lets go when it is gone.

Two smaller things some simple versions get wrong:

killall caffeinate is too blunt. It kills every caffeinate on your machine, including one you started by hand for a render or a big download, and the one behind a caffeinate -i claude you still have open. Claude keeps working with nothing holding the Mac awake, and nothing warns you. The script above never kills anything. Its caffeinate ends when Claude Code does.

Two windows break each other. If you run Claude Code in two projects at once, a single shared on/off switch means closing one window lets your Mac sleep while the other is still working. The script gives each Claude Code session its own caffeinate, tied to that session’s process.

Other agents

The one-line fix is not specific to Claude Code. caffeinate runs any command and holds the Mac awake until it exits:

caffeinate -i codex
caffeinate -i gemini

The hook is the Claude Code part. Codex has an experimental prevent_idle_sleep setting that keeps the Mac awake while a turn is running, and it is off by default. For any other agent, wrap it.

What this still does not solve

The script does its job. Your Mac stays awake for the whole session.

But being awake was never the expensive part of this problem. Three things are still true, and a keep-awake script does not fix them:

You cannot see it from wherever you are. The run is on your Mac. You are somewhere else. Is it still going? Did it finish an hour ago? Did something stop it at minute nine? You either walk back and look, or you guess.

Nothing tells you when it fails. Someone closes the lid. The power button gets knocked. macOS makes a decision you did not ask for. The script goes quiet and you find out in the morning.

The clock runs while you are still sitting there. You keep the Mac awake for two hours because you need two hours away from the desk. Then you keep working for forty minutes before you actually leave, and the time you were counting on gets spent while you are still in the chair.

Every one of these happens after you walk away, and a keep-awake command stays on the Mac.

Where Awake Qubit fits

We built Awake Qubit for that part.

It holds your Mac awake the same way caffeinate does, through the same public Apple API. That half is not the point. The point is the other half:

Your phone shows the live session. How long is left, which apps the Mac has open, whether the connection is healthy. Free.

It warns you when the hardware is in trouble. If the Mac overheats, runs very low on battery while unplugged, or nearly runs out of disk space during a session, the alert shows up on your Mac and your phone. Free.

It tells you if the Mac slept anyway. The interruption goes into Activity, your phone shows the Mac as asleep, and with Pro you get a sleep alert on your phone once the Mac is back.

Smart Pause only counts the time you are gone. On a timed session, the countdown freezes while you are typing, on a call or presenting full screen, and starts again after a short wait you choose. An hour means an hour away from the desk. Pro.

You can start, extend or stop a session from your phone, and lock the Mac’s screen without ending the run. Pro.

All of this works on sessions you start in Awake Qubit, on the Mac or (with Pro) from your phone, with the iPhone app signed in to the same iCloud account. The hook above does not talk to it. On the Mac itself, you can link a session to your terminal or editor so it ends when you quit that app, and the Assertions Inspector shows every process holding your Mac awake, the hook’s caffeinate included. Both free.

The Mac essentials are free on the App Store, and so is the iPhone app. Pro is $1.99 a month, $19.99 a year, or $49.99 once, and the yearly plan starts with a 7-day free trial. One purchase covers your Mac and your iPhone. Compare Free and Pro, or get Awake Qubit free on the App Store.

And if all you needed was the script, take the script. It is yours, it works, and you do not owe us anything for it.

Honest limits

A few things neither the script nor Awake Qubit can do:

  • Closing a MacBook’s lid puts it to sleep unless it is plugged in with an external display attached. Neither caffeinate nor any App Store app, Awake Qubit included, can override that. Workarounds like sudo pmset -a disablesleep 1 exist, but they change a system-wide setting you have to remember to undo (sudo pmset -a disablesleep 0), and a closed laptop in a bag gets hot.
  • A keep-awake hold only stops the Mac from sleeping on its own. Choosing Sleep from the Apple menu, pressing the power button, a nearly flat battery or overheating can still put it to sleep.
  • Once your Mac is asleep, the run is stuck until it wakes. Starting a session from your phone (Pro) will try to wake it, but that relies on macOS Wake for network access: on battery it usually cannot, and on the power adapter it can take a minute or more.
  • Linking a session to your terminal keeps the Mac awake while the terminal is open. It does not know when Claude Code finishes, and the session keeps going until you quit the terminal.

Worth knowing before you rely on any of this for something that matters.