2026-08-28
Prefix the command with caffeinate — caffeinate -i ./build.sh holds off idle sleep until build.sh exits, then releases automatically. To cover an already-running process, use caffeinate -i -w <pid>, which releases when that pid exits. The hold is scoped to the work, which is the whole point — nothing to remember to turn off. It does not survive the lid closing, and -s only works on AC power.
The naive way to keep a Mac awake for a long task is to open System Settings and set sleep to Never, run the task, and try to remember to set it back. The failure mode is the second half: nobody remembers, and the machine spends the next month never sleeping.
The right shape is a hold that is created by the work and dies with the work. That is exactly what caffeinate does when you give it a command:
caffeinate -i ./build.sh
caffeinate starts build.sh, holds an assertion against idle sleep for as long as it runs, and releases it the instant the process exits — success, failure, or ctrl-C. There is nothing to remember, because there is nothing left behind.
For work that is already running, scope to its pid instead:
caffeinate -i -w 48291
The assertion is released when that process exits.
From caffeinate(8), condensed to the ones you will actually use:
| Flag | Holds off | Notes |
|---|---|---|
-i | Idle system sleep | The default choice. Works on battery. |
-d | Display sleep | Add it if something on screen must stay visible |
-s | System sleep | AC power only — on battery it holds nothing |
-m | Disk idle sleep | Rarely needed on SSDs |
-w <pid> | — | Scope the hold to an existing process |
-t <secs> | — | Timed hold, no command attached |
The -s caveat is the one that bites people: it reads like the strongest option, and on a plugged-in machine it is, but the man page is explicit that the assertion is valid only on AC power. A laptop that leaves the desk mid-task is no longer holding anything.
You can watch any of these holds exist and disappear with pmset -g assertions, which lists every active assertion and the process behind it.
Two boundaries, one obvious and one not:
The lid. Every caffeinate assertion prevents some form of idle sleep. Closing the lid is not idle sleep, and it wins — in detail here. If the laptop will be closed while the work runs, you are in different territory.
Work that doesn't map to a process. caffeinate -i cmd is perfect when one process is the work. An AI coding agent breaks that assumption: the process sits blocked on a network socket for minutes at a time, looking exactly like an idle one, and the session outlives any single command. Scoping a hold to agent activity takes cooperation from the agent's harness, which is its own subject. For a plain long command, though — a build, a training run, an export, a huge copy — the wrapper pattern is exactly right, and goguma run -- <command> is the same idea with expiry and safety cutouts attached.
caffeinate, and everything else on this page, keeps an awake machine awake. If the machine will already be asleep when the work is due — the 3am cron job, the backup before you get up — no assertion helps, because there is nothing awake to hold. That case needs a scheduled wake, which is a different mechanism entirely.
Run the script under caffeinate — caffeinate -i ./script.sh. The assertion is created when the command starts and released when it exits, so the machine can sleep again the moment the work is done.
caffeinate -i -w <pid> waits on that pid and holds sleep off until it exits.
No. All of its assertions prevent idle sleep; closing the lid is a different kind of sleep and wins. On battery, a closed lid sleeps the machine regardless of caffeinate.
-i prevents idle system sleep and works on battery. -s prevents system sleep but is only valid on AC power — on battery it holds nothing.
goguma does this for you: it reads the scheduled jobs already on your Mac, wakes the machine shortly before each one is due, holds sleep off while it runs, and lets it sleep again afterwards. Free and open source, macOS 14+.
Get goguma →