KillSwitch
v1.0 PRD
KillSwitch is a lightweight macOS menu bar utility for seeing memory pressure and quickly quitting heavy apps.
KillSwitch exists to solve a very specific moment:
A user feels their Mac getting sluggish and wants to know, within a few seconds:
- Is memory pressure actually the problem?
- Which apps are using the most memory right now?
- Which app can I gracefully quit first?
KillSwitch is not a “Mac optimizer,” not a system cleaner, and not a dashboard product. It is a small native utility.
The product should feel:
- fast
- quiet
- useful
- native to macOS
- open-source worthy
- narrow in scope and well executed
- Live in the macOS menu bar
- Surface current memory state at a glance
- Show total unified memory used and available
- Show the top memory-using user apps
- Let the user gracefully quit an app from the popover
- Provide a very small settings window
- Provide standard app utility actions like updates and about
- Stay lightweight in both UX and runtime cost
- Feel polished enough to be a strong public GitHub project
- Be easy for others to clone, run, and understand
- Use native Apple frameworks and straightforward architecture
KillSwitch v1 must not become a full desktop product.
- notifications
- auto-cleaning
- automatic recovery actions
- AI recommendations
- memory history charts
- trend analytics
- scanning all processes in a noisy advanced view
- force quit as the primary behavior
- startup manager features
- CPU/network monitoring as first-class surfaces
- rich onboarding
- animated backgrounds
- theme system
- system cleaning claims
If a feature makes KillSwitch feel like a product suite instead of a utility, it should be excluded.
- Mac users on 8 GB / 16 GB machines who occasionally run into memory pressure
- developers, designers, and general users who keep many apps open
- users who want a faster path than opening Activity Monitor
- They want quick answers, not diagnostics theater
- They already understand what “quit” means
- They do not want the app itself to become visually or technically heavy
The popover is the product.
Use standard macOS patterns wherever possible.
KillSwitch reports memory usage and offers graceful quit. It does not promise fake optimization.
The app should open fast, refresh sensibly, and avoid unnecessary background work.
The codebase should be clear, focused, and practical.
As a user, I want to click a menu bar utility and instantly see whether memory pressure is high.
As a user, I want to see which apps are using the most memory without opening Activity Monitor.
As a user, I want to gracefully quit a heavy app and still preserve the app’s normal save prompts.
As a user, I want a simple refresh action if I suspect the list is stale.
As a user, I want basic utility commands such as settings, check for updates, about, and quit app.
KillSwitch has four surfaces only:
- Menu bar icon
- Main popover
- Overflow utility menu
- Mini settings window
There is also a standard About KillSwitch panel.
No other primary windows are needed in v1.
- User clicks the KillSwitch menu bar icon
- Popover opens
- User sees memory summary immediately
- User scans top memory-heavy apps
- User clicks
Quiton an app if desired - App terminates gracefully through normal macOS behavior
- Save prompts remain the responsibility of the target app / system
Secondary path:
- User opens overflow menu via
⋯ - User can choose:
- Refresh Now
- Check for Updates…
- About KillSwitch
- Settings…
- Quit KillSwitch
This PRD adopts the latest approved v1 design direction:
- compact menu bar popover
- subtle glass/material treatment only where useful
- mostly neutral surfaces
- restrained color only in memory bars and pressure state
- app-level commands moved into an overflow utility menu
- mini settings window rather than a full preferences app
The visual feel should be:
- native macOS
- light material shell
- crisp typography
- quiet hierarchy
- no dashboard bloat
- Always available in the macOS menu bar
- Clicking toggles the main popover
- monochrome icon
- simple enough to read at small size
- should feel like a native utility icon rather than a brand-heavy logo
This is the primary product surface.
- width: ~344 pt
- height: dynamic based on app rows
- Header
- Summary card
- Top applications list
- Footer
Contains:
- small app icon
KillSwitchtitle- subtitle:
Memory utility Refreshbutton⋯overflow button
- lightweight, utility-like
- compact vertical spacing
- slight material treatment is acceptable
- no oversized controls
Shows:
- label:
Unified Memory - primary value: e.g.
11.4 / 16 GB - secondary value: e.g.
4.6 GB available - pressure badge: e.g.
High Pressure - one main memory progress bar
- small footer labels:
Memory in useand percentage
- this is the strongest visual block in the popover
- should not feel like a big SaaS analytics card
- use restrained color only for the main memory bar and pressure state
Supported display states:
- Normal
- Elevated
- High
- Critical
Pressure state should be derived primarily from the OS memory pressure signal rather than a naive used-memory percentage alone.
Used / total memory and percent remain useful secondary display values, but the pressure badge should reflect real system pressure when possible.
Exact underlying thresholds may be tuned during implementation.
Shows the top 5–7 user-relevant apps by memory usage.
- left:
Top Applications - right:
By memory
- app name
- memory used (e.g.
3.2 GB) - percent of total memory (e.g.
20% total) - small usage meter
Quitbutton
- pressing
Quitrequests graceful termination for that app - the list refreshes after termination or next refresh cycle
- compact rows
- minimal visual separators
- readable typography
- buttons should look like real native controls, not text links
- heavy usage: warm gradient (orange/amber)
- medium usage: cool gradient (blue/cyan)
- light usage: green/teal gradient
This color is purely for scan speed and relative severity.
Contains:
- small status line:
Graceful quit keeps save prompts Settingsshortcut
Footer should be low emphasis.
Opened from the ⋯ button in the popover header.
Holds app-level commands that do not belong in the main content area.
In order:
Refresh NowCheck for Updates…About KillSwitchSettings…Quit KillSwitch
- compact native-style floating utility menu
- anchored visually to the header action area
- not large, not decorative
- should feel like a standard menu bar utility command sheet
Refresh Nowtriggers an immediate refreshCheck for Updates…checks for a newer buildAbout KillSwitchopens the standard about panelSettings…opens the mini settings windowQuit KillSwitchquits the app itself
A tiny preferences surface, intentionally limited.
- width: ~420 pt
- height: based on content, roughly 430–500 pt
- Title bar / standard macOS chrome
- General settings group
- Display settings group
- Footer actions
Includes:
- Launch at login
- Show Dock icon
- Show app icons
Includes:
- Sort apps by
- Refresh interval
Restore DefaultsDone
- should feel intentionally small
- grouped rows
- standard toggles and value controls
- no sidebar
- no tabs
- no advanced sections in v1
- opens a standard macOS About panel
- no custom marketing window needed in v1
- app name
- app icon
- version
- short one-line description
- copyright / attribution
- source repository link if desired
- neutral shell
- light material in small doses
- mostly opaque readable surfaces
- clean contrast
- tiny gradients only where they improve signal
Allowed:
- header shell
- footer shell
- subtle card background treatment
Avoid:
- heavy glass everywhere
- layered translucent chaos
- decorative visual effects that add no function
- strong, compact hierarchy
- no oversized marketing type
- prioritize readability and density
Button styles in v1:
- small bordered utility button for
Refresh - stronger push-button treatment for row-level
Quit - standard window actions in settings
Use color sparingly:
- pressure badge
- summary memory bar
- per-app mini meters
Everything else should stay mostly neutral.
The mock preview can use an ambient gradient backdrop, but the actual app should not ship with an expensive or theatrical background treatment.
Real app surfaces should be simple and native.
- app must launch into the menu bar
- app should be usable primarily from the menu bar surface
- app should not require a main document window
The app must display:
- total unified memory
- used memory
- available memory
- used percentage
- pressure state
The app must display a user-relevant list of running applications with:
- app name
- icon when enabled in settings
- memory usage in human-readable units
- percent of total memory
- list sorted according to selected sort mode
- each row exposes a
Quitaction - this action must be a graceful normal quit
- the app should not skip save prompts
- force quit is not part of the primary v1 surface
- user can manually trigger refresh
- app also refreshes automatically on a lightweight interval
Supported settings in v1:
- launchAtLogin: Bool
- showDockIcon: Bool
- showAppIcons: Bool
- sortMode: Enum
- refreshInterval: Enum
- baseloadLimit: Enum
The app must expose a Check for Updates… command.
Implementation note:
- if Sparkle is integrated, this should call the updater directly
- if update integration is deferred during early local development, the command may be temporarily stubbed or hidden in debug builds
The app must expose About KillSwitch and open the standard about panel.
The app must expose Quit KillSwitch to terminate itself.
- Swift
- SwiftUI
- AppKit interop only where needed
- no unnecessary dependencies in core functionality
Use SwiftUI App lifecycle.
Primary scenes:
- MenuBarExtra scene
- Settings scene
Optional:
- standard about panel through AppKit
KillSwitch/
├── KillSwitchApp.swift
├── Models/
│ ├── AppMemoryStat.swift
│ ├── MemorySnapshot.swift
│ ├── PressureLevel.swift
│ └── SettingsModel.swift
├── Services/
│ ├── MemoryMonitorService.swift
│ ├── RunningApplicationsService.swift
│ ├── ProcessMemoryService.swift
│ ├── ApplicationQuitService.swift
│ ├── SettingsStore.swift
│ ├── LoginItemService.swift
│ └── UpdateService.swift
├── ViewModels/
│ ├── MenuBarViewModel.swift
│ └── SettingsViewModel.swift
├── Views/
│ ├── MenuBar/
│ │ ├── MenuBarRootView.swift
│ │ ├── PopoverHeaderView.swift
│ │ ├── MemorySummaryCard.swift
│ │ ├── TopApplicationsSection.swift
│ │ ├── ApplicationRowView.swift
│ │ ├── FooterBarView.swift
│ │ └── OverflowMenuContent.swift
│ └── Settings/
│ └── SettingsView.swift
├── Support/
│ ├── Formatters.swift
│ ├── DesignTokens.swift
│ ├── PreviewData.swift
│ └── Constants.swift
└── Resources/
└── Assets.xcassets
Suggested fields:
- id
- pid
- name
- bundleIdentifier
- icon
- memoryBytes
- memoryPercentOfTotal
- isFrontmost
Suggested fields:
- totalBytes
- usedBytes
- availableBytes
- usedPercent
- pressureLevel
- capturedAt
Enum examples:
- normal
- elevated
- high
- critical
Suggested fields:
- launchAtLogin
- showDockIcon
- showAppIcons
- sortMode
- refreshInterval
- baseloadLimit
Responsible for:
- total memory snapshot
- available memory snapshot
- used memory calculation
- pressure state evaluation or system pressure mapping
Responsible for:
- reading running user-facing applications
- app names
- bundle ids
- icons
- frontmost detection if needed
Responsible for:
- per-process memory reads
- joining memory values back onto running applications
- avoiding UI logic
Responsible for:
- graceful application termination only
- clean encapsulation of quit behavior
Responsible for:
- saving and loading preferences
- likely backed by UserDefaults in v1
Responsible for:
- enabling / disabling launch at login
Responsible for:
- manual update checks
- integration with Sparkle or a future updater path
Responsible for:
- combining memory snapshot and application list
- sorting rows
- applying baseload inclusion rules
- exposing top 5–7 apps
- manual refresh
- timed refresh while popover is open
- simple state handling for errors / empty results
Responsible for:
- reading settings
- updating settings
- resetting defaults
KillSwitch must stay lightweight.
- refresh immediately when popover opens
- refresh every 3–5 seconds while popover remains open
- pause or significantly reduce work while popover is closed
- manual
Refreshbutton forces an immediate reload
This avoids turning the utility into a constant background sampler.
- memory descending
- name ascending
The app list should remain short and useful. It should not attempt to become a full process explorer.
The displayed list should prefer user-relevant apps.
An app should appear in the utility if it meets one of the following:
- it is within the top 5–7 user-relevant apps by memory usage
- its memory usage exceeds the configured baseload limit
- its percent of total memory is meaningfully large enough to remain useful in the list if additional tuning is needed during implementation
The goal is to avoid clutter from tiny processes while still surfacing meaningful offenders.
Baseload limit is a user-configurable filter that determines the minimum memory usage for an app to be eligible for display outside of the top ranked apps.
Recommended default behavior:
- Auto
- 150 MB
- 250 MB
- 500 MB
- 1 GB
- 8 GB Macs → 150 MB
- 16 GB Macs → 250 MB
- 24 GB or greater Macs → 500 MB
This keeps the list useful across lower-memory and higher-memory machines.
- visible apps
- normal user applications
- familiar high-level apps like browsers, Slack, Figma, Spotify, Notion
- low-level helper processes that clutter the list
- system daemons
- internal utility processes unless explicitly needed
Exact filtering can be tuned during implementation, but the final list should feel clean.
Quitmust request normal app termination- do not bypass the app’s own lifecycle
- preserve normal save prompts
If an app cannot be quit normally:
- do not crash
- do not hang the UI
- optionally show a small inline failure state later if needed
- force quit remains out of scope for primary v1
- type: toggle
- default: off or on depending on desired product stance
- recommended default for early builds: off
- type: toggle
- default: off
- type: toggle
- default: on
- type: segmented / menu / picker
- values:
- Memory
- Name
- default: Memory
- type: picker
- values:
- 3 sec
- 5 sec
- 10 sec
- default: 5 sec
- type: picker
- values:
- Auto
- 150 MB
- 250 MB
- 500 MB
- 1 GB
- default: Auto
- 8 GB Macs → 150 MB
- 16 GB Macs → 250 MB
- 24 GB or greater Macs → 500 MB
This setting controls the minimum memory usage required for an app to qualify for display outside of the top memory-ranked apps.
Resets all settings to v1 defaults.
If KillSwitch is distributed outside the App Store, use Sparkle for update checks and signed release delivery.
- UI includes
Check for Updates… - if Sparkle is wired, call the updater directly
- if Sparkle is not yet wired in development builds, allow this path to be disabled or stubbed
- GitHub repository is the source of truth for code
- GitHub Releases can be the release channel
- notarized builds and signed archives can be added as the release path when ready
Use the standard About panel instead of building a custom About window.
This keeps the app native and avoids unnecessary UI surface area.
- prefer standard SwiftUI and AppKit patterns
- keep controls compact
- use material lightly
- use a window-like menu bar popover layout
- make settings intentionally small
- custom chrome for the sake of custom chrome
- oversized rounded dashboard cards
- decorative motion
- design systems that add weight without function
When opened, KillSwitch should feel like a native utility someone already had on their Mac.
KillSwitch must remain credible as a memory utility.
- low idle overhead
- no constant heavy polling while closed
- no charts or history models in v1
- no image-heavy UI
- no web views
- no heavy dependency graph
The utility itself should not become the thing the user wants to quit.
- no meaningful app list returned
- permissions or API limitations for some processes
- transient memory readings changing between refreshes
- app quit call does nothing
- icon missing for some apps
- updater unavailable in debug builds
- stay quiet and stable
- degrade gracefully
- avoid noisy alerts unless absolutely necessary
This PRD should be used as the implementation spec for Codex.
- create macOS SwiftUI app
- add MenuBarExtra entry point
- add Settings scene
- wire basic icon and popover shell
- implement memory snapshot service
- implement running applications service
- implement per-app memory service
- expose mockable data models
- build header
- build summary card
- build top applications list
- build Quit row button
- build footer and settings shortcut
- add
Refresh Now - add
Check for Updates… - add
About KillSwitch - add
Settings… - add
Quit KillSwitch
- build mini settings window
- persist values with UserDefaults-backed store
- wire launch at login
- wire refresh interval and sort mode
- filter app list better
- tune spacing and materials
- validate refresh behavior
- verify quit flow and save prompt preservation
- add README
- add screenshots / GIF
- add install instructions
- add roadmap and contribution notes
KillSwitch v1 is done when:
- it launches into the menu bar reliably
- the popover opens fast
- memory summary is understandable at a glance
- top memory-heavy apps are shown clearly
Quitperforms graceful termination- overflow menu contains app-level commands
- settings window is minimal and functional
- update command path is accounted for
- about panel opens correctly
- the app still feels small, calm, and unobtrusive
KillSwitch is a lightweight macOS menu bar utility for seeing memory pressure and quickly quitting heavy apps.
Built in Swift and SwiftUI, KillSwitch gives you a fast, native way to spot memory-heavy apps and gracefully quit them without opening Activity Monitor.
These are explicitly post-ship ideas:
- optional force quit secondary action
- improved helper-process filtering
- compact popover mode
- Activity Monitor shortcut
- menu bar pressure-only mode
- basic optional notifications
These should not block v1.
If a user can install KillSwitch, click it, immediately understand system memory pressure, quit a heavy app, and then forget the utility exists until they need it again, the product is working.