On recent versions of macOS, closing the last window of an app leaves it running. Pages, Numbers, Preview, Notes and many others keep sitting in the Dock with no windows open, and you have to quit them by hand.
swift_kick quits them for you, the same way Cmd+Q would.
It only ever touches apps you explicitly add. Anything not on your list is never watched and never quit.
Open swift_kick and you get one window, Monitored Apps — that list is the configuration.
- Add lists the apps currently running. Pick one or more; they start being watched immediately.
- × on a row stops watching that app. It does not quit it.
- Apps you have added but that are not running show (not running).
Close the window and swift_kick keeps working in the background, with no Dock icon and no menu bar item. Open it again from Spotlight or Finder whenever you want to change the list.
Two checkboxes in the footer:
- Run in background — on by default. Turn it off if you would rather swift_kick quit when you close the window, so "is it running?" is answered by "is the window open?".
- Run at login — starts watching at login, silently. No window, no Dock icon.
./build.sh
open build/swift_kick.appNeeds macOS 15 or later and a Swift 6 toolchain. Move the built app wherever you
like, /Applications included.
build.sh signs with the first codesigning identity it finds, preferring
Developer ID over Apple Development. Override with
SIGN_IDENTITY="..." ./build.sh. With no identity it falls back to ad-hoc
signing, which works but has an annoying consequence — see below.
swift_kick counts windows through the Accessibility API, so macOS requires your permission. It asks on first launch.
Grant it under System Settings → Privacy & Security → Accessibility.
Until then swift_kick shows a banner and does not quit anything, though you can still edit the list. It starts working the moment you grant access — no relaunch needed.
It does not request Screen Recording, and does not need it.
If the banner stays after you grant access, the cause is almost always a stale entry. macOS ties the permission to the app's code signature, so an ad-hoc-signed build looks like a brand new app every time it is rebuilt. Remove every swift_kick entry from the Accessibility list and re-add the current build. Signing with a real identity avoids this entirely.
By design:
- It never force-quits. If an app refuses to quit — an unsaved-changes sheet, for example — swift_kick leaves it alone.
- It never quits Finder, the Dock, or other system apps, and they cannot be added.
- It will not quit an app you have hidden with Cmd+H, or one whose only window is minimized, or one whose last visible window is on another desktop.
- It only quits an app that it has actually seen open a window. An app sitting idle with no document open is left alone.
When anything is ambiguous — an Accessibility error, a timeout, a window list it cannot read — it does nothing. Leaving an app running is a much better failure than quitting one you were still using.
swift_kick attaches an Accessibility observer to each app on your list and waits for windows to close. When an app appears to have none left, it waits a moment, then checks twice: once through Accessibility, once against the window server's own list of visible windows across every desktop. Only if both agree the app has no windows does it ask the app to quit, using the same graceful terminate as Cmd+Q.
The second check exists because Accessibility alone is not reliable enough. Some apps keep a permanently blank, invisible window that never disappears, and windows on other desktops are not always visible to Accessibility. Getting either case wrong means quitting an app with a document still open, so both are checked against the window server directly.
| Path | Purpose |
|---|---|
AppDelegate.swift |
Lifecycle, single instance, Dock icon behavior |
MonitoredAppsWindow.swift |
The Monitored Apps window |
AddAppDialog.swift |
The Add App dialog |
AllowlistStore.swift |
Which apps are watched, and persistence |
Watcher.swift |
Observers and the quit sequence |
WindowCounter.swift |
Deciding whether a window is real |
ProtectedApps.swift |
Apps that must never be touched |
AccessibilityCoordinator.swift |
Permission handling, login item |
WindowCounter.swift carries comments explaining which window-detection
approaches were tried and why they fail; worth reading before changing it.
MIT