README.md
Amped ⚊
A tiny, completely native macOS menu bar app that keeps your Mac awake — an
Amphetamine-style alternative whose party trick is keeping the Mac awake with
the lid closed, using pmset disablesleep rather than caffeinate alone.
No window, no settings sheet, no Dock icon. Just a pill in your menu bar and a handful of switches.
Install
| 1 | brew install --cask gustaferiksson/tap/amped |
Or grab the notarized Amped.app from the latest release
and drop it in /Applications. macOS 26 (Tahoe) or newer.
The menu
Click the pill in the menu bar:
| Toggle | What it does |
|---|---|
| Keep Awake | Prevents idle sleep while the lid is open. Uses an IOKit power assertion (same mechanism as caffeinate). No password needed. |
| Keep Running While Locked | Keeps the Mac and everything on it running with the lid closed (clamshell), and, when no external display is active, locks the screen and turns it off the instant the lid shuts so it stays behind your password. Runs pmset -a disablesleep 1, the only thing that overrides clamshell sleep; suppressing sleep also suppresses the usual lock-on-sleep, which is why Amped locks instead. An independent switch: it keeps the Mac awake on its own (it holds the idle system-sleep assertion internally) without flipping the Keep Awake toggle. It lets the display sleep as usual, so the normal idle lock still applies; turn on Keep Awake too to keep the screen on. |
| Auto-off at 20% Battery | Safety net: when on battery and the charge drops to 20% or below, Amped releases everything so the Mac can sleep normally. Remembered between launches. |
| Launch at Login | Registers Amped as a login item (via SMAppService) so the pill is there every time you log in. |
The menu bar pill reflects the state at a glance:
pill— sleep allowed (off)pill.fill— awake (lid open)pills.fill— awake with the lid closed
A status line shows the current state and battery level. ⌘Q quits.
On launch Amped starts with everything off (so it never surprises you by blocking sleep or prompting). Only the Auto-off preference is remembered. When it quits it always restores normal sleep behaviour.
How lid-closed mode stays passwordless
Keeping a Mac awake with the lid shut requires flipping the system
disablesleep flag, which only root can do. Amped does this through a small
privileged helper — a root LaunchDaemon embedded in the app bundle that
the app talks to over XPC. The XPC channel is locked to Amped's own
Developer-ID Team ID (setCodeSigningRequirement), so nothing but Amped's
signed app can reach the helper, and the helper does exactly one thing:
pmset disablesleep on/off.
The first time you enable Keep Running While Locked, Amped offers to set the helper up. Approve "Amped" once under System Settings → General → Login Items & Extensions, and from then on the lid toggle is silent — which also lets Auto-off at 20% drop clamshell mode while the lid is shut and you're away. Prefer not to? Just This Time keeps the Mac awake now with a single password prompt and installs nothing. Remove the helper anytime from that same System Settings pane (it's visible there, unlike a hidden sudoers rule); the setup offer reappears the next time you enable lid-closed mode.
The helper only runs in a properly signed build. In an unsigned local build it can't be approved, so lid mode falls back to a password prompt on every toggle. Build signed (below) to exercise the real path.
Build & run
Requires Xcode, plus two Homebrew tools:
| 1 | brew install xcodegen librsvg |
| 2 | ./build.sh # ad-hoc local build → ./dist (helper inactive; password fallback) |
| 3 | open dist/Amped.app # the pill appears in your menu bar |
Signed build (helper works)
Signing config lives in .env (git-ignored; copy from .env.example):
| 1 | DEVELOPMENT_TEAM=82K3YC8HVF |
| 2 | CODE_SIGN_IDENTITY="Developer ID Application" |
Then ./build.sh produces a build that meets Apple's notarization requirements:
Developer ID signing, Hardened Runtime on both the app and the helper, a
secure timestamp, and no get-task-allow entitlement. Install and try it:
| 1 | cp -R dist/Amped.app /Applications/ # run from a stable location |
| 2 | open /Applications/Amped.app |
Then: enable Keep Running While Locked → Set Up Helper… → approve Amped in System Settings → toggle Keep Running While Locked again — it's now silent. (No Team ID is hard-coded: the app reads its own at runtime to pin the XPC channel to the same team.)
Notarize & ship
One-time: create a notarytool keychain profile (the password is an
app-specific password from appleid.apple.com, not your Apple ID password):
| 1 | xcrun notarytool store-credentials "Amped" \ |
| 2 | --apple-id "you@example.com" --team-id 82K3YC8HVF --password "xxxx-xxxx-xxxx-xxxx" |
Set NOTARY_PROFILE=Amped in .env, then after a signed ./build.sh:
| 1 | ./notarize.sh # ditto-zips, notarytool submit --wait, stapler staple, verifies |
Distribute the stapled dist/Amped.app (zip or DMG). altool is dead since
Nov 2023 — this uses notarytool.
For automated releases — push a v* tag and CI produces the notarized
GitHub Release and bumps the Homebrew cask — see docs/RELEASING.md.
To work on it in Xcode:
| 1 | ./icon/generate-icons.sh && xcodegen generate && open Amped.xcodeproj |
(The .xcodeproj is generated from project.yml and is git-ignored.)
The icon
- Menu bar: an SF Symbol (
pillfamily) — Apple permits SF Symbols in your own UI, and they adapt to light/dark and the focus state automatically. - App icon:
icon/amped.svg(a two-tone capsule).icon/generate-icons.shrenders it into the asset catalog at all macOS sizes. To make a proper Liquid Glass icon, openamped.svgin Icon Composer, refine the layers, and export an.iconto drop into the project.
A note on the App Store
The lid-closed feature relies on pmset disablesleep / a privileged helper,
which a sandboxed App Store build cannot do. Ship it as a notarized
Developer ID app. An App Store version would have to drop the clamshell
feature.
Project layout
| 1 | Sources/ (the app) |
| 2 | AmpedApp.swift @main App + MenuBarExtra |
| 3 | MenuContent.swift the dropdown (toggles + status + quit) |
| 4 | MenuBarLabel.swift the pill SF Symbol that reflects state |
| 5 | SleepController.swift state, battery polling, auto-off safety net |
| 6 | PowerAssertion.swift IOKit power assertion wrapper (idle sleep) |
| 7 | Privileged.swift routes pmset to the helper, else an admin prompt |
| 8 | HelperClient.swift registers/calls the helper (SMAppService + XPC) |
| 9 | Battery.swift battery % + on-battery via IOKit power sources |
| 10 | LoginItem.swift launch-at-login via SMAppService |
| 11 | Prompts.swift first-use helper-setup dialogs |
| 12 | AppDelegate.swift restores normal sleep on quit |
| 13 | Helper/ (the privileged root daemon) |
| 14 | main.swift XPC listener entry point |
| 15 | HelperService.swift runs pmset as root; pins the client by Team ID |
| 16 | dev.gustaf.Amped.Helper.plist LaunchDaemon definition |
| 17 | Shared/ (compiled into both targets) |
| 18 | HelperProtocol.swift the XPC contract |
| 19 | HelperConstants.swift identifiers / service names |
| 20 | CodeSigning.swift Team-ID requirement helpers |
| 21 | icon/ amped.svg + render script |
| 22 | project.yml XcodeGen project (app + helper targets) |
| 23 | build.sh one-shot local / signed build |
| 24 | notarize.sh notarytool submit + stapler staple |
| 25 | .env.example signing / notary config template |