
Have you ever been mid-presentation, watching a long build compile, or waiting for a large file to download β only for your Mac to decide it's nap time? macOS ships a built-in tool for exactly this: caffeinate. But running it from the terminal every time is clunky.
So I built NoSleep β a tiny macOS menu bar utility that wraps caffeinate in a one-click toggle. No Dock icon. No main window. Just a cup icon in your menu bar.
Features
- One-click toggle β start/stop caffeinate from the menu bar
- Duration presets β 15 min, 30 min, 1 hr, 2 hr, 4 hr, 8 hr, 10 hr, or Indefinite
-
Live countdown β shows remaining time while active (e.g.
2h 34m) - Start at Login β optional LaunchAgent so it auto-starts on boot
-
Prevents display + idle sleep β uses
caffeinate -d -i
The Stack
- Swift 6.0 with strict concurrency
-
SwiftUI +
MenuBarExtra(macOS 13+) - Swift Package Manager β no Xcode project file required
- Minimum target: macOS 14 (Sonoma)
App Entry Point: MenuBarExtra
The entire app lives in the menu bar, which SwiftUI makes surprisingly clean with MenuBarExtra:
@main
struct NoSleepApp: App {
@StateObject private var caffeinateManager = CaffeinateManager()
@StateObject private var loginManager = LoginItemManager()
var body: some Scene {
MenuBarExtra {
MenuBarView(manager: caffeinateManager, loginManager: loginManager)
} label: {
Image(systemName: caffeinateManager.isActive
? "cup.and.saucer.fill"
: "cup.and.saucer")
}
}
}
That's the whole entry point. MenuBarExtra handles all the menu bar plumbing β no NSStatusItem, no AppKit boilerplate. The icon toggles between a filled and outlined cup based on whether caffeinate is running.
Setting LSUIElement: true in Info.plist hides the Dock icon and removes the main window entirely.
Core Logic: CaffeinateManager
The heart of the app is CaffeinateManager β an @MainActor ObservableObject that manages the caffeinate child process and a countdown timer.
Spawning the Process
func start() {
stop()
let proc = Process()
proc.executableURL = URL(fileURLWithPath: "/usr/bin/caffeinate")
var args = ["-d", "-i"]
if selectedDuration != .indefinite {
args += ["-t", "\(selectedDuration.rawValue)"]
remainingSeconds = selectedDuration.rawValue
}
proc.arguments = args
proc.terminationHandler = { [weak self] _ in
Task { @MainActor [weak self] in
self?.handleTermination()
}
}
try? proc.run()
process = proc
isActive = true
if selectedDuration != .indefinite {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
Task { @MainActor [weak self] in
self?.tick()
}
}
}
}
A few things worth noting:
-d -i flags β -d prevents the display from sleeping, -i prevents idle sleep. Together they cover the common use cases.
-t <seconds> β when a duration is selected, caffeinate self-terminates after that many seconds. The app also runs a Timer in parallel to track remaining time for the UI.
terminationHandler β if caffeinate exits on its own (duration expired, or the system killed it), this handler fires and cleans up app state. The Task { @MainActor in ... } pattern bridges from the background callback thread into the main actor, which Swift 6 strict concurrency requires.
Duration Options
Durations are a typed enum with raw values in seconds:
enum SleepDuration: Int, CaseIterable, Identifiable, Sendable {
case fifteenMin = 900
case thirtyMin = 1800
case oneHour = 3600
case twoHours = 7200
case fourHours = 14400
case eightHours = 28800
case tenHours = 36000
case indefinite = 0
}
The selected duration is persisted in UserDefaults so the preference survives app restarts.
Login Item: LaunchAgent Plist
Rather than using SMAppService (which requires a sandboxed app), NoSleep writes a LaunchAgent plist directly to ~/Library/LaunchAgents/:
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.nosleep.app</string>
<key>ProgramArguments</key>
<array>
<string>/Users/you/Applications/NoSleep.app/Contents/MacOS/NoSleep</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
This approach works without sandboxing and gives full control over the plist.
Build & Install
The project uses Swift Package Manager β no .xcodeproj needed.
# Build (compiles, bundles, ad-hoc code signs)
./build.sh
# Run
open NoSleep.app
# Install to ~/Applications (optional)
./install.sh
Requirements: Swift 6.0+, Xcode Command Line Tools, macOS 14+.
Source Code
NoSleep is open source under the GPLv3.
GitHub: github.com/sergio-farfan/nosleep
Contributions, issues, and stars are all welcome. If you run into any macOS quirks with caffeinate or MenuBarExtra, feel free to open an issue.
Built with Swift 6 and SwiftUI on macOS Sonoma.
United States
NORTH AMERICA
Related News
CBS News Shutters Radio Service After Nearly a Century
5h ago
White House Unveils National AI Policy Framework To Limit State Power
5h ago
Officer Leaks Location of French Aircraft Carrier With Strava Run
5h ago
Microsoft Says It Is Fixing Windows 11
5h ago
NASA's Hubble Unexpectedly Catches Comet Breaking Up
5h ago
