Skip to content

amoswzw/stayawake

Repository files navigation

stayawake

stayawake app icon

stayawake is a lightweight macOS menu-bar utility that automatically decides when your Mac should stay awake.

It is designed for long-running work: builds, downloads, renders, scripts, audio playback, fullscreen activity, and focused work apps. When there is no useful activity, it lets macOS sleep normally.

Project page · Latest release · Screenshots

Preview

The menu-bar character changes with the current decision. The sleeping character means macOS can sleep normally; the energized character means stayawake is actively keeping the Mac awake.

Awake and Sleep menu-bar status icons

Screenshots

More screenshots: Screenshots.

Features

  • Automatic sleep control with no manual toggle required for normal use
  • Menu-bar status icon with separate Awake and Sleep states
  • Current decision, reason, and recent logs directly in the menu
  • Manual keep-awake options for 30 minutes, 1 hour, or until turned off
  • Configurable CPU, network, disk, idle, process, foreground-app, and blocklist rules
  • Low-resource polling strategy for a small always-on menu-bar app
  • English and Simplified Chinese localization
  • No cloud service, account, telemetry, or content upload

Install

The fastest way to install is through Homebrew:

brew install --cask amoswzw/tap/stayawake

You can also download the latest DMG directly from the GitHub Releases page and drag stayawake.app into /Applications.

Requirements

Runtime:

  • macOS 13 or later

Development:

  • Xcode 15 or Swift 5.9 or later

Build

swift build -c release
./build-app.sh
open build/stayawake.app

build-app.sh creates an ad-hoc signed .app bundle at build/stayawake.app.

Usage

Launch the app and click the menu-bar icon. stayawake does not show a Dock icon.

The menu shows:

  • Current state: keeping awake, manual keep-awake, or sleep allowed
  • Current reason and next check timing
  • Recent logs: the latest 5 meaningful state changes
  • Manual keep-awake actions
  • Settings and full logs windows
  • Quit

The menu-bar icon follows macOS light and dark appearances. The sleeping character means sleep is allowed; the energized character means stayawake is actively keeping the Mac awake.

Settings

Open Settings... from the menu to configure:

  • Launch at login
  • App language
  • Idle threshold
  • Sampling and release cooldown
  • CPU, network, and disk thresholds
  • Task process names
  • Foreground work-app allowlist
  • Foreground/fullscreen blocklist

Settings are stored locally in UserDefaults.

How It Decides

stayawake collects lightweight system signals and feeds them into a pure policy function.

Signal Source
Idle time CGEventSourceSecondsSinceLastEventType
Foreground app NSWorkspace.frontmostApplication
Task process names sysctl(KERN_PROC_ALL)
Per-core CPU usage host_processor_info with a 60s P75 window
Network rate getifaddrs / if_data with a 60s P75 window
Disk rate IOBlockStorageDriver statistics with a 60s P75 window
Audio activity CoreAudio device running state
Fullscreen windows CGWindowListCopyWindowInfo
Battery / AC power IOPSGetProvidingPowerSourceType
Thermal state ProcessInfo.thermalState

Decision order:

  1. Manual override keeps the Mac awake.
  2. Serious or critical thermal state on battery allows sleep.
  3. Resource activity or audio keeps the Mac awake.
  4. Task process, foreground work app, or fullscreen activity keeps the Mac awake only when paired with recent user input.
  5. Probe failures keep the Mac awake to avoid interrupting work.
  6. User idle with no activity allows sleep.
  7. Otherwise, sleep is allowed.

Resource Usage

stayawake favors low overhead over high-frequency monitoring.

  • Automatic decisions are rechecked after the configured cooldown, defaulting to 120 seconds.
  • Manual keep-awake until turned off uses a longer 300-second tick.
  • Repeated identical automatic decisions are deduplicated in the log.
  • CoreAudio device lists are cached for 5 minutes.
  • Logs are kept in memory and capped.

This keeps the app small and quiet while preserving the main goal: avoid interrupting long-running work.

Privacy

  • No Accessibility permission is required.
  • No user files, windows, text, browser content, or terminal output are read.
  • No data is uploaded.
  • The app only reads aggregate system signals such as CPU, network, disk counters, app bundle IDs, process names, idle time, audio activity, and power state.

Localization

Bundled languages:

  • English
  • Simplified Chinese

To add another language:

  1. Create Sources/stayawake/Resources/<locale>.lproj/Localizable.strings.
  2. Use Sources/stayawake/Resources/en.lproj/Localizable.strings as the template.
  3. Add the locale to CFBundleLocalizations in build-app.sh.

Project Structure

.
├── Package.swift
├── build-app.sh
├── docs/_config.yml
├── docs/_layouts
├── docs/index.md
├── docs/SCREENSHOTS.md
├── docs/assets
├── docs/screenshots
├── Sources/stayawake
│   ├── App.swift
│   ├── AppCoordinator.swift
│   ├── MenuBarController.swift
│   ├── SettingsView.swift
│   ├── LogsView.swift
│   ├── Policy.swift
│   ├── *Probe.swift
│   └── Resources
│       ├── en.lproj
│       ├── zh-Hans.lproj
│       ├── status-awake-template.png
│       ├── status-sleep-template.png
│       └── stayawake.icns
└── Tests/stayawakeTests
    ├── PolicyTests.swift
    └── EventLogTests.swift

build/, .build/, and Xcode user state are generated locally and should not be committed.

Tests

swift test

The test suite covers policy decisions, signal derivation, log deduplication, blocklist behavior, and sliding-window behavior.

License

MIT. See LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors