A macOS caffeinate utility — menu bar app + CLI. Mascot: Dapple the Mushroom.
- Swift (SwiftUI + AppKit hybrid)
- macOS 14+, Apple Silicon (arm64) only
- IOKit power assertions (native, no shelling out to
caffeinate) - Swift ArgumentParser for CLI
- XCTest for unit + integration tests
Three targets in Package.swift:
InsomniaCore— shared library (power management, scheduling, IPC, models)Insomnia— macOS GUI app (MenuBarExtra + AppKit)InsomniaCLI— CLI tool
swift build # debug build
swift build -Xswiftc -strict-concurrency=complete # build with strict concurrency (matches CI)
swift test # 133+ tests
swift run Insomnia # run GUI locally
swift run InsomniaCLI status # run CLIImportant: CI runs Swift 5.10 with strict concurrency checking. Always run swift build -Xswiftc -strict-concurrency=complete before pushing to catch actor-isolation errors that don't surface in default debug builds.
85%+ comment coverage required. Every file needs:
- File header explaining purpose
///doc comments on public APIs- Inline comments explaining intent on significant code blocks
- Tags:
v{major}.{minor}(e.g.,v0.2,v0.3) — no patch number - Build number: GitHub Actions run number becomes the patch
- Bundle version:
{major}.{minor}.{runNumber}(e.g.,0.2.42) - The
.0patch in tags is meaningless — never usev0.2.0
- Homebrew:
brew install --cask gordonbeeming/tap/insomnia- Always use fully qualified name (upstream "Insomnia" API client conflicts)
- Cask auto-updated by CI on release via deploy key
- GitHub Releases: signed + notarized DMG + CLI binary
- No App Store (IOKit needs unsandboxed access)
.github/workflows/build.yml- Push/PR: build + test only
- Release (published): build + test + sign + notarize + DMG + upload + update Homebrew tap
- Secrets:
DEVELOPER_ID_CERTIFICATE,DEVELOPER_ID_PASSWORD,APPLE_ID,APPLE_TEAM_ID,APPLE_APP_PASSWORD,HOMEBREW_TAP_DEPLOY_KEY
Debug builds use separate identifiers (BuildEnvironment.swift):
- App name: "Insomnia Dev"
- IPC socket:
~/Library/Application Support/Insomnia Dev/insomnia.sock - UserDefaults prefix:
com.insomnia.dev.* - "(Dev)" suffix in status text
This lets dev and prod run side-by-side.
Sources/InsomniaCore/Power/PowerAssertionManager.swift— IOKit assertion lifecycleSources/InsomniaCore/IPC/IPCServer.swift— Unix domain socket serverSources/InsomniaCore/Models/BuildEnvironment.swift— dev/prod separationSources/Insomnia/InsomniaApp.swift— @main, MenuBarExtra sceneSources/Insomnia/Views/MenuBarView.swift— main dropdown menuSources/Insomnia/AppDelegate.swift— lifecycle, IPC server, icon loadingScripts/build-release.sh— builds CLI + .app bundle (args: version, build number)Resources/AppIcon.icns— Dapple mushroom icon
LSUIElement apps need special handling to show windows:
openWindow(id:)to openNSApp.activate(ignoringOtherApps: true)after short delay The app always stays in.accessorymode (no dock icon).