{"slug": "your-agent-didn-t-fail-you-closed-the-lid", "title": "Your agent didn't fail. You closed the lid", "summary": "A developer created SleepSwitch, a macOS menu bar utility that prevents Macs from sleeping when the lid is closed, addressing a common issue with AI coding agents and long-running tasks. The tool combines a user-level assertion with a root-level pmset command, and includes a battery guard to prevent overheating. It is available as a .pkg installer.", "body_md": "SleepSwitch is a macOS menu bar toggle that stops your Mac from sleeping — lid closed included. One click, no password prompts, and a battery guard so you don't cook your laptop in a bag.\n\nYou kick off a long agent run — Claude Code refactoring half a service, Codex grinding through a test suite, some pipeline that's going to take 40 minutes. You close the lid and walk away.\n\nYou come back to a session that died somewhere in the middle. Half the edits applied. The agent's context gone. Whatever it was in the middle of writing, gone with it.\n\nYour Mac went to sleep. That's it. That's the whole bug.\n\n`caffeinate`\n\ndoesn't save you\nThe standard answer is `caffeinate -dimsu`\n\n. It works — right up until you close the lid, at which point the Mac sleeps anyway.\n\nLid-close sleep is a **separate setting**, it lives behind `sudo`\n\n, and no user-level assertion touches it:\n\n```\nsudo pmset -a disablesleep 1   # the one that actually matters\n```\n\nSo the real workflow becomes: remember the flag, type your password, remember to turn it back off later, and — the fun part — forget once, drop the laptop in a bag, and it runs hot in there until the battery is flat.\n\nI got tired of that loop and wrote ** SleepSwitch**. One menu bar icon, one click, both layers at once.\n\n| Icon | Meaning |\n|---|---|\n| 🌙 | Normal — your Mac sleeps as configured |\n| ☕️ | Mode on — sleep fully blocked, lid included |\n| ⚠️ | Partial — idle sleep blocked, but the lid still sleeps |\n\nLeft click toggles. Right click is the menu — launch behaviour, login item, updates, the `sudo`\n\nrule.\n\nClose the lid with the mode on and you get a muted porcelain tone; open it and a higher one. Enough to confirm the machine stayed awake without opening anything to check.\n\nThis started as a \"keep the build running\" utility. Then AI coding agents happened, and it turned out they're the worst possible workload for macOS power management:\n\nSo: hit the switch, close the lid, come back to a finished run. Same for `npm run build`\n\non a monorepo, a long download, a render, an SSH session you need to survive lunch.\n\n| Layer | Blocks | Needs root |\n|---|---|---|\n`pmset -a disablesleep 1` |\nLid-close sleep, and all sleep | Yes |\n`PreventUserIdleSystemSleep` assertion |\nIdle sleep | No |\n`PreventUserIdleDisplaySleep` assertion |\nDisplay turning off | No |\n\nThe IOKit assertions are held by the process, so they evaporate the moment the app dies — they can't get stuck. The `pmset`\n\nsetting is different: it's a system setting that outlives the process. So the app clears it on quit, on `SIGTERM`\n\n, and reports the real state at launch by reading `SleepDisabled`\n\nstraight from `IOPMrootDomain`\n\nrather than trusting its own memory of what it did.\n\n`pmset disablesleep`\n\nneeds root, and prompting on every toggle makes the whole thing pointless. So the installer writes `/etc/sudoers.d/sleepswitch`\n\n:\n\n```\nyou ALL=(root) NOPASSWD: /usr/bin/pmset -a disablesleep 0\nyou ALL=(root) NOPASSWD: /usr/bin/pmset -a disablesleep 1\n```\n\nTwo commands, no wildcards. `sudo`\n\nmatches arguments exactly, so this grants \"toggle one sleep setting\" and nothing else — `pmset -a sleep 0`\n\nstill asks for a password.\n\nThe rule is written, validated with `visudo`\n\nand installed entirely as root inside a mode-`0700`\n\ntemp directory, so there's no user-writable file to swap in between the check and the install. The username is validated before it reaches `sudoers`\n\n, and only an account in the `admin`\n\ngroup gets it.\n\nDon't want it? Untick the box at install time, remove it later from the menu, or:\n\n```\nsudo rm /etc/sudoers.d/sleepswitch\n```\n\nThe failure mode I mentioned above is real and it's the reason this feature exists: mode on, lid closed, laptop in a bag, cooking.\n\nSo the mode switches itself off once the battery drops to a threshold you pick — 20% out of the box — and, optionally, the instant the power adapter is unplugged. A notification tells you which of the two fired.\n\nTwo small decisions I'd defend:\n\nGrab the `.pkg`\n\nfrom the [latest release](https://github.com/AppsGanin/SleepSwitch/releases/latest) and open it.\n\nIt's not signed with an Apple Developer certificate, so macOS blocks the first open. On Sequoia and newer, Control-click no longer overrides that: open the `.pkg`\n\n, let it be refused, then **System Settings → Privacy & Security → Open Anyway**. One time.\n\nOr from source:\n\n```\n./make-installer.sh     # → dist/SleepSwitch-<version>.pkg\n./install.sh            # or straight into /Applications\n```\n\nCommand Line Tools is the only requirement. The icon is drawn in code at build time, the lid tones are synthesised at build time — no binary assets in the repo. A missing translation fails the build.\n\n**One warning worth repeating:** turn the mode off *before* deleting the app. The `pmset`\n\nsetting is a system setting; dragging the app to the Trash while the mode is on leaves you with a Mac that won't sleep and no switch left to turn it off. The **Uninstall SleepSwitch…** menu item handles the ordering for you.\n\n`.pkg`\n\nand hands it to the system Installer. Requests pinned to `https`\n\non GitHub hosts, redirects included. Turn the check off and nothing goes over the network.** github.com/AppsGanin/SleepSwitch** — stars are appreciated, issues more so. ☕️", "url": "https://wpnews.pro/news/your-agent-didn-t-fail-you-closed-the-lid", "canonical_source": "https://dev.to/dmitryganin/your-agent-didnt-fail-you-closed-the-lid-g8o", "published_at": "2026-08-28 22:33:41+00:00", "updated_at": "2026-08-28 22:48:02.428317+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["SleepSwitch", "Claude Code", "Codex", "macOS"], "alternates": {"html": "https://wpnews.pro/news/your-agent-didn-t-fail-you-closed-the-lid", "markdown": "https://wpnews.pro/news/your-agent-didn-t-fail-you-closed-the-lid.md", "text": "https://wpnews.pro/news/your-agent-didn-t-fail-you-closed-the-lid.txt", "jsonld": "https://wpnews.pro/news/your-agent-didn-t-fail-you-closed-the-lid.jsonld"}}