Vibecode Bartender
track this build5 phases, 16 steps, beginner friendly0%The core loop is small enough for a capable coding agent to produce a useful local version in one sitting. For Bartender, hide, reveal, and arrange menu-bar items with user-defined rules. The hard boundary is deep macos menu-bar handling, os update compatibility, and polished interaction, plus os integration polish and maintenance.
You are building a lean indie version of Bartender. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # Bartender · indie build A background agent that collapses the menu bar down to the icons you actually watch, keeps the rest one click or one hotkey away, applies per-application and per-condition rules, and is honest in its own interface about the fact that this entire category breaks on major macOS releases. Estimated effort: **weekend**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Language | Swift 6 and SwiftUI in Xcode | NSStatusItem and the capture APIs are AppKit, and nothing else can reach them | | App type | A background agent with LSUIElement true | a menu bar manager with a Dock icon is a joke at its own expense | | Hiding mechanism | Your own NSStatusItem used as an expanding spacer | the only supported lever: your item grows and pushes other applications' items off the visible bar | | Redraw | ScreenCaptureKit, which requires the Screen Recording permission | the hidden icons belong to other processes, so the only way to show them in your own row is to capture and redraw them | | Storage | A property list in Application Support | rules and layout are small, structured and edited rarely | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **A Mac running macOS 14 or newer** · free if you already own a Mac - Why: The entire build is menu bar behaviour, which cannot be developed or tested anywhere else. - Get it: Apple menu, then About This Mac, to check the version. - Verify: About This Mac reports macOS 14 or higher - [ ] **Xcode 16 or newer** · free - Why: Builds and signs the agent. - Get it: Mac App Store or developer.apple.com/xcode. Large download, start it early. - Verify: xcodebuild -version prints 16 or higher - [ ] **Willingness to grant Screen Recording, and to explain it** · free - Why: Redrawing hidden icons is impossible without it, and users are right to treat the prompt seriously. You need a sentence you believe before you ask anyone else to accept it. - Get it: System Settings, then Privacy and Security, then Screen Recording. During development the grant must be re-given whenever the binary path or signature changes. - Verify: Capture returns menu bar pixels rather than a black frame - [ ] **A menu bar with at least eight items in it** · free - Why: The mechanism is invisible on a tidy bar, and the segmentation code in Phase 2 needs real variety in icon widths to be worth anything. - Get it: Install a handful of applications that add menu bar items, or borrow a colleague's cluttered machine for an hour of testing. - Verify: Your menu bar has enough items that some are pushed off on a narrow display - [ ] **Apple Developer Program membership** (optional) · 99 USD per year - Why: Product phase only. No Developer ID means no notarization, and for this category the update channel matters more than usual because macOS releases break it. - Get it: Enrol at developer.apple.com/programs. Review takes a day or two. - Verify: A Developer ID Application certificate appears in Xcode settings ## Quick start ```sh codesign --force --options runtime --sign "Developer ID Application: YOUR NAME" Bar.app xcrun notarytool submit Bar.zip --keychain-profile AC --wait ``` Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Any guarantee across major macOS releases. This category breaks and then gets fixed, every year. - The interaction polish that commercial alternatives have accumulated. - Settings sync between machines. - Support for the cases where the underlying mechanism only half works, which is most of what you are paying for. - deep macOS menu-bar handling, OS update compatibility, and polished interaction - years of OS-version edge cases - large extension ecosystem - cross-device sync - commercial support and rapid compatibility fixes If one of those is essential to you, that is the reason to keep paying for Bartender, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · Bartender The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a macOS menu bar manager that hides icons behind a divider and brings them back on demand to replace Bartender. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Language: Swift 6 and SwiftUI in Xcode · NSStatusItem and the capture APIs are AppKit, and nothing else can reach them - App type: A background agent with LSUIElement true · a menu bar manager with a Dock icon is a joke at its own expense - Hiding mechanism: Your own NSStatusItem used as an expanding spacer · the only supported lever: your item grows and pushes other applications' items off the visible bar - Redraw: ScreenCaptureKit, which requires the Screen Recording permission · the hidden icons belong to other processes, so the only way to show them in your own row is to capture and redraw them - Storage: A property list in Application Support · rules and layout are small, structured and edited rarely ### Data model (create this before Phase 1) - items(id, bundle_id, title, last_seen_at, hidden, always_visible, position) · one row per menu bar item you have observed - rules(id, item_id, trigger, condition_json, action) · trigger is app_activated, time_of_day, battery_state or manual - profiles(id, name, active) · a named set of hidden and visible assignments, for example presenting versus working - settings(key, value) · hotkey, spacer width, whether the hidden row auto-collapses and after how long - Item identity is the owning bundle identifier plus a stable title where one exists, because index position changes every time any application adds or removes an item. ### Phase 1 · Agent, status item and the spacer Build: A background agent with no Dock icon and one NSStatusItem. Give that item a variable length. Growing it consumes menu bar width and displaces items to its left, which is the entire mechanism every application in this category uses. Trap: There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. Done when: Growing the status item visibly pushes at least one other application's icon off the visible menu bar, and shrinking it brings the icon back. The agent has no Dock icon and does not appear in the application switcher. The width survives a relaunch. Do not build yet: No capture, no rules, no hotkey. One item that can take up space on demand. ### Phase 2 · Seeing the bar, which means asking for Screen Recording Build: Request Screen Recording and use ScreenCaptureKit to capture the menu bar region. Identify individual items by their bounds. Render the hidden ones into your own secondary row so clicking one forwards the click to the real item underneath. Trap: Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. Trap: The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. Done when: The hidden row renders recognisable copies of the displaced icons. Clicking a copy activates the real item, verified by an item whose menu you can see open. Refusing the permission leaves the application running with hiding available and redrawing disabled, with an explanation rather than a crash. Do not build yet: No rules and no hotkey yet. ### Phase 3 · Rules and profiles Build: Rules that fire on application activation, time of day, battery state or manual invocation. Profiles as named sets of hidden and visible assignments. Identify items by bundle identifier so a rule survives an item changing position. Trap: Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. Done when: Activating a chosen application hides the icons that rule names, and switching away restores them. A rule keyed to an item still applies after other applications have launched and shifted the layout. Switching profiles changes the visible set in one action and is reversible. Do not build yet: No hotkey search yet. ### Phase 4 · Hotkey, search and keyboard control Build: A global hotkey that reveals the hidden row, plus a search field that filters items by name and activates one with Return. Arrow keys move between items. Escape collapses. Trap: Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. Done when: The hotkey reveals the hidden row from any application. Typing filters to a matching item and Return activates it. Escape collapses the row and returns focus to the application that was frontmost. No Accessibility permission is requested anywhere in the application. Do not build yet: No distribution yet. ### Phase 5 · Surviving the operating system Build: Self-diagnostics that verify the spacer still displaces items and that capture still returns pixels. On failure, show a clear banner naming the macOS version and what is not working. Record the last macOS version the build was verified against. Trap: Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. Done when: Simulating a capture failure produces a visible banner naming the macOS version, not an empty row. The application reports the last version it was verified against. A first launch on an untested major version shows a caution rather than pretending everything is fine. Do not build yet: Signing and updates come next. ### Phase 6 · Signing, notarization and updates Build: Hardened runtime, Developer ID signing, notarization, stapling, and Sparkle updates. Because this category breaks on major releases, the update channel is not optional polish, it is how the application stays usable. Trap: Your first signed release invalidates the Screen Recording grant your testers gave the unsigned build, and macOS will not re-prompt. Put the removal instructions in the release notes rather than in a support reply. Done when: A notarized build opens on a Mac that never ran it, with no Gatekeeper warning, and requests Screen Recording once. An update published to the appcast installs and relaunches. The release notes explain the permission reset. Do not build yet: Nothing after this. ### Out of scope (and why) - A supported way to hide other applications' icons. It does not exist, and everything here rests on a spacer and a screen capture. - Guaranteed compatibility with the next macOS release. This category breaks roughly annually, and the honest deliverable is a diagnostic that tells you when it has. - The years of interaction polish behind the commercial applications, which is mostly the handling of the cases where the mechanism half works. - Cross-device settings sync, which would mean accounts and a server for a preferences file. ### README must contain - That hiding uses a spacer item and there is no API for hiding another application's icon - That Screen Recording is required only for redrawing hidden icons, what it can see, and that hiding still works without it - That no Accessibility permission is requested, and why the hotkey uses the Carbon registration - The last macOS version this build was verified against, and that major releases usually break this category - That re-signing invalidates the Screen Recording grant and how to clear the stale entry ===== AGENTS.md ===== # Agent instructions · Bartender indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: Swift 6 and SwiftUI in Xcode, A background agent with LSUIElement true, Your own NSStatusItem used as an expanding spacer, ScreenCaptureKit, which requires the Screen Recording permission, A property list in Application Support. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. - Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. - The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. - Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. - Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. - Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. ===== BUILD_PLAN.md ===== # Build plan · Bartender A background agent that collapses the menu bar down to the icons you actually watch, keeps the rest one click or one hotkey away, applies per-application and per-condition rules, and is honest in its own interface about the fact that this entire category breaks on major macOS releases. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · Agent, status item and the spacer Your own icon sits in the menu bar and can push other icons out of sight. ### Steps 1. Create the agent target SwiftUI app with Application is agent set to YES in Info.plist, and a MenuBarExtra so there is something to click before anything else works. Files: `Info.plist`, `App.swift` 2. Add a variable-length status item NSStatusItem with a length you set programmatically. Animate changes, because an instant jump reads as a glitch rather than an action. Files: `Spacer.swift` 3. Persist the state Write the current width and collapsed state to a property list in Application Support and restore it on launch. Files: `Settings.swift` ### Done when - [ ] Growing the item pushes another application's icon out of view - [ ] Shrinking it restores that icon - [ ] The agent has no Dock icon and no entry in the application switcher - [ ] Collapsed state survives quitting and relaunching ### Watch out - There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. ## Phase 2 · Seeing the bar, which means asking for Screen Recording You can enumerate and redraw the icons you have displaced, and the user understands why that needs a serious permission. ### Steps 1. Explain, then request Screen Recording Your own panel first, saying what is captured and what is not. Then CGRequestScreenCaptureAccess. A permission this broad deserves a sentence you wrote. Files: `Permissions.swift` 2. Capture the menu bar region and segment it SCStreamConfiguration limited to the menu bar strip. Segment on the gaps between items rather than assuming a fixed icon width, because widths vary. Files: `BarCapture.swift` 3. Render a secondary row and forward clicks Draw the captured icons in your own window below the bar. On click, synthesise a click at the real item's coordinates. Files: `HiddenRow.swift` 4. Degrade honestly without the permission Hiding still works, because the spacer needs no permission. Only the redraw does. Say which half is unavailable rather than disabling everything. Files: `Permissions.swift` ### Done when - [ ] The hidden row shows recognisable icons - [ ] Clicking a copy opens the real item's menu - [ ] Refusing Screen Recording leaves hiding working and says what is lost - [ ] Re-signing the app and relaunching surfaces a clear message about the stale grant ### Watch out - Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. - The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. ## Phase 3 · Rules and profiles The bar rearranges itself for the situation instead of needing you to fiddle with it. ### Steps 1. Observe application activation NSWorkspace notifications for activation and deactivation. This needs no additional permission and is the most useful trigger. Files: `Rules.swift` 2. Key rules to bundle identifiers Store the owner rather than the slot. Add a test that shuffles observed positions and asserts the same items are chosen. Files: `Items.swift` 3. Add profiles A named set with one active at a time, switchable from the menu and from a hotkey later. Files: `Profiles.swift` ### Done when - [ ] Activating an application applies its rule and deactivating reverses it - [ ] A rule still targets the right item after the layout shifts - [ ] Switching profiles changes the visible set in one action - [ ] A rule referencing an application that is not installed is ignored rather than erroring ### Watch out - Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. ## Phase 4 · Hotkey, search and keyboard control You never have to aim at a small icon with the mouse. ### Steps 1. Register the hotkey without Accessibility RegisterEventHotKey and a Carbon handler. Confirm in System Settings that your application is not listed under Accessibility. Files: `Hotkey.swift` 2. Add search over observed items Filter by application name and item title. Items you have seen before are searchable even when currently hidden. Files: `Search.swift` 3. Make the whole row keyboard navigable Arrows to move, Return to activate, Escape to dismiss and restore focus. Files: `HiddenRow.swift` ### Done when - [ ] The hotkey works while another application is frontmost - [ ] Typing filters and Return activates the right item - [ ] Escape collapses and returns focus to the previous application - [ ] The application does not appear in the Accessibility permission list ### Watch out - Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. ## Phase 5 · Surviving the operating system When a macOS release breaks the mechanism, the application says so instead of appearing broken. ### Steps 1. Write the self test Grow the spacer, capture, and assert the bar contents changed. Run it on launch and on demand from the menu. Files: `SelfTest.swift` 2. Show honest failure states A banner naming the macOS version and the specific capability that failed, with a link to your release notes. Files: `Diagnostics.swift` 3. Record the verified version Bake in the last macOS version you tested and compare at runtime. Show a caution above it rather than a hard block. Files: `Info.plist` ### Done when - [ ] A simulated capture failure produces a specific banner rather than an empty row - [ ] The verified macOS version is visible in the interface - [ ] An untested major version produces a caution on first launch - [ ] The self test can be run on demand and reports each capability separately ### Watch out - Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. ## Not in this build - Any guarantee across major macOS releases. This category breaks and then gets fixed, every year. - The interaction polish that commercial alternatives have accumulated. - Settings sync between machines. - Support for the cases where the underlying mechanism only half works, which is most of what you are paying for. ## After v1, if you want it - A presenting profile that hides everything except the clock - Per-display rules, because an external monitor changes how much bar you have - Importing an existing configuration from another menu bar manager ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Where rules, profiles and layout are stored. BAR_SETTINGS_PATH=~/Library/Application Support/Bar/settings.plist # Required. How long the revealed row stays open before collapsing. Zero disables auto-collapse. BAR_AUTOCOLLAPSE_SECONDS=8 # Required. The last macOS version this build was tested against. Shown in the interface and used for the untested-version caution. BAR_VERIFIED_MACOS=15.4 # Optional. Product phase only. Where the signed appcast is published. SPARKLE_FEED_URL=https://example.com/appcast.xml
You are building a lean indie version of Bartender. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # Bartender · indie build A background agent that collapses the menu bar down to the icons you actually watch, keeps the rest one click or one hotkey away, applies per-application and per-condition rules, and is honest in its own interface about the fact that this entire category breaks on major macOS releases. Estimated effort: **weekend**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Language | Swift 6 and SwiftUI in Xcode | NSStatusItem and the capture APIs are AppKit, and nothing else can reach them | | App type | A background agent with LSUIElement true | a menu bar manager with a Dock icon is a joke at its own expense | | Hiding mechanism | Your own NSStatusItem used as an expanding spacer | the only supported lever: your item grows and pushes other applications' items off the visible bar | | Redraw | ScreenCaptureKit, which requires the Screen Recording permission | the hidden icons belong to other processes, so the only way to show them in your own row is to capture and redraw them | | Storage | A property list in Application Support | rules and layout are small, structured and edited rarely | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **A Mac running macOS 14 or newer** · free if you already own a Mac - Why: The entire build is menu bar behaviour, which cannot be developed or tested anywhere else. - Get it: Apple menu, then About This Mac, to check the version. - Verify: About This Mac reports macOS 14 or higher - [ ] **Xcode 16 or newer** · free - Why: Builds and signs the agent. - Get it: Mac App Store or developer.apple.com/xcode. Large download, start it early. - Verify: xcodebuild -version prints 16 or higher - [ ] **Willingness to grant Screen Recording, and to explain it** · free - Why: Redrawing hidden icons is impossible without it, and users are right to treat the prompt seriously. You need a sentence you believe before you ask anyone else to accept it. - Get it: System Settings, then Privacy and Security, then Screen Recording. During development the grant must be re-given whenever the binary path or signature changes. - Verify: Capture returns menu bar pixels rather than a black frame - [ ] **A menu bar with at least eight items in it** · free - Why: The mechanism is invisible on a tidy bar, and the segmentation code in Phase 2 needs real variety in icon widths to be worth anything. - Get it: Install a handful of applications that add menu bar items, or borrow a colleague's cluttered machine for an hour of testing. - Verify: Your menu bar has enough items that some are pushed off on a narrow display - [ ] **Apple Developer Program membership** (optional) · 99 USD per year - Why: Product phase only. No Developer ID means no notarization, and for this category the update channel matters more than usual because macOS releases break it. - Get it: Enrol at developer.apple.com/programs. Review takes a day or two. - Verify: A Developer ID Application certificate appears in Xcode settings ## Quick start ```sh codesign --force --options runtime --sign "Developer ID Application: YOUR NAME" Bar.app xcrun notarytool submit Bar.zip --keychain-profile AC --wait ``` Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Any guarantee across major macOS releases. This category breaks and then gets fixed, every year. - The interaction polish that commercial alternatives have accumulated. - Settings sync between machines. - Support for the cases where the underlying mechanism only half works, which is most of what you are paying for. - deep macOS menu-bar handling, OS update compatibility, and polished interaction - years of OS-version edge cases - large extension ecosystem - cross-device sync - commercial support and rapid compatibility fixes If one of those is essential to you, that is the reason to keep paying for Bartender, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · Bartender The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a macOS menu bar manager that hides icons behind a divider and brings them back on demand to replace Bartender. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Language: Swift 6 and SwiftUI in Xcode · NSStatusItem and the capture APIs are AppKit, and nothing else can reach them - App type: A background agent with LSUIElement true · a menu bar manager with a Dock icon is a joke at its own expense - Hiding mechanism: Your own NSStatusItem used as an expanding spacer · the only supported lever: your item grows and pushes other applications' items off the visible bar - Redraw: ScreenCaptureKit, which requires the Screen Recording permission · the hidden icons belong to other processes, so the only way to show them in your own row is to capture and redraw them - Storage: A property list in Application Support · rules and layout are small, structured and edited rarely ### Data model (create this before Phase 1) - items(id, bundle_id, title, last_seen_at, hidden, always_visible, position) · one row per menu bar item you have observed - rules(id, item_id, trigger, condition_json, action) · trigger is app_activated, time_of_day, battery_state or manual - profiles(id, name, active) · a named set of hidden and visible assignments, for example presenting versus working - settings(key, value) · hotkey, spacer width, whether the hidden row auto-collapses and after how long - Item identity is the owning bundle identifier plus a stable title where one exists, because index position changes every time any application adds or removes an item. ### Phase 1 · Agent, status item and the spacer Build: A background agent with no Dock icon and one NSStatusItem. Give that item a variable length. Growing it consumes menu bar width and displaces items to its left, which is the entire mechanism every application in this category uses. Trap: There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. Done when: Growing the status item visibly pushes at least one other application's icon off the visible menu bar, and shrinking it brings the icon back. The agent has no Dock icon and does not appear in the application switcher. The width survives a relaunch. Do not build yet: No capture, no rules, no hotkey. One item that can take up space on demand. ### Phase 2 · Seeing the bar, which means asking for Screen Recording Build: Request Screen Recording and use ScreenCaptureKit to capture the menu bar region. Identify individual items by their bounds. Render the hidden ones into your own secondary row so clicking one forwards the click to the real item underneath. Trap: Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. Trap: The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. Done when: The hidden row renders recognisable copies of the displaced icons. Clicking a copy activates the real item, verified by an item whose menu you can see open. Refusing the permission leaves the application running with hiding available and redrawing disabled, with an explanation rather than a crash. Do not build yet: No rules and no hotkey yet. ### Phase 3 · Rules and profiles Build: Rules that fire on application activation, time of day, battery state or manual invocation. Profiles as named sets of hidden and visible assignments. Identify items by bundle identifier so a rule survives an item changing position. Trap: Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. Done when: Activating a chosen application hides the icons that rule names, and switching away restores them. A rule keyed to an item still applies after other applications have launched and shifted the layout. Switching profiles changes the visible set in one action and is reversible. Do not build yet: No hotkey search yet. ### Phase 4 · Hotkey, search and keyboard control Build: A global hotkey that reveals the hidden row, plus a search field that filters items by name and activates one with Return. Arrow keys move between items. Escape collapses. Trap: Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. Done when: The hotkey reveals the hidden row from any application. Typing filters to a matching item and Return activates it. Escape collapses the row and returns focus to the application that was frontmost. No Accessibility permission is requested anywhere in the application. Do not build yet: No distribution yet. ### Phase 5 · Surviving the operating system Build: Self-diagnostics that verify the spacer still displaces items and that capture still returns pixels. On failure, show a clear banner naming the macOS version and what is not working. Record the last macOS version the build was verified against. Trap: Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. Done when: Simulating a capture failure produces a visible banner naming the macOS version, not an empty row. The application reports the last version it was verified against. A first launch on an untested major version shows a caution rather than pretending everything is fine. Do not build yet: Signing and updates come next. ### Phase 6 · Signing, notarization and updates Build: Hardened runtime, Developer ID signing, notarization, stapling, and Sparkle updates. Because this category breaks on major releases, the update channel is not optional polish, it is how the application stays usable. Trap: Your first signed release invalidates the Screen Recording grant your testers gave the unsigned build, and macOS will not re-prompt. Put the removal instructions in the release notes rather than in a support reply. Done when: A notarized build opens on a Mac that never ran it, with no Gatekeeper warning, and requests Screen Recording once. An update published to the appcast installs and relaunches. The release notes explain the permission reset. Do not build yet: Nothing after this. ### Out of scope (and why) - A supported way to hide other applications' icons. It does not exist, and everything here rests on a spacer and a screen capture. - Guaranteed compatibility with the next macOS release. This category breaks roughly annually, and the honest deliverable is a diagnostic that tells you when it has. - The years of interaction polish behind the commercial applications, which is mostly the handling of the cases where the mechanism half works. - Cross-device settings sync, which would mean accounts and a server for a preferences file. ### README must contain - That hiding uses a spacer item and there is no API for hiding another application's icon - That Screen Recording is required only for redrawing hidden icons, what it can see, and that hiding still works without it - That no Accessibility permission is requested, and why the hotkey uses the Carbon registration - The last macOS version this build was verified against, and that major releases usually break this category - That re-signing invalidates the Screen Recording grant and how to clear the stale entry ===== AGENTS.md ===== # Agent instructions · Bartender indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: Swift 6 and SwiftUI in Xcode, A background agent with LSUIElement true, Your own NSStatusItem used as an expanding spacer, ScreenCaptureKit, which requires the Screen Recording permission, A property list in Application Support. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. - Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. - The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. - Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. - Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. - Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. ===== BUILD_PLAN.md ===== # Build plan · Bartender A background agent that collapses the menu bar down to the icons you actually watch, keeps the rest one click or one hotkey away, applies per-application and per-condition rules, and is honest in its own interface about the fact that this entire category breaks on major macOS releases. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · Agent, status item and the spacer Your own icon sits in the menu bar and can push other icons out of sight. ### Steps 1. Create the agent target SwiftUI app with Application is agent set to YES in Info.plist, and a MenuBarExtra so there is something to click before anything else works. Files: `Info.plist`, `App.swift` 2. Add a variable-length status item NSStatusItem with a length you set programmatically. Animate changes, because an instant jump reads as a glitch rather than an action. Files: `Spacer.swift` 3. Persist the state Write the current width and collapsed state to a property list in Application Support and restore it on launch. Files: `Settings.swift` ### Done when - [ ] Growing the item pushes another application's icon out of view - [ ] Shrinking it restores that icon - [ ] The agent has no Dock icon and no entry in the application switcher - [ ] Collapsed state survives quitting and relaunching ### Watch out - There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. ## Phase 2 · Seeing the bar, which means asking for Screen Recording You can enumerate and redraw the icons you have displaced, and the user understands why that needs a serious permission. ### Steps 1. Explain, then request Screen Recording Your own panel first, saying what is captured and what is not. Then CGRequestScreenCaptureAccess. A permission this broad deserves a sentence you wrote. Files: `Permissions.swift` 2. Capture the menu bar region and segment it SCStreamConfiguration limited to the menu bar strip. Segment on the gaps between items rather than assuming a fixed icon width, because widths vary. Files: `BarCapture.swift` 3. Render a secondary row and forward clicks Draw the captured icons in your own window below the bar. On click, synthesise a click at the real item's coordinates. Files: `HiddenRow.swift` 4. Degrade honestly without the permission Hiding still works, because the spacer needs no permission. Only the redraw does. Say which half is unavailable rather than disabling everything. Files: `Permissions.swift` ### Done when - [ ] The hidden row shows recognisable icons - [ ] Clicking a copy opens the real item's menu - [ ] Refusing Screen Recording leaves hiding working and says what is lost - [ ] Re-signing the app and relaunching surfaces a clear message about the stale grant ### Watch out - Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. - The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. ## Phase 3 · Rules and profiles The bar rearranges itself for the situation instead of needing you to fiddle with it. ### Steps 1. Observe application activation NSWorkspace notifications for activation and deactivation. This needs no additional permission and is the most useful trigger. Files: `Rules.swift` 2. Key rules to bundle identifiers Store the owner rather than the slot. Add a test that shuffles observed positions and asserts the same items are chosen. Files: `Items.swift` 3. Add profiles A named set with one active at a time, switchable from the menu and from a hotkey later. Files: `Profiles.swift` ### Done when - [ ] Activating an application applies its rule and deactivating reverses it - [ ] A rule still targets the right item after the layout shifts - [ ] Switching profiles changes the visible set in one action - [ ] A rule referencing an application that is not installed is ignored rather than erroring ### Watch out - Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. ## Phase 4 · Hotkey, search and keyboard control You never have to aim at a small icon with the mouse. ### Steps 1. Register the hotkey without Accessibility RegisterEventHotKey and a Carbon handler. Confirm in System Settings that your application is not listed under Accessibility. Files: `Hotkey.swift` 2. Add search over observed items Filter by application name and item title. Items you have seen before are searchable even when currently hidden. Files: `Search.swift` 3. Make the whole row keyboard navigable Arrows to move, Return to activate, Escape to dismiss and restore focus. Files: `HiddenRow.swift` ### Done when - [ ] The hotkey works while another application is frontmost - [ ] Typing filters and Return activates the right item - [ ] Escape collapses and returns focus to the previous application - [ ] The application does not appear in the Accessibility permission list ### Watch out - Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. ## Phase 5 · Surviving the operating system When a macOS release breaks the mechanism, the application says so instead of appearing broken. ### Steps 1. Write the self test Grow the spacer, capture, and assert the bar contents changed. Run it on launch and on demand from the menu. Files: `SelfTest.swift` 2. Show honest failure states A banner naming the macOS version and the specific capability that failed, with a link to your release notes. Files: `Diagnostics.swift` 3. Record the verified version Bake in the last macOS version you tested and compare at runtime. Show a caution above it rather than a hard block. Files: `Info.plist` ### Done when - [ ] A simulated capture failure produces a specific banner rather than an empty row - [ ] The verified macOS version is visible in the interface - [ ] An untested major version produces a caution on first launch - [ ] The self test can be run on demand and reports each capability separately ### Watch out - Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. ## Not in this build - Any guarantee across major macOS releases. This category breaks and then gets fixed, every year. - The interaction polish that commercial alternatives have accumulated. - Settings sync between machines. - Support for the cases where the underlying mechanism only half works, which is most of what you are paying for. ## After v1, if you want it - A presenting profile that hides everything except the clock - Per-display rules, because an external monitor changes how much bar you have - Importing an existing configuration from another menu bar manager ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Where rules, profiles and layout are stored. BAR_SETTINGS_PATH=~/Library/Application Support/Bar/settings.plist # Required. How long the revealed row stays open before collapsing. Zero disables auto-collapse. BAR_AUTOCOLLAPSE_SECONDS=8 # Required. The last macOS version this build was tested against. Shown in the interface and used for the untested-version caution. BAR_VERIFIED_MACOS=15.4 # Optional. Product phase only. Where the signed appcast is published. SPARKLE_FEED_URL=https://example.com/appcast.xml
You are building a production product version of Bartender. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== PRODUCT.md ===== # Bartender · product brief ## Problem The core loop is small enough for a capable coding agent to produce a useful local version in one sitting. For Bartender, hide, reveal, and arrange menu-bar items with user-defined rules. The hard boundary is deep macos menu-bar handling, os update compatibility, and polished interaction, plus os integration polish and maintenance. ## Product outcome A menu bar manager that works, asks for exactly one serious permission and explains it, degrades honestly when refused, and tells the user when a macOS release has broken the mechanism rather than looking broken itself. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - macOS 14 or later - Xcode - only the permissions required by the selected feature ## Explicit non-goals for v1 - Any guarantee across major macOS releases. This category breaks and then gets fixed, every year. - The interaction polish that commercial alternatives have accumulated. - Settings sync between machines. - Support for the cases where the underlying mechanism only half works, which is most of what you are paying for. - deep macOS menu-bar handling, OS update compatibility, and polished interaction - years of OS-version edge cases - large extension ecosystem - cross-device sync - commercial support and rapid compatibility fixes ## Success criteria - The self test passes on the newest macOS version you support - Refusing Screen Recording leaves hiding functional with a clear explanation - The application does not appear in the Accessibility permission list - spctl accepts the notarized build on a Mac that never ran it - The release notes explain the permission reset caused by signing ===== BRIEF.md ===== # Build brief · Bartender The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a macOS menu bar manager that hides icons behind a divider and brings them back on demand to replace Bartender. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Language: Swift 6 and SwiftUI in Xcode · NSStatusItem and the capture APIs are AppKit, and nothing else can reach them - App type: A background agent with LSUIElement true · a menu bar manager with a Dock icon is a joke at its own expense - Hiding mechanism: Your own NSStatusItem used as an expanding spacer · the only supported lever: your item grows and pushes other applications' items off the visible bar - Redraw: ScreenCaptureKit, which requires the Screen Recording permission · the hidden icons belong to other processes, so the only way to show them in your own row is to capture and redraw them - Storage: A property list in Application Support · rules and layout are small, structured and edited rarely ### Data model (create this before Phase 1) - items(id, bundle_id, title, last_seen_at, hidden, always_visible, position) · one row per menu bar item you have observed - rules(id, item_id, trigger, condition_json, action) · trigger is app_activated, time_of_day, battery_state or manual - profiles(id, name, active) · a named set of hidden and visible assignments, for example presenting versus working - settings(key, value) · hotkey, spacer width, whether the hidden row auto-collapses and after how long - Item identity is the owning bundle identifier plus a stable title where one exists, because index position changes every time any application adds or removes an item. ### Phase 1 · Agent, status item and the spacer Build: A background agent with no Dock icon and one NSStatusItem. Give that item a variable length. Growing it consumes menu bar width and displaces items to its left, which is the entire mechanism every application in this category uses. Trap: There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. Done when: Growing the status item visibly pushes at least one other application's icon off the visible menu bar, and shrinking it brings the icon back. The agent has no Dock icon and does not appear in the application switcher. The width survives a relaunch. Do not build yet: No capture, no rules, no hotkey. One item that can take up space on demand. ### Phase 2 · Seeing the bar, which means asking for Screen Recording Build: Request Screen Recording and use ScreenCaptureKit to capture the menu bar region. Identify individual items by their bounds. Render the hidden ones into your own secondary row so clicking one forwards the click to the real item underneath. Trap: Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. Trap: The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. Done when: The hidden row renders recognisable copies of the displaced icons. Clicking a copy activates the real item, verified by an item whose menu you can see open. Refusing the permission leaves the application running with hiding available and redrawing disabled, with an explanation rather than a crash. Do not build yet: No rules and no hotkey yet. ### Phase 3 · Rules and profiles Build: Rules that fire on application activation, time of day, battery state or manual invocation. Profiles as named sets of hidden and visible assignments. Identify items by bundle identifier so a rule survives an item changing position. Trap: Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. Done when: Activating a chosen application hides the icons that rule names, and switching away restores them. A rule keyed to an item still applies after other applications have launched and shifted the layout. Switching profiles changes the visible set in one action and is reversible. Do not build yet: No hotkey search yet. ### Phase 4 · Hotkey, search and keyboard control Build: A global hotkey that reveals the hidden row, plus a search field that filters items by name and activates one with Return. Arrow keys move between items. Escape collapses. Trap: Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. Done when: The hotkey reveals the hidden row from any application. Typing filters to a matching item and Return activates it. Escape collapses the row and returns focus to the application that was frontmost. No Accessibility permission is requested anywhere in the application. Do not build yet: No distribution yet. ### Phase 5 · Surviving the operating system Build: Self-diagnostics that verify the spacer still displaces items and that capture still returns pixels. On failure, show a clear banner naming the macOS version and what is not working. Record the last macOS version the build was verified against. Trap: Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. Done when: Simulating a capture failure produces a visible banner naming the macOS version, not an empty row. The application reports the last version it was verified against. A first launch on an untested major version shows a caution rather than pretending everything is fine. Do not build yet: Signing and updates come next. ### Phase 6 · Signing, notarization and updates Build: Hardened runtime, Developer ID signing, notarization, stapling, and Sparkle updates. Because this category breaks on major releases, the update channel is not optional polish, it is how the application stays usable. Trap: Your first signed release invalidates the Screen Recording grant your testers gave the unsigned build, and macOS will not re-prompt. Put the removal instructions in the release notes rather than in a support reply. Done when: A notarized build opens on a Mac that never ran it, with no Gatekeeper warning, and requests Screen Recording once. An update published to the appcast installs and relaunches. The release notes explain the permission reset. Do not build yet: Nothing after this. ### Out of scope (and why) - A supported way to hide other applications' icons. It does not exist, and everything here rests on a spacer and a screen capture. - Guaranteed compatibility with the next macOS release. This category breaks roughly annually, and the honest deliverable is a diagnostic that tells you when it has. - The years of interaction polish behind the commercial applications, which is mostly the handling of the cases where the mechanism half works. - Cross-device settings sync, which would mean accounts and a server for a preferences file. ### README must contain - That hiding uses a spacer item and there is no API for hiding another application's icon - That Screen Recording is required only for redrawing hidden icons, what it can see, and that hiding still works without it - That no Accessibility permission is requested, and why the hotkey uses the Carbon registration - The last macOS version this build was verified against, and that major releases usually break this category - That re-signing invalidates the Screen Recording grant and how to clear the stale entry ===== ARCHITECTURE.md ===== # Architecture · Bartender ## Stack | Part | Choice | Why | | --- | --- | --- | | Language | Swift 6 and SwiftUI in Xcode | NSStatusItem and the capture APIs are AppKit, and nothing else can reach them | | App type | A background agent with LSUIElement true | a menu bar manager with a Dock icon is a joke at its own expense | | Hiding mechanism | Your own NSStatusItem used as an expanding spacer | the only supported lever: your item grows and pushes other applications' items off the visible bar | | Redraw | ScreenCaptureKit, which requires the Screen Recording permission | the hidden icons belong to other processes, so the only way to show them in your own row is to capture and redraw them | | Storage | A property list in Application Support | rules and layout are small, structured and edited rarely | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Spacer | The status item whose width does the hiding. | Not swappable. This is the only lever the platform offers and everything else is presentation. | | Capture | Reading the bar and segmenting items. | ScreenCaptureKit is the only sanctioned path. The segmentation heuristic inside it is yours and will need revisiting after macOS releases. | | Rules | Triggers, conditions and profiles. | Pure logic over observed items, testable without a menu bar at all, and the part most likely to survive an operating system change. | | Diagnostics | Knowing whether the mechanism still works. | Never remove this. It is what separates a broken build from a broken operating system in the user's mind. | | Updates | Shipping the fix after a macOS release. | Sparkle is conventional. What matters is that the channel exists before you need it urgently. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `BAR_SETTINGS_PATH` · required · Where rules, profiles and layout are stored. - `BAR_AUTOCOLLAPSE_SECONDS` · required · How long the revealed row stays open before collapsing. Zero disables auto-collapse. - `BAR_VERIFIED_MACOS` · required · The last macOS version this build was tested against. Shown in the interface and used for the untested-version caution. - `SPARKLE_FEED_URL` · optional · Product phase only. Where the signed appcast is published. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it. ===== AGENTS.md ===== # Agent instructions · Bartender product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: Swift 6 and SwiftUI in Xcode, A background agent with LSUIElement true, Your own NSStatusItem used as an expanding spacer, ScreenCaptureKit, which requires the Screen Recording permission, A property list in Application Support. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. - Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. - The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. - Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. - Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. - Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. - Your first signed release invalidates the Screen Recording grant your testers gave the unsigned build, and macOS will not re-prompt. Put the removal instructions in the release notes rather than in a support reply. ===== MILESTONES.md ===== # Delivery milestones · Bartender Estimated effort: **weekend** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · Agent, status item and the spacer Your own icon sits in the menu bar and can push other icons out of sight. ### Steps 1. Create the agent target SwiftUI app with Application is agent set to YES in Info.plist, and a MenuBarExtra so there is something to click before anything else works. Files: `Info.plist`, `App.swift` 2. Add a variable-length status item NSStatusItem with a length you set programmatically. Animate changes, because an instant jump reads as a glitch rather than an action. Files: `Spacer.swift` 3. Persist the state Write the current width and collapsed state to a property list in Application Support and restore it on launch. Files: `Settings.swift` ### Done when - [ ] Growing the item pushes another application's icon out of view - [ ] Shrinking it restores that icon - [ ] The agent has no Dock icon and no entry in the application switcher - [ ] Collapsed state survives quitting and relaunching ### Watch out - There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. ## M2 · Seeing the bar, which means asking for Screen Recording You can enumerate and redraw the icons you have displaced, and the user understands why that needs a serious permission. ### Steps 1. Explain, then request Screen Recording Your own panel first, saying what is captured and what is not. Then CGRequestScreenCaptureAccess. A permission this broad deserves a sentence you wrote. Files: `Permissions.swift` 2. Capture the menu bar region and segment it SCStreamConfiguration limited to the menu bar strip. Segment on the gaps between items rather than assuming a fixed icon width, because widths vary. Files: `BarCapture.swift` 3. Render a secondary row and forward clicks Draw the captured icons in your own window below the bar. On click, synthesise a click at the real item's coordinates. Files: `HiddenRow.swift` 4. Degrade honestly without the permission Hiding still works, because the spacer needs no permission. Only the redraw does. Say which half is unavailable rather than disabling everything. Files: `Permissions.swift` ### Done when - [ ] The hidden row shows recognisable icons - [ ] Clicking a copy opens the real item's menu - [ ] Refusing Screen Recording leaves hiding working and says what is lost - [ ] Re-signing the app and relaunching surfaces a clear message about the stale grant ### Watch out - Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. - The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. ## M3 · Rules and profiles The bar rearranges itself for the situation instead of needing you to fiddle with it. ### Steps 1. Observe application activation NSWorkspace notifications for activation and deactivation. This needs no additional permission and is the most useful trigger. Files: `Rules.swift` 2. Key rules to bundle identifiers Store the owner rather than the slot. Add a test that shuffles observed positions and asserts the same items are chosen. Files: `Items.swift` 3. Add profiles A named set with one active at a time, switchable from the menu and from a hotkey later. Files: `Profiles.swift` ### Done when - [ ] Activating an application applies its rule and deactivating reverses it - [ ] A rule still targets the right item after the layout shifts - [ ] Switching profiles changes the visible set in one action - [ ] A rule referencing an application that is not installed is ignored rather than erroring ### Watch out - Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. ## M4 · Hotkey, search and keyboard control You never have to aim at a small icon with the mouse. ### Steps 1. Register the hotkey without Accessibility RegisterEventHotKey and a Carbon handler. Confirm in System Settings that your application is not listed under Accessibility. Files: `Hotkey.swift` 2. Add search over observed items Filter by application name and item title. Items you have seen before are searchable even when currently hidden. Files: `Search.swift` 3. Make the whole row keyboard navigable Arrows to move, Return to activate, Escape to dismiss and restore focus. Files: `HiddenRow.swift` ### Done when - [ ] The hotkey works while another application is frontmost - [ ] Typing filters and Return activates the right item - [ ] Escape collapses and returns focus to the previous application - [ ] The application does not appear in the Accessibility permission list ### Watch out - Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. ## M5 · Surviving the operating system When a macOS release breaks the mechanism, the application says so instead of appearing broken. ### Steps 1. Write the self test Grow the spacer, capture, and assert the bar contents changed. Run it on launch and on demand from the menu. Files: `SelfTest.swift` 2. Show honest failure states A banner naming the macOS version and the specific capability that failed, with a link to your release notes. Files: `Diagnostics.swift` 3. Record the verified version Bake in the last macOS version you tested and compare at runtime. Show a caution above it rather than a hard block. Files: `Info.plist` ### Done when - [ ] A simulated capture failure produces a specific banner rather than an empty row - [ ] The verified macOS version is visible in the interface - [ ] An untested major version produces a caution on first launch - [ ] The self test can be run on demand and reports each capability separately ### Watch out - Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. ## M6 · Signing, notarization and updates (production only) Someone else can install it, and you can ship the fix the next macOS release will demand. ### Steps 1. Sign and notarize Hardened runtime, Developer ID Application, notarytool, stapler. ```sh codesign --force --options runtime --sign "Developer ID Application: YOUR NAME" Bar.app xcrun notarytool submit Bar.zip --keychain-profile AC --wait ``` 2. Ship Sparkle with a signed appcast An EdDSA key pair with the private half outside the repository, and appcast.xml served over HTTPS. Files: `appcast.xml` 3. Write the permission reset note One paragraph telling users to remove the stale Screen Recording entry after the first signed update. Files: `RELEASE_NOTES.md` ### Done when - [ ] spctl reports the notarized build accepted - [ ] A fresh Mac opens it with no Gatekeeper warning - [ ] An appcast update installs and relaunches - [ ] The release notes explain the permission reset ### Watch out - Your first signed release invalidates the Screen Recording grant your testers gave the unsigned build, and macOS will not re-prompt. Put the removal instructions in the release notes rather than in a support reply. ===== OPERATIONS.md ===== # Operations · Bartender ## Backup The settings property list is the whole state. It is small enough to copy anywhere and is covered by any ordinary backup of the home directory. ## Restore Quit, replace the property list, relaunch, and confirm the profile list matches. Rules referencing uninstalled applications are ignored rather than erroring, so a restore onto a different machine degrades gracefully. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Run the self test on launch and record the result. A rising failure rate across your users after a macOS release is the signal to ship, and without the self test you learn it from support threads instead. ## Incident checklist A macOS release breaking the mechanism is the expected incident, not an unlikely one. Keep the previous build downloadable, put a minimum and maximum verified macOS version in the appcast, and lead the release notes with what changed on Apple's side. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] The self test passes on the newest macOS version you support - [ ] Refusing Screen Recording leaves hiding functional with a clear explanation - [ ] The application does not appear in the Accessibility permission list - [ ] spctl accepts the notarized build on a Mac that never ran it - [ ] The release notes explain the permission reset caused by signing ## Launch constraint Do not market omitted Bartender capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered. ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required. Where rules, profiles and layout are stored. BAR_SETTINGS_PATH=~/Library/Application Support/Bar/settings.plist # Required. How long the revealed row stays open before collapsing. Zero disables auto-collapse. BAR_AUTOCOLLAPSE_SECONDS=8 # Required. The last macOS version this build was tested against. Shown in the interface and used for the untested-version caution. BAR_VERIFIED_MACOS=15.4 # Optional. Product phase only. Where the signed appcast is published. SPARKLE_FEED_URL=https://example.com/appcast.xml
# Bartender · indie build A background agent that collapses the menu bar down to the icons you actually watch, keeps the rest one click or one hotkey away, applies per-application and per-condition rules, and is honest in its own interface about the fact that this entire category breaks on major macOS releases. Estimated effort: **weekend**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Language | Swift 6 and SwiftUI in Xcode | NSStatusItem and the capture APIs are AppKit, and nothing else can reach them | | App type | A background agent with LSUIElement true | a menu bar manager with a Dock icon is a joke at its own expense | | Hiding mechanism | Your own NSStatusItem used as an expanding spacer | the only supported lever: your item grows and pushes other applications' items off the visible bar | | Redraw | ScreenCaptureKit, which requires the Screen Recording permission | the hidden icons belong to other processes, so the only way to show them in your own row is to capture and redraw them | | Storage | A property list in Application Support | rules and layout are small, structured and edited rarely | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **A Mac running macOS 14 or newer** · free if you already own a Mac - Why: The entire build is menu bar behaviour, which cannot be developed or tested anywhere else. - Get it: Apple menu, then About This Mac, to check the version. - Verify: About This Mac reports macOS 14 or higher - [ ] **Xcode 16 or newer** · free - Why: Builds and signs the agent. - Get it: Mac App Store or developer.apple.com/xcode. Large download, start it early. - Verify: xcodebuild -version prints 16 or higher - [ ] **Willingness to grant Screen Recording, and to explain it** · free - Why: Redrawing hidden icons is impossible without it, and users are right to treat the prompt seriously. You need a sentence you believe before you ask anyone else to accept it. - Get it: System Settings, then Privacy and Security, then Screen Recording. During development the grant must be re-given whenever the binary path or signature changes. - Verify: Capture returns menu bar pixels rather than a black frame - [ ] **A menu bar with at least eight items in it** · free - Why: The mechanism is invisible on a tidy bar, and the segmentation code in Phase 2 needs real variety in icon widths to be worth anything. - Get it: Install a handful of applications that add menu bar items, or borrow a colleague's cluttered machine for an hour of testing. - Verify: Your menu bar has enough items that some are pushed off on a narrow display - [ ] **Apple Developer Program membership** (optional) · 99 USD per year - Why: Product phase only. No Developer ID means no notarization, and for this category the update channel matters more than usual because macOS releases break it. - Get it: Enrol at developer.apple.com/programs. Review takes a day or two. - Verify: A Developer ID Application certificate appears in Xcode settings ## Quick start ```sh codesign --force --options runtime --sign "Developer ID Application: YOUR NAME" Bar.app xcrun notarytool submit Bar.zip --keychain-profile AC --wait ``` Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - Any guarantee across major macOS releases. This category breaks and then gets fixed, every year. - The interaction polish that commercial alternatives have accumulated. - Settings sync between machines. - Support for the cases where the underlying mechanism only half works, which is most of what you are paying for. - deep macOS menu-bar handling, OS update compatibility, and polished interaction - years of OS-version edge cases - large extension ecosystem - cross-device sync - commercial support and rapid compatibility fixes If one of those is essential to you, that is the reason to keep paying for Bartender, and the README should say so rather than pretend.
# Build brief · Bartender The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a macOS menu bar manager that hides icons behind a divider and brings them back on demand to replace Bartender. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Language: Swift 6 and SwiftUI in Xcode · NSStatusItem and the capture APIs are AppKit, and nothing else can reach them - App type: A background agent with LSUIElement true · a menu bar manager with a Dock icon is a joke at its own expense - Hiding mechanism: Your own NSStatusItem used as an expanding spacer · the only supported lever: your item grows and pushes other applications' items off the visible bar - Redraw: ScreenCaptureKit, which requires the Screen Recording permission · the hidden icons belong to other processes, so the only way to show them in your own row is to capture and redraw them - Storage: A property list in Application Support · rules and layout are small, structured and edited rarely ### Data model (create this before Phase 1) - items(id, bundle_id, title, last_seen_at, hidden, always_visible, position) · one row per menu bar item you have observed - rules(id, item_id, trigger, condition_json, action) · trigger is app_activated, time_of_day, battery_state or manual - profiles(id, name, active) · a named set of hidden and visible assignments, for example presenting versus working - settings(key, value) · hotkey, spacer width, whether the hidden row auto-collapses and after how long - Item identity is the owning bundle identifier plus a stable title where one exists, because index position changes every time any application adds or removes an item. ### Phase 1 · Agent, status item and the spacer Build: A background agent with no Dock icon and one NSStatusItem. Give that item a variable length. Growing it consumes menu bar width and displaces items to its left, which is the entire mechanism every application in this category uses. Trap: There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. Done when: Growing the status item visibly pushes at least one other application's icon off the visible menu bar, and shrinking it brings the icon back. The agent has no Dock icon and does not appear in the application switcher. The width survives a relaunch. Do not build yet: No capture, no rules, no hotkey. One item that can take up space on demand. ### Phase 2 · Seeing the bar, which means asking for Screen Recording Build: Request Screen Recording and use ScreenCaptureKit to capture the menu bar region. Identify individual items by their bounds. Render the hidden ones into your own secondary row so clicking one forwards the click to the real item underneath. Trap: Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. Trap: The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. Done when: The hidden row renders recognisable copies of the displaced icons. Clicking a copy activates the real item, verified by an item whose menu you can see open. Refusing the permission leaves the application running with hiding available and redrawing disabled, with an explanation rather than a crash. Do not build yet: No rules and no hotkey yet. ### Phase 3 · Rules and profiles Build: Rules that fire on application activation, time of day, battery state or manual invocation. Profiles as named sets of hidden and visible assignments. Identify items by bundle identifier so a rule survives an item changing position. Trap: Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. Done when: Activating a chosen application hides the icons that rule names, and switching away restores them. A rule keyed to an item still applies after other applications have launched and shifted the layout. Switching profiles changes the visible set in one action and is reversible. Do not build yet: No hotkey search yet. ### Phase 4 · Hotkey, search and keyboard control Build: A global hotkey that reveals the hidden row, plus a search field that filters items by name and activates one with Return. Arrow keys move between items. Escape collapses. Trap: Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. Done when: The hotkey reveals the hidden row from any application. Typing filters to a matching item and Return activates it. Escape collapses the row and returns focus to the application that was frontmost. No Accessibility permission is requested anywhere in the application. Do not build yet: No distribution yet. ### Phase 5 · Surviving the operating system Build: Self-diagnostics that verify the spacer still displaces items and that capture still returns pixels. On failure, show a clear banner naming the macOS version and what is not working. Record the last macOS version the build was verified against. Trap: Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. Done when: Simulating a capture failure produces a visible banner naming the macOS version, not an empty row. The application reports the last version it was verified against. A first launch on an untested major version shows a caution rather than pretending everything is fine. Do not build yet: Signing and updates come next. ### Phase 6 · Signing, notarization and updates Build: Hardened runtime, Developer ID signing, notarization, stapling, and Sparkle updates. Because this category breaks on major releases, the update channel is not optional polish, it is how the application stays usable. Trap: Your first signed release invalidates the Screen Recording grant your testers gave the unsigned build, and macOS will not re-prompt. Put the removal instructions in the release notes rather than in a support reply. Done when: A notarized build opens on a Mac that never ran it, with no Gatekeeper warning, and requests Screen Recording once. An update published to the appcast installs and relaunches. The release notes explain the permission reset. Do not build yet: Nothing after this. ### Out of scope (and why) - A supported way to hide other applications' icons. It does not exist, and everything here rests on a spacer and a screen capture. - Guaranteed compatibility with the next macOS release. This category breaks roughly annually, and the honest deliverable is a diagnostic that tells you when it has. - The years of interaction polish behind the commercial applications, which is mostly the handling of the cases where the mechanism half works. - Cross-device settings sync, which would mean accounts and a server for a preferences file. ### README must contain - That hiding uses a spacer item and there is no API for hiding another application's icon - That Screen Recording is required only for redrawing hidden icons, what it can see, and that hiding still works without it - That no Accessibility permission is requested, and why the hotkey uses the Carbon registration - The last macOS version this build was verified against, and that major releases usually break this category - That re-signing invalidates the Screen Recording grant and how to clear the stale entry
# Agent instructions · Bartender indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: Swift 6 and SwiftUI in Xcode, A background agent with LSUIElement true, Your own NSStatusItem used as an expanding spacer, ScreenCaptureKit, which requires the Screen Recording permission, A property list in Application Support. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. - Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. - The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. - Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. - Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. - Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread.
# Build plan · Bartender A background agent that collapses the menu bar down to the icons you actually watch, keeps the rest one click or one hotkey away, applies per-application and per-condition rules, and is honest in its own interface about the fact that this entire category breaks on major macOS releases. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · Agent, status item and the spacer Your own icon sits in the menu bar and can push other icons out of sight. ### Steps 1. Create the agent target SwiftUI app with Application is agent set to YES in Info.plist, and a MenuBarExtra so there is something to click before anything else works. Files: `Info.plist`, `App.swift` 2. Add a variable-length status item NSStatusItem with a length you set programmatically. Animate changes, because an instant jump reads as a glitch rather than an action. Files: `Spacer.swift` 3. Persist the state Write the current width and collapsed state to a property list in Application Support and restore it on launch. Files: `Settings.swift` ### Done when - [ ] Growing the item pushes another application's icon out of view - [ ] Shrinking it restores that icon - [ ] The agent has no Dock icon and no entry in the application switcher - [ ] Collapsed state survives quitting and relaunching ### Watch out - There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. ## Phase 2 · Seeing the bar, which means asking for Screen Recording You can enumerate and redraw the icons you have displaced, and the user understands why that needs a serious permission. ### Steps 1. Explain, then request Screen Recording Your own panel first, saying what is captured and what is not. Then CGRequestScreenCaptureAccess. A permission this broad deserves a sentence you wrote. Files: `Permissions.swift` 2. Capture the menu bar region and segment it SCStreamConfiguration limited to the menu bar strip. Segment on the gaps between items rather than assuming a fixed icon width, because widths vary. Files: `BarCapture.swift` 3. Render a secondary row and forward clicks Draw the captured icons in your own window below the bar. On click, synthesise a click at the real item's coordinates. Files: `HiddenRow.swift` 4. Degrade honestly without the permission Hiding still works, because the spacer needs no permission. Only the redraw does. Say which half is unavailable rather than disabling everything. Files: `Permissions.swift` ### Done when - [ ] The hidden row shows recognisable icons - [ ] Clicking a copy opens the real item's menu - [ ] Refusing Screen Recording leaves hiding working and says what is lost - [ ] Re-signing the app and relaunching surfaces a clear message about the stale grant ### Watch out - Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. - The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. ## Phase 3 · Rules and profiles The bar rearranges itself for the situation instead of needing you to fiddle with it. ### Steps 1. Observe application activation NSWorkspace notifications for activation and deactivation. This needs no additional permission and is the most useful trigger. Files: `Rules.swift` 2. Key rules to bundle identifiers Store the owner rather than the slot. Add a test that shuffles observed positions and asserts the same items are chosen. Files: `Items.swift` 3. Add profiles A named set with one active at a time, switchable from the menu and from a hotkey later. Files: `Profiles.swift` ### Done when - [ ] Activating an application applies its rule and deactivating reverses it - [ ] A rule still targets the right item after the layout shifts - [ ] Switching profiles changes the visible set in one action - [ ] A rule referencing an application that is not installed is ignored rather than erroring ### Watch out - Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. ## Phase 4 · Hotkey, search and keyboard control You never have to aim at a small icon with the mouse. ### Steps 1. Register the hotkey without Accessibility RegisterEventHotKey and a Carbon handler. Confirm in System Settings that your application is not listed under Accessibility. Files: `Hotkey.swift` 2. Add search over observed items Filter by application name and item title. Items you have seen before are searchable even when currently hidden. Files: `Search.swift` 3. Make the whole row keyboard navigable Arrows to move, Return to activate, Escape to dismiss and restore focus. Files: `HiddenRow.swift` ### Done when - [ ] The hotkey works while another application is frontmost - [ ] Typing filters and Return activates the right item - [ ] Escape collapses and returns focus to the previous application - [ ] The application does not appear in the Accessibility permission list ### Watch out - Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. ## Phase 5 · Surviving the operating system When a macOS release breaks the mechanism, the application says so instead of appearing broken. ### Steps 1. Write the self test Grow the spacer, capture, and assert the bar contents changed. Run it on launch and on demand from the menu. Files: `SelfTest.swift` 2. Show honest failure states A banner naming the macOS version and the specific capability that failed, with a link to your release notes. Files: `Diagnostics.swift` 3. Record the verified version Bake in the last macOS version you tested and compare at runtime. Show a caution above it rather than a hard block. Files: `Info.plist` ### Done when - [ ] A simulated capture failure produces a specific banner rather than an empty row - [ ] The verified macOS version is visible in the interface - [ ] An untested major version produces a caution on first launch - [ ] The self test can be run on demand and reports each capability separately ### Watch out - Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. ## Not in this build - Any guarantee across major macOS releases. This category breaks and then gets fixed, every year. - The interaction polish that commercial alternatives have accumulated. - Settings sync between machines. - Support for the cases where the underlying mechanism only half works, which is most of what you are paying for. ## After v1, if you want it - A presenting profile that hides everything except the clock - Per-display rules, because an external monitor changes how much bar you have - Importing an existing configuration from another menu bar manager
# Copy to .env and fill in. Never commit .env; this file documents it. # Required. Where rules, profiles and layout are stored. BAR_SETTINGS_PATH=~/Library/Application Support/Bar/settings.plist # Required. How long the revealed row stays open before collapsing. Zero disables auto-collapse. BAR_AUTOCOLLAPSE_SECONDS=8 # Required. The last macOS version this build was tested against. Shown in the interface and used for the untested-version caution. BAR_VERIFIED_MACOS=15.4 # Optional. Product phase only. Where the signed appcast is published. SPARKLE_FEED_URL=https://example.com/appcast.xml
# Bartender · product brief ## Problem The core loop is small enough for a capable coding agent to produce a useful local version in one sitting. For Bartender, hide, reveal, and arrange menu-bar items with user-defined rules. The hard boundary is deep macos menu-bar handling, os update compatibility, and polished interaction, plus os integration polish and maintenance. ## Product outcome A menu bar manager that works, asks for exactly one serious permission and explains it, degrades honestly when refused, and tells the user when a macOS release has broken the mechanism rather than looking broken itself. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - macOS 14 or later - Xcode - only the permissions required by the selected feature ## Explicit non-goals for v1 - Any guarantee across major macOS releases. This category breaks and then gets fixed, every year. - The interaction polish that commercial alternatives have accumulated. - Settings sync between machines. - Support for the cases where the underlying mechanism only half works, which is most of what you are paying for. - deep macOS menu-bar handling, OS update compatibility, and polished interaction - years of OS-version edge cases - large extension ecosystem - cross-device sync - commercial support and rapid compatibility fixes ## Success criteria - The self test passes on the newest macOS version you support - Refusing Screen Recording leaves hiding functional with a clear explanation - The application does not appear in the Accessibility permission list - spctl accepts the notarized build on a Mac that never ran it - The release notes explain the permission reset caused by signing
# Build brief · Bartender The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me a macOS menu bar manager that hides icons behind a divider and brings them back on demand to replace Bartender. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Stack (fixed, do not substitute) - Language: Swift 6 and SwiftUI in Xcode · NSStatusItem and the capture APIs are AppKit, and nothing else can reach them - App type: A background agent with LSUIElement true · a menu bar manager with a Dock icon is a joke at its own expense - Hiding mechanism: Your own NSStatusItem used as an expanding spacer · the only supported lever: your item grows and pushes other applications' items off the visible bar - Redraw: ScreenCaptureKit, which requires the Screen Recording permission · the hidden icons belong to other processes, so the only way to show them in your own row is to capture and redraw them - Storage: A property list in Application Support · rules and layout are small, structured and edited rarely ### Data model (create this before Phase 1) - items(id, bundle_id, title, last_seen_at, hidden, always_visible, position) · one row per menu bar item you have observed - rules(id, item_id, trigger, condition_json, action) · trigger is app_activated, time_of_day, battery_state or manual - profiles(id, name, active) · a named set of hidden and visible assignments, for example presenting versus working - settings(key, value) · hotkey, spacer width, whether the hidden row auto-collapses and after how long - Item identity is the owning bundle identifier plus a stable title where one exists, because index position changes every time any application adds or removes an item. ### Phase 1 · Agent, status item and the spacer Build: A background agent with no Dock icon and one NSStatusItem. Give that item a variable length. Growing it consumes menu bar width and displaces items to its left, which is the entire mechanism every application in this category uses. Trap: There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. Done when: Growing the status item visibly pushes at least one other application's icon off the visible menu bar, and shrinking it brings the icon back. The agent has no Dock icon and does not appear in the application switcher. The width survives a relaunch. Do not build yet: No capture, no rules, no hotkey. One item that can take up space on demand. ### Phase 2 · Seeing the bar, which means asking for Screen Recording Build: Request Screen Recording and use ScreenCaptureKit to capture the menu bar region. Identify individual items by their bounds. Render the hidden ones into your own secondary row so clicking one forwards the click to the real item underneath. Trap: Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. Trap: The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. Done when: The hidden row renders recognisable copies of the displaced icons. Clicking a copy activates the real item, verified by an item whose menu you can see open. Refusing the permission leaves the application running with hiding available and redrawing disabled, with an explanation rather than a crash. Do not build yet: No rules and no hotkey yet. ### Phase 3 · Rules and profiles Build: Rules that fire on application activation, time of day, battery state or manual invocation. Profiles as named sets of hidden and visible assignments. Identify items by bundle identifier so a rule survives an item changing position. Trap: Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. Done when: Activating a chosen application hides the icons that rule names, and switching away restores them. A rule keyed to an item still applies after other applications have launched and shifted the layout. Switching profiles changes the visible set in one action and is reversible. Do not build yet: No hotkey search yet. ### Phase 4 · Hotkey, search and keyboard control Build: A global hotkey that reveals the hidden row, plus a search field that filters items by name and activates one with Return. Arrow keys move between items. Escape collapses. Trap: Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. Done when: The hotkey reveals the hidden row from any application. Typing filters to a matching item and Return activates it. Escape collapses the row and returns focus to the application that was frontmost. No Accessibility permission is requested anywhere in the application. Do not build yet: No distribution yet. ### Phase 5 · Surviving the operating system Build: Self-diagnostics that verify the spacer still displaces items and that capture still returns pixels. On failure, show a clear banner naming the macOS version and what is not working. Record the last macOS version the build was verified against. Trap: Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. Done when: Simulating a capture failure produces a visible banner naming the macOS version, not an empty row. The application reports the last version it was verified against. A first launch on an untested major version shows a caution rather than pretending everything is fine. Do not build yet: Signing and updates come next. ### Phase 6 · Signing, notarization and updates Build: Hardened runtime, Developer ID signing, notarization, stapling, and Sparkle updates. Because this category breaks on major releases, the update channel is not optional polish, it is how the application stays usable. Trap: Your first signed release invalidates the Screen Recording grant your testers gave the unsigned build, and macOS will not re-prompt. Put the removal instructions in the release notes rather than in a support reply. Done when: A notarized build opens on a Mac that never ran it, with no Gatekeeper warning, and requests Screen Recording once. An update published to the appcast installs and relaunches. The release notes explain the permission reset. Do not build yet: Nothing after this. ### Out of scope (and why) - A supported way to hide other applications' icons. It does not exist, and everything here rests on a spacer and a screen capture. - Guaranteed compatibility with the next macOS release. This category breaks roughly annually, and the honest deliverable is a diagnostic that tells you when it has. - The years of interaction polish behind the commercial applications, which is mostly the handling of the cases where the mechanism half works. - Cross-device settings sync, which would mean accounts and a server for a preferences file. ### README must contain - That hiding uses a spacer item and there is no API for hiding another application's icon - That Screen Recording is required only for redrawing hidden icons, what it can see, and that hiding still works without it - That no Accessibility permission is requested, and why the hotkey uses the Carbon registration - The last macOS version this build was verified against, and that major releases usually break this category - That re-signing invalidates the Screen Recording grant and how to clear the stale entry
# Architecture · Bartender ## Stack | Part | Choice | Why | | --- | --- | --- | | Language | Swift 6 and SwiftUI in Xcode | NSStatusItem and the capture APIs are AppKit, and nothing else can reach them | | App type | A background agent with LSUIElement true | a menu bar manager with a Dock icon is a joke at its own expense | | Hiding mechanism | Your own NSStatusItem used as an expanding spacer | the only supported lever: your item grows and pushes other applications' items off the visible bar | | Redraw | ScreenCaptureKit, which requires the Screen Recording permission | the hidden icons belong to other processes, so the only way to show them in your own row is to capture and redraw them | | Storage | A property list in Application Support | rules and layout are small, structured and edited rarely | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Spacer | The status item whose width does the hiding. | Not swappable. This is the only lever the platform offers and everything else is presentation. | | Capture | Reading the bar and segmenting items. | ScreenCaptureKit is the only sanctioned path. The segmentation heuristic inside it is yours and will need revisiting after macOS releases. | | Rules | Triggers, conditions and profiles. | Pure logic over observed items, testable without a menu bar at all, and the part most likely to survive an operating system change. | | Diagnostics | Knowing whether the mechanism still works. | Never remove this. It is what separates a broken build from a broken operating system in the user's mind. | | Updates | Shipping the fix after a macOS release. | Sparkle is conventional. What matters is that the channel exists before you need it urgently. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `BAR_SETTINGS_PATH` · required · Where rules, profiles and layout are stored. - `BAR_AUTOCOLLAPSE_SECONDS` · required · How long the revealed row stays open before collapsing. Zero disables auto-collapse. - `BAR_VERIFIED_MACOS` · required · The last macOS version this build was tested against. Shown in the interface and used for the untested-version caution. - `SPARKLE_FEED_URL` · optional · Product phase only. Where the signed appcast is published. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it.
# Agent instructions · Bartender product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: Swift 6 and SwiftUI in Xcode, A background agent with LSUIElement true, Your own NSStatusItem used as an expanding spacer, ScreenCaptureKit, which requires the Screen Recording permission, A property list in Application Support. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. - Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. - The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. - Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. - Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. - Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. - Your first signed release invalidates the Screen Recording grant your testers gave the unsigned build, and macOS will not re-prompt. Put the removal instructions in the release notes rather than in a support reply.
# Delivery milestones · Bartender Estimated effort: **weekend** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · Agent, status item and the spacer Your own icon sits in the menu bar and can push other icons out of sight. ### Steps 1. Create the agent target SwiftUI app with Application is agent set to YES in Info.plist, and a MenuBarExtra so there is something to click before anything else works. Files: `Info.plist`, `App.swift` 2. Add a variable-length status item NSStatusItem with a length you set programmatically. Animate changes, because an instant jump reads as a glitch rather than an action. Files: `Spacer.swift` 3. Persist the state Write the current width and collapsed state to a property list in Application Support and restore it on launch. Files: `Settings.swift` ### Done when - [ ] Growing the item pushes another application's icon out of view - [ ] Shrinking it restores that icon - [ ] The agent has no Dock icon and no entry in the application switcher - [ ] Collapsed state survives quitting and relaunching ### Watch out - There is no public API to hide another application's menu bar item. Anyone promising one is describing the spacer trick with better marketing. Understanding that early stops you searching for an API that does not exist. ## M2 · Seeing the bar, which means asking for Screen Recording You can enumerate and redraw the icons you have displaced, and the user understands why that needs a serious permission. ### Steps 1. Explain, then request Screen Recording Your own panel first, saying what is captured and what is not. Then CGRequestScreenCaptureAccess. A permission this broad deserves a sentence you wrote. Files: `Permissions.swift` 2. Capture the menu bar region and segment it SCStreamConfiguration limited to the menu bar strip. Segment on the gaps between items rather than assuming a fixed icon width, because widths vary. Files: `BarCapture.swift` 3. Render a secondary row and forward clicks Draw the captured icons in your own window below the bar. On click, synthesise a click at the real item's coordinates. Files: `HiddenRow.swift` 4. Degrade honestly without the permission Hiding still works, because the spacer needs no permission. Only the redraw does. Say which half is unavailable rather than disabling everything. Files: `Permissions.swift` ### Done when - [ ] The hidden row shows recognisable icons - [ ] Clicking a copy opens the real item's menu - [ ] Refusing Screen Recording leaves hiding working and says what is lost - [ ] Re-signing the app and relaunching surfaces a clear message about the stale grant ### Watch out - Every menu bar manager needs Screen Recording, because redrawing an icon your process did not create means capturing pixels it did not draw. Users are right to hesitate at that prompt. Explain it in your own words before the system asks, and say plainly that you can see the whole screen and choose not to look at it. - The grant is bound to your code signature, so re-signing invalidates it and macOS will not prompt again. During development this will catch you repeatedly. ## M3 · Rules and profiles The bar rearranges itself for the situation instead of needing you to fiddle with it. ### Steps 1. Observe application activation NSWorkspace notifications for activation and deactivation. This needs no additional permission and is the most useful trigger. Files: `Rules.swift` 2. Key rules to bundle identifiers Store the owner rather than the slot. Add a test that shuffles observed positions and asserts the same items are chosen. Files: `Items.swift` 3. Add profiles A named set with one active at a time, switchable from the menu and from a hotkey later. Files: `Profiles.swift` ### Done when - [ ] Activating an application applies its rule and deactivating reverses it - [ ] A rule still targets the right item after the layout shifts - [ ] Switching profiles changes the visible set in one action - [ ] A rule referencing an application that is not installed is ignored rather than erroring ### Watch out - Menu bar items move constantly as applications launch and quit, so a rule keyed to position will act on the wrong icon within a day. Key on the owning bundle identifier and treat position as presentation only. ## M4 · Hotkey, search and keyboard control You never have to aim at a small icon with the mouse. ### Steps 1. Register the hotkey without Accessibility RegisterEventHotKey and a Carbon handler. Confirm in System Settings that your application is not listed under Accessibility. Files: `Hotkey.swift` 2. Add search over observed items Filter by application name and item title. Items you have seen before are searchable even when currently hidden. Files: `Search.swift` 3. Make the whole row keyboard navigable Arrows to move, Return to activate, Escape to dismiss and restore focus. Files: `HiddenRow.swift` ### Done when - [ ] The hotkey works while another application is frontmost - [ ] Typing filters and Return activates the right item - [ ] Escape collapses and returns focus to the previous application - [ ] The application does not appear in the Accessibility permission list ### Watch out - Register the hotkey with RegisterEventHotKey rather than a global event monitor. The monitor route needs Accessibility, which is a second serious permission on top of Screen Recording, and asking for two makes users refuse both. ## M5 · Surviving the operating system When a macOS release breaks the mechanism, the application says so instead of appearing broken. ### Steps 1. Write the self test Grow the spacer, capture, and assert the bar contents changed. Run it on launch and on demand from the menu. Files: `SelfTest.swift` 2. Show honest failure states A banner naming the macOS version and the specific capability that failed, with a link to your release notes. Files: `Diagnostics.swift` 3. Record the verified version Bake in the last macOS version you tested and compare at runtime. Show a caution above it rather than a hard block. Files: `Info.plist` ### Done when - [ ] A simulated capture failure produces a specific banner rather than an empty row - [ ] The verified macOS version is visible in the interface - [ ] An untested major version produces a caution on first launch - [ ] The self test can be run on demand and reports each capability separately ### Watch out - Menu bar management sits on undocumented behaviour, and major releases break it for everybody at once. macOS 27 betas broke essentially every application in this category, including the commercial ones. A build that fails silently looks like your bug; a build that says the operating system changed is telling the truth and saves you a support thread. ## M6 · Signing, notarization and updates (production only) Someone else can install it, and you can ship the fix the next macOS release will demand. ### Steps 1. Sign and notarize Hardened runtime, Developer ID Application, notarytool, stapler. ```sh codesign --force --options runtime --sign "Developer ID Application: YOUR NAME" Bar.app xcrun notarytool submit Bar.zip --keychain-profile AC --wait ``` 2. Ship Sparkle with a signed appcast An EdDSA key pair with the private half outside the repository, and appcast.xml served over HTTPS. Files: `appcast.xml` 3. Write the permission reset note One paragraph telling users to remove the stale Screen Recording entry after the first signed update. Files: `RELEASE_NOTES.md` ### Done when - [ ] spctl reports the notarized build accepted - [ ] A fresh Mac opens it with no Gatekeeper warning - [ ] An appcast update installs and relaunches - [ ] The release notes explain the permission reset ### Watch out - Your first signed release invalidates the Screen Recording grant your testers gave the unsigned build, and macOS will not re-prompt. Put the removal instructions in the release notes rather than in a support reply.
# Operations · Bartender ## Backup The settings property list is the whole state. It is small enough to copy anywhere and is covered by any ordinary backup of the home directory. ## Restore Quit, replace the property list, relaunch, and confirm the profile list matches. Rules referencing uninstalled applications are ignored rather than erroring, so a restore onto a different machine degrades gracefully. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Run the self test on launch and record the result. A rising failure rate across your users after a macOS release is the signal to ship, and without the self test you learn it from support threads instead. ## Incident checklist A macOS release breaking the mechanism is the expected incident, not an unlikely one. Keep the previous build downloadable, put a minimum and maximum verified macOS version in the appcast, and lead the release notes with what changed on Apple's side. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] The self test passes on the newest macOS version you support - [ ] Refusing Screen Recording leaves hiding functional with a clear explanation - [ ] The application does not appear in the Accessibility permission list - [ ] spctl accepts the notarized build on a Mac that never ran it - [ ] The release notes explain the permission reset caused by signing ## Launch constraint Do not market omitted Bartender capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered.
# Copy to .env and fill in. Never commit .env; this file documents it. # Required. Where rules, profiles and layout are stored. BAR_SETTINGS_PATH=~/Library/Application Support/Bar/settings.plist # Required. How long the revealed row stays open before collapsing. Zero disables auto-collapse. BAR_AUTOCOLLAPSE_SECONDS=8 # Required. The last macOS version this build was tested against. Shown in the interface and used for the untested-version caution. BAR_VERIFIED_MACOS=15.4 # Optional. Product phase only. Where the signed appcast is published. SPARKLE_FEED_URL=https://example.com/appcast.xml
$ choose a build depth, inspect the files, then open the complete pack in your agent
People still pay for Bartender because small utilities are technically reproducible, but customers pay for polish and immediate fixes when an OS update breaks a daily habit. The recurring cost buys permissions, accessibility APIs, sandboxing, signing, notarization, OS regressions, updates, backups, and support, not just the visible interface.
xdeep macOS menu-bar handling, OS update compatibility, and polished interaction
xyears of OS-version edge cases
xlarge extension ecosystem
xcross-device sync
xcommercial support and rapid compatibility fixes
Don't feel like building it? These folks already made it free.
no votes, no pay-to-list · just what's real
Bartender pricing
| plan | monthly | annual (per mo) | what you get |
|---|---|---|---|
| bartender 6 | custom | — | Perpetual Bartender 6 licence; includes updates within the major version. |
| bartender 6 upgrade | custom | — | Upgrade path for owners of an earlier Bartender licence. |
| bartender pro | — | $1.25 | Includes Bartender and future major-version upgrades while the subscription remains active. |
| mega supporter | custom | — | Lifetime Bartender access and upgrades. |
free tierno free tier
billingone-time purchase or annual Pro subscription; 4-week Bartender 6 trial and 7-day Pro trial
hidden costsThe perpetual Bartender 6 purchase does not include future major versions; only Pro or Mega Supporter does. Upgrade pricing varies by the existing licence, and Mega Supporter's public price is hidden in the interactive checkout.
verified 2026-08-14 · source ↗
Vibecode Bartender
Yes. A competent AI coding agent (Claude Code, Codex, Cursor) can build a usable personal Bartender replacement in one session with the prompt on this page. It runs on your own machine or server with no subscription.
How much does Bartender cost?
Bartender's pricing is usage-based or varies by plan · Sold as a one-time licence; canonical monthly amount is null..
What do I lose by replacing Bartender?
Honestly: deep macOS menu-bar handling, OS update compatibility, and polished interaction; years of OS-version edge cases; large extension ecosystem; cross-device sync; commercial support and rapid compatibility fixes. If any of those are load-bearing for you, keep paying.
Is there an open-source alternative to Bartender?
Yes: Thaw (Ice thawed: signed, actively maintained, and limited to macOS 26 or later.) SaneBar (A native menu-bar bouncer with every former Pro feature unlocked.) The prompt is for when you want it exactly your way.