Keep a Mac awake for a long-running job — a shell-agnostic `caf` wrapper around `caffeinate` (on/off/status, human durations like "2 hour", optional `--lid` to survive closing the lid via `pmset disablesleep`, auto-reverted when the timer expires, and a screen blackout that darkens the built-in display while the lid is shut and restores the brightness on open). Use to start/stop/inspect the keep-awake state on this Mac from any shell, or to install the whole setup (script + one-time sudoers g...
2 stars
0 votes
0 copies
3 views
Added September 6, 2026
toolsgoswiftshellbashdebugging
Works with
terminal
cli
Security analysis
B75/100
criticalAccesses sensitive system or user directories
Installs into .claude/skills of the current project.
Are you the author of caf?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/savchenko-dev-caf)
---
name: caf
description: Keep a Mac awake for a long-running job — a shell-agnostic `caf` wrapper around `caffeinate` (on/off/status, human durations like "2 hour", optional `--lid` to survive closing the lid via `pmset disablesleep`, auto-reverted when the timer expires, and a screen blackout that darkens the built-in display while the lid is shut and restores the brightness on open). Use to start/stop/inspect the keep-awake state on this Mac from any shell, or to install the whole setup (script + one-time sudoers grant) on a fresh Mac. Do NOT use for scheduling wakeups, `pmset` power profiles, or Linux/Windows sleep settings.
triggers:
- "keep the mac awake / don't let it sleep while X runs"
- "не давай маку засыпать, идёт выкатка / тесты"
- "caffeinate for 2 hours"
- "caf on / caf off / caf status"
- "keep it running with the lid closed"
- "add another hour / extend the keep-awake / продли caf"
- "is the mac still caffeinated? / turn sleep back on"
- "set up caf on this Mac / install my keep-awake script"
---
# caf — keep the Mac awake from any shell
`caf` is a small POSIX-`sh` script wrapping `caffeinate` with a pidfile, human-readable
durations, and an opt-in lid-close override. It is a plain executable, so it behaves
identically from `sh`, `bash`, `zsh`, `fish`, or a non-interactive agent shell.
Script: `~/.claude/skills/caf/caf` (run it by full path if it isn't on PATH).
## Commands
| 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 extend 1 hour` | add time to a running caf without dropping the lid override |
| `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-dim`) |
| `caf install-sudoers` | one-time setup so `--lid` needs no password (prompts for sudo) |
Durations are parsed by `/usr/bin/units`, so they need a space: `2 hour`, not `2h`.
Unparseable input fails loudly instead of silently caffeinating forever.
## Behaviour worth knowing
- **Background process, not a shell job.** `caffeinate -d -i [-t <secs>]` is started with
`nohup`, so it survives the invoking shell and the terminal window closing. Its pid lives
in `/tmp/caf.pid`.
- **`on` is idempotent.** With caffeinate already running, `caf on …` refuses to change the
timer (`run 'caf off' first`) — except `caf on --lid`, which adds the lid override to the
already-running process without restarting it.
- **`extend` is how you change a running timer.** It starts the replacement `caffeinate`
before killing the old one and never calls `pmset`, so there is no window where a shut
lid could sleep the Mac — unlike the `caf off && caf on --lid …` it replaces. It *adds*
to the remaining time, so it can never shorten a run; on an indefinite run, which has no
deadline to add to, it sets one that far out instead.
- **A timed run leaves a stale pidfile** once `caffeinate -t` exits by itself; `status`/`off`
detect that via `kill -0` and report OFF.
- **Lid override is real system state.** `sudo pmset -a disablesleep 1` disables lid-close
sleep machine-wide, and it persists across reboots until set back to 0. Every path that
sets it also restores it: `caf off`, and for a timed run a detached watcher that fires at
expiry. The watcher only reverts if `/tmp/caf.lid` still holds *its own* pid, so a later
`caf off` or a new `caf on --lid` can't be clobbered by a stale watcher.
- **`caf on --lid` prints warnings** about airflow with the lid closed, and about running on
battery (with the current percentage) — a flat battery kills every process anyway.
- **`--lid` also blacks out the screen.** `caffeinate -d` keeps the display awake, so the panel
would otherwise stay lit behind a shut lid and drain the battery to light nothing. A watcher
(`caf-dim watch`, pid in `/tmp/caf.dim`) polls the lid twice a second, sets the built-in
display to 0 on close, and restores the last brightness seen *while the lid was open*. It
touches only the panel `CGDisplayIsBuiltin()` reports, so an external monitor in clamshell
mode is never dimmed; it re-asserts 0 if macOS brings the backlight back; and it logs every
transition to `/tmp/caf.dim.log`. `caf off` restores brightness even after a `kill -9`, from
the value parked in `/tmp/caf.dimmed`. `--no-dim` opts out.
- **The blackout needs `swiftc`.** Brightness has no supported CLI on Apple Silicon, so
`caf-dim.swift` calls `DisplayServicesGet/SetBrightness` from the private DisplayServices
framework. It compiles on demand into `~/.cache/caf/caf-dim` (rebuilt when the source is
newer; `caf build` does it up front). Without `swiftc` the blackout is skipped with a
warning and `--lid` still works.
- **Retrofitting a running session.** With caffeinate already up *and* lid-close already
disabled, `caf on --lid` no longer just says "already ON" — it arms the blackout on the
existing process without restarting it.
## Using it on this Mac
Just run it. `caf status` first if the user asks whether the Mac is caffeinated; prefer a
bounded duration (`caf on 2 hour`) over indefinite when the job has a known length.
Only reach for `--lid` when the user explicitly wants the lid closed — it changes global
power behaviour, and a Mac running with a closed lid must be on a desk, never in a bag.
Never run `caf install-sudoers` unprompted: it writes `/etc/sudoers.d/caf-pmset` and needs
an interactive password. Ask the user to run it themselves.
## Installing on a fresh Mac (any shell)
1. Copy the script somewhere on PATH and make it executable:
```sh
install -m 755 ~/.claude/skills/caf/caf /usr/local/bin/caf
```
Any PATH dir works (`~/.local/bin`, `~/bin`, `~/dotfiles/bin` + a PATH entry). Because it
is an executable with a `#!/bin/sh` shebang, no per-shell function/alias is needed — the
same file serves `zsh`, `bash`, and `fish` alike.
Copy `caf-dim.swift` alongside it to keep the screen blackout — the script looks next to
itself, then in `~/.claude/skills/caf/`, then at `$CAF_DIM_SRC`. Then `caf build` once.
2. Optional, only needed for `--lid`: the user runs `caf install-sudoers` once. It writes
```text
<user> ALL=(root) NOPASSWD: /usr/bin/pmset -a disablesleep 0, /usr/bin/pmset -a disablesleep 1
```
to `/etc/sudoers.d/caf-pmset` (mode 440, root:wheel). Exact-match commands, no wildcards:
the worst it grants is toggling lid-close sleep. Without it, `--lid` still works but
prompts for a password — and the auto-revert watcher will fail silently at expiry, because
the sudo timestamp is long gone by then, so lid-close sleep stays disabled until `caf off`.
3. `units` (`/usr/bin/units`) and `caffeinate` ship with macOS — nothing else to install.
## Shadowing by a shell function
A shell function or alias named `caf` wins over a PATH executable — notably a fish-native
`caf` in `~/dotfiles/fish/functions/caf.fish`, which this script was ported from. If both
exist, `caf` means different code in fish than in zsh/bash, so check with
`type caf` / `functions caf` before debugging odd behaviour. Either mirror edits into both
or delete the function and let the script serve every shell; the sudoers grant is shared.
## Troubleshooting
- **`caf: don't understand duration '2h'`** — add a space: `2 hour`. `units` won't parse glued
forms.
- **`caf: can't reach pmset without a password prompt`** — the sudoers grant is missing; run
`caf install-sudoers`.
- **Lid-close sleep stayed disabled** — check `pmset -g | grep SleepDisabled`; `caf off`
restores it, or `sudo pmset -a disablesleep 0` directly.
- **`caf status` says OFF but the Mac stays awake** — something else is holding an assertion;
check `pmset -g assertions` (other tools, incl. agent harnesses, run their own `caffeinate`).
- **`screen blackout unavailable`** — no `swiftc` (`xcode-select --install`) or `caf-dim.swift`
isn't next to the script; `caf build` reports which. `--lid` still works, screen stays lit.
- **Screen stayed dark after the lid opened** — `caf off` restores it from `/tmp/caf.dimmed`,
or set it by hand: `~/.cache/caf/caf-dim set 0.5`.
- **Did the blackout actually fire?** You can't watch it happen, so read `/tmp/caf.dim.log` —
it records every close/open transition with the restore value.