Keep your Mac awake for as long as a job takes — a small POSIX-sh wrapper around
caffeinate with human-readable durations, a pidfile, and an opt-in lid-close override that
restores itself when the timer expires.
It's a plain executable with a #!/bin/sh shebang, so the same file behaves identically in
sh, bash, zsh, fish, or a non-interactive agent shell — no per-shell function, alias,
or plugin.
$ caf on 2 hour
caf: ON (pid 41207) for 2 hour (≈ 7200s) — until 23:31
$ caf status
caf: ON (pid 41207) — until 23:31 (1h58m left)
caf: lid-close normal — closing the lid sleeps the Mac
$ caf off
caf: OFFInstalling with an AI agent? Follow
SKILL.md— it carries the canonical, ordered steps. The one detail the snippet below encodes and agents keep missing:caf-dim.swiftmust land in the same directory ascaf, orcaf buildand--lidscreen-dimming can't work.
DIR=/usr/local/bin # any dir on PATH works: ~/.local/bin, ~/bin, …
curl -fsSL https://raw.githubusercontent.com/savchenko-dev/caf/main/caf -o "$DIR/caf"
curl -fsSL https://raw.githubusercontent.com/savchenko-dev/caf/main/caf-dim.swift -o "$DIR/caf-dim.swift"
chmod +x "$DIR/caf"macOS ships everything else it needs — caffeinate, pmset, and /usr/bin/units are all part
of the system. (swiftc, from xcode-select --install, is only needed for --lid screen
dimming; without it --lid still works, just lit.)
| Command | Effect |
|---|---|
caf on |
keep awake indefinitely (closing the lid still sleeps) |
caf on 2 hour |
keep awake for 2 hours; 15 min, 30 sec, 1.5 hour, hour also work |
caf on --lid |
also disable lid-close sleep, indefinitely |
caf on --lid 2 hour |
also disable lid-close sleep; auto-restored when the timer expires |
caf on --lid --no-dim |
keep the lid override but leave the screen lit |
caf off |
kill the caffeinate process, restore lid-close sleep and brightness |
caf status |
caffeinate ON/OFF (with until-time + time left for a timed run) + lid-close and screen-blackout state |
caf build |
precompile the screen-blackout helper |
caf install-sudoers |
one-time setup so --lid needs no password |
Durations are parsed by /usr/bin/units, so they need a space — 2 hour, not 2h.
Anything unparseable fails loudly instead of silently caffeinating forever:
$ caf on 2h
caf: don't understand duration '2h'
try: caf on 2 hour | 15 min | 30 sec | 1.5 hour | hour
note: glued forms like 2h / 15m aren't supported — add a spacecaffeinate cannot stop a laptop from sleeping when the lid closes — that takes
sudo pmset -a disablesleep 1, which is real machine-wide state that persists across
reboots. --lid opts into it, and every exit path puts it back:
caf offrestores it;- a timed
caf on --lid 2 hourspawns a detached watcher that restores it at expiry. The watcher only reverts if/tmp/caf.lidstill holds its own pid, so a latercaf offor a newcaf on --lidcan't be clobbered by a stale watcher.
Because the watcher fires long after the sudo timestamp has expired, --lid wants a
passwordless grant for exactly those two commands:
caf install-sudoerswrites /etc/sudoers.d/caf-pmset (mode 440, root:wheel):
<you> ALL=(root) NOPASSWD: /usr/bin/pmset -a disablesleep 0, /usr/bin/pmset -a disablesleep 1
Exact-match commands, no wildcards — the worst it grants is turning lid-close sleep on or
off. Without the grant --lid still works, but prompts for a password and the auto-revert at
expiry fails silently, leaving lid-close sleep disabled until the next caf off.
caf on --lid also warns you about the two ways this bites: a closed lid means no airflow
(desk only, never a bag), and running on battery means a flat battery kills every process it
was protecting.
caffeinate -d keeps the display awake, so with disablesleep 1 the panel stays lit behind a
closed lid — burning battery to light nothing. --lid therefore also arms a watcher that
blacks the screen out while the lid is shut and puts the brightness back when it opens:
$ caf on --lid
caf: ON (pid 41207) + lid-close disabled — no time limit, run 'caf off' to stop
✓ screen goes dark while the lid is shut, restored on open
$ caf status
caf: ON (pid 41207) — no time limit
caf: lid-close DISABLED — closing the lid keeps the Mac running
caf: screen blackout armed (pid 41219) — dark while the lid is shut, now 44%- The restore target is the last brightness seen while the lid was open, so a fade at close time can't be mistaken for your setting.
- It only ever drives the panel
CGDisplayIsBuiltin()reports, and does nothing when that panel is offline — an external monitor in clamshell mode is never touched. - macOS brings the backlight back on some wake events; the watcher holds it down and logs
every transition to
/tmp/caf.dim.log, which is how you check what happened with the lid shut. caf offrestores brightness even if the watcher was killed with-9, using the value parked in/tmp/caf.dimmed.--no-dimopts out and keeps the old lit-screen behaviour.
Brightness has no supported CLI on Apple Silicon, so this rides DisplayServicesGetBrightness
/ SetBrightness from the private DisplayServices framework via a small Swift helper
(caf-dim.swift). It is compiled on demand into ~/.cache/caf/caf-dim and rebuilt whenever
the source is newer — caf build does it up front. Without swiftc the blackout is skipped
with a warning and --lid still works.
caffeinate -d -i [-t <secs>]is started undernohup, so it survives the invoking shell and the terminal window closing. Its pid goes to/tmp/caf.pid.caf onis idempotent: with caffeinate already running it refuses to change the timer — exceptcaf on --lid, which adds the lid override to the running process without restarting it.- A timed run leaves a stale pidfile behind once
caffeinate -texits on its own;statusandoffdetect that withkill -0and report OFF.
This repo doubles as a Claude Code skill — clone it
straight into your skills directory and Claude can drive caf for you ("keep the Mac awake
while the deploy runs") or install it on a new machine:
git clone https://github.com/savchenko-dev/caf ~/.claude/skills/cafSKILL.md carries the model-facing instructions; the script sits next to it.
| Symptom | Fix |
|---|---|
caf: can't reach pmset without a password prompt |
run caf install-sudoers |
| lid-close sleep stayed disabled | caf off, or sudo pmset -a disablesleep 0 |
caf status says OFF but the Mac stays awake |
something else holds an assertion — see pmset -g assertions |
caf behaves differently in one shell |
a shell function/alias shadows the executable — check type caf |