Engineering Practice
`caffeinate` Is a Small Tool With a Clear Lifecycle
Use macOS's caffeinate in time-bounded or process-bounded modes to keep a laptop awake for a task and ensure it always stops when that task finishes.
- macOS
- Command Line
- Operational Safety
- Runbooks
The best tiny command-line tools do one thing, are easy to scope to another process, and stop automatically instead of becoming permanent configuration. caffeinate on macOS follows that pattern: it prevents sleep for a bounded intent (a duration or a target PID) and hands you a small, auditable blast radius instead of a global policy change.
Prefer bounded assertions to global policy
Disabling sleep at the OS or power-profile level is a hairball: it changes global defaults, requires privileges, and often outlives the task that needed it. That increases the blast radius (battery drain, thermal stress, lost automatic sleep on shared desks). A tiny tool should invert that risk by scoping intent and reverting automatically. Use caffeinate instead of editing pmset or energy preferences unless you mean to change behavior for all time and all users.
Two explicit modes: time-bounded and process-bounded
- Time-bounded:
caffeinate -t <seconds>asserts wakefulness for a fixed interval. Use this for predictable tasks: a known-length download, a scheduled long run, or a timed presentation rehearsal. Example:caffeinate -t 3600keeps the machine awake for one hour. - Process-bounded:
caffeinate -w <pid>waits while a given process ID runs and holds the assertion until it exits. This is the safer default for long, variable work: your task controls lifecycle, not an external timer. Example: start your job in one shell and wrap it:caffeinate -w $(pgrep -f my-download)or start under a shell that reports its own PID.
Tradeoffs: time-bounded is simple and auditable but can overrun or under-protect (if task runs longer than the timer). Process-bounded is precise but requires that the process you point at is the right owner of the task and that PID is stable.
Examples for common cases
-
Downloads: Start the download process, then
caffeinate -w <pid>so sleep stops automatically when the downloader exits. If your downloader spawns child processes, target the parent process that controls completion. -
Presentations: Use
caffeinate -t <seconds>with a margin:caffeinate -t $((90 * 60))for a 90-minute slot. Prefer a short margin and an escape route (kill the assertion) over a huge global timeout. -
Long tasks (compiles, builds, syncs): Start the job under your monitoring shell or a small wrapper that writes a PID file; then point caffeinate at that PID. For batch tooling run by automation systems, prefer the automation process’s PID or a supervisor so the assertion dies with the job.
Failure modes and costs: incorrect PID selection leaves the machine awake indefinitely; long timeouts waste battery and can throttle thermal headroom. If the task forks and detaches, -w can lose track—wrap the task or use a supervisor that doesn’t double-fork.
How to confirm and how to stop it
Confirmation steps:
- Check the process table:
pgrep -a caffeinateorps aux | grep caffeinate. - Inspect system assertions:
pmset -g assertionsshows who is preventing sleep and why; caffeinate appears as an assertion with your user and reason. - Verify expected behavior: close the lid or trigger a short sleep dry-run in a controlled environment (presentation room) to ensure the assertion blocks sleep as intended.
Stopping caffeinate:
- If caffeinate runs foreground in a shell, stop it with Ctrl-C.
- If it runs backgrounded,
pkill caffeinateorkill <pid>removes the assertion. - For process-bounded mode, stopping the target process causes caffeinate to exit and the system to resume normal sleep policy.
Acceptance criteria for a successful run:
- The device remains awake for the task window and returns to normal sleep behavior afterward.
- No global power-settings changed; only transient assertions were added.
- Battery and thermal metrics stayed within acceptable bounds during the run (if on battery, prefer short windows or an AC connection).
Checklist: run caffeinate safely
- Decide: Is this a time-bounded or process-bounded need? (Prefer process-bounded.)
- Prepare: Identify the PID or the expected duration; reserve a small margin.
- Start: Use
caffeinate -w <pid>orcaffeinate -t <seconds>. - Verify:
pmset -g assertionsandpgrep -a caffeinateshow the assertion. - Observe: monitor battery and temperature if on battery or in sensitive environments.
- End: Let the process exit or kill caffeinate; confirm assertions cleared with
pmset -g assertions.
Use this sequence as a preflight in a runbook when scheduling presentations or long unattended runs.
Design notes, tradeoffs, and where this advice is wrong
- Least privilege: caffeinate does not require privileged changes; it runs as the invoking user and its assertion is scoped. That matches the principle of smallest necessary change.
- Observability: Put the assertion intent in logs or a small note file (write a one-line record when you start caffeinate). That makes audits and postmortems straightforward: who requested extended wakefulness and why.
- Failure modes: the common slip is pointing caffeinate at the wrong PID (a short-lived wrapper), which causes early termination of the assertion. Another is leaving a long
-tvalue on a laptop on battery overnight. - When this advice is wrong: if an organization needs uniform power policy across a fleet or wants to disable sleep to support system-level services, modify the global policy via configuration management and treat it as a controlled change with rollback, not a local caffeinate invocation.
Takeaway
Tiny tools earn their keep by limiting scope and duration. Use caffeinate in process-bounded mode whenever possible, fall back to a short time-bounded mode with monitoring when needed, and always verify assertions with pmset -g assertions. Keep a short log entry alongside the command so you can answer who asked the machine to stay awake and why. If you need behavior that must outlive a user session or apply fleet-wide, treat it as a policy change, not a caffeinate invocation. /contact