- Published on
- 5 min read
> Prevent Your Mac from Sleeping While Claude Code Works
You kick off a big refactor with Claude Code, grab some coffee, and come back to find your Mac asleep and the task half-finished. Claude was waiting for a response from a tool, your Mac went to sleep, and network connections dropped or processes stalled.
The fix is caffeinate, a built-in macOS command that prevents sleep. Pair it with Claude Code hooks and you get automatic sleep prevention that kicks in when Claude starts working and releases when it's done.
How caffeinate Works
The caffeinate command ships with every Mac. Run it and your computer won't sleep until you stop it:
# Prevent sleep indefinitely (Ctrl+C to stop)
caffeinate
# Prevent sleep for a specific duration (in seconds)
caffeinate -t 3600 # 1 hour
# Prevent sleep while another command runs
caffeinate -i npm run build
The -i flag specifically prevents idle sleep, which is usually what you want. There's also -d to prevent display sleep and -s to prevent sleep only when on AC power. For Claude Code, -i covers most cases.
When you run caffeinate without -t or a command, it creates an assertion that keeps the system awake until the process exits. You can run it in the background and kill it later:
caffeinate -i &
CAFFEINE_PID=$!
# ... do work ...
kill $CAFFEINE_PID
The Simple Approach: A Wrapper Script
The quickest solution is a shell alias or script that wraps Claude Code:
# Add to ~/.zshrc or ~/.bashrc
claude-awake() {
caffeinate -i claude "$@"
}
Now claude-awake runs Claude Code and keeps your Mac awake for the entire session. When you exit Claude, caffeinate exits too. Simple, but it keeps your Mac awake even when Claude is idle waiting for your input.
Automatic Sleep Control with Hooks
For something smarter, use Claude Code's hooks system to start caffeinate only when Claude is actively working and stop it when Claude finishes a response.
Create or edit ~/.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "pgrep -qf 'caffeinate.*claude-code-session' || caffeinate -i -w $$ &"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "pkill -f 'caffeinate.*claude-code-session' 2>/dev/null || true"
}
]
}
]
}
}
The PreToolUse hook fires before Claude runs any tool. The pgrep check prevents spawning multiple caffeinate processes if one is already running. The -w $$ flag ties caffeinate to the parent shell, so if Claude crashes or you force-quit, caffeinate dies too.
The Stop hook fires when Claude finishes responding. It kills the caffeinate process, allowing your Mac to sleep normally until Claude needs to work again.
A More Robust Version
The hook above has a subtle issue: the Stop hook fires after every response, even quick ones. If you're having a rapid back-and-forth conversation, caffeinate starts and stops constantly. A better approach uses a dedicated PID file:
{
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "PIDFILE=\"/tmp/claude-caffeinate.pid\"; if [ ! -f \"$PIDFILE\" ] || ! kill -0 $(cat \"$PIDFILE\" 2>/dev/null) 2>/dev/null; then caffeinate -i & echo $! > \"$PIDFILE\"; fi"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "PIDFILE=\"/tmp/claude-caffeinate.pid\"; [ -f \"$PIDFILE\" ] && kill $(cat \"$PIDFILE\" 2>/dev/null) 2>/dev/null; rm -f \"$PIDFILE\""
}
]
}
]
}
}
This version writes the caffeinate PID to a file and checks if the process is still running before starting a new one. It also cleans up the PID file on stop.
Using a Notification Hook Instead
If you use Claude Code's notification system for long-running tasks, you can tie sleep prevention to that instead. The Notification hook fires when Claude would show a system notification:
{
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "PIDFILE=\"/tmp/claude-caffeinate.pid\"; if [ ! -f \"$PIDFILE\" ] || ! kill -0 $(cat \"$PIDFILE\" 2>/dev/null) 2>/dev/null; then caffeinate -i & echo $! > \"$PIDFILE\"; fi"
}
]
}
],
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "PIDFILE=\"/tmp/claude-caffeinate.pid\"; [ -f \"$PIDFILE\" ] && kill $(cat \"$PIDFILE\" 2>/dev/null) 2>/dev/null; rm -f \"$PIDFILE\""
}
]
}
]
}
}
Now your Mac stays awake while Claude works, and releases when Claude sends a notification that it's done. This works well if you've configured notifications to fire when Claude needs your attention.
Preventing Display Sleep Too
If you want to see what Claude is doing when you glance over, add the -d flag to prevent display sleep as well:
caffeinate -i -d &
Just be aware this keeps your screen on, which might not be what you want if you're stepping away for a while. You can also use -s to only prevent sleep when plugged in, letting your MacBook sleep normally on battery.
Which Approach to Use
The wrapper script is the simplest and works well if you always want your Mac awake during Claude sessions. It's one line in your shell config and you're done.
The hook-based approach is better if you have long sessions with mixed active work and idle time. Your Mac can sleep when you're thinking or reading Claude's output, but stays awake while it's churning through file edits.
The notification hook variant is ideal if you tend to kick off tasks and walk away. Your Mac stays awake until Claude explicitly signals it's done, then can sleep normally.
For most workflows, I'd start with the wrapper script and switch to hooks if you find your Mac staying awake longer than necessary.
// Continue_Learning
Auto-Approve the Xcode MCP Connection Prompt with Claude Code Hooks
The Xcode MCP server connection prompt interrupts your flow every time you restart Claude Code or clear your session. Here's how to automate it away using hooks.
Claude Code Auto Commit: How to Automatically Commit Changes as You Go
Claude Code can commit changes automatically while it works. Here's how to set that up using hooks, CLAUDE.md instructions, and the right permission configuration.
Using Vercel's Skills Library to Supercharge AI Agents for React Native
Vercel's Skills library lets you add reusable instruction sets to AI coding agents. Here's how to use it to make agents more effective for React Native development.
// Stay Updated
Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.