hidden Documentation

An ultra-light MacOS utility that helps hide menu bar icons

15,238 stars Swift Swift 5 files Β· ~6,140 tokens #macos#swift#utilities
RAW Doc

Technical Documentation: dwarvesf/hidden

ℹ️ Provenance: Multi-Tier Ingestion Β· CodeWiki Reference

Overview (`README.md`)

Hidden Bar

Hidden Bar lets you hide menu bar items to give your Mac a cleaner look.

πŸš€ Install

ο£Ώ App Store

Others

The Hidden Bar is notarized before distributed out side App Store. It's safe to use πŸ‘

Using Homebrew

text
brew install --cask hiddenbar

Manual download

  • Download latest version
  • Open and drag the app to the Applications folder.
  • Launch Hidden and drag the icon in your menu bar (hold CMD) to the right so it is between some other icons.

πŸ•Ή Usage

  • ⌘ + drag to move the Hidden icons around in the menu bar.
  • Click the Arrow icon to hide menu bar items.

πŸ“š Documentation

  • Manual: every setting, the hidden Terminal-only options, and troubleshooting.
  • Architecture: how the hiding trick works, topology, and known limits.
  • Maintainer runbook: build, behavioral verification, and release process.

✨[Contributors](https://github.com/dwarvesf/hidden/graphs/contributors)

This project exists thanks to all the people who contribute. Thank you guys so much πŸ‘

Please read this before you make a contribution.

Requirements

macOS version >= 13.0 (Ventura)

Running an older macOS? The last release supporting macOS 10.13 High Sierra
through 12 Monterey is v1.10.
Later versions require macOS 13 because autostart moved to the SMAppService
API introduced there.

You may also like

  • Blurred - A macOS utility that helps reduce distraction by dimming your inactive noise
  • Micro Sniff - An ultra-light macOS utility that notify whenever your micro-device is being used
  • VimMotion Vim style shortcut for MacOS

License

MIT © Dwarves Foundation


ARCHITECTURE (`docs/ARCHITECTURE.md`)

Architecture

Hidden Bar is a single-process, sandboxed AppKit menubar utility (~1.5k lines of
Swift, one dependency: HotKey). There is no
helper app, no daemon, no network. Everything happens inside three
NSStatusItems and one window.

The core trick

macOS offers no API to hide other apps' menubar icons. Hidden Bar fakes it with
geometry: a separator status item whose length is inflated to roughly the
width of the widest attached screen
, shoving every icon to its left off-screen.
Collapsing and expanding is just flipping that length between ~20pt and the
inflated value.

mermaid
flowchart LR
    subgraph menubar [menu bar, right to left]
        direction RL
        ARROW["arrow item\n(toggle, variable length)"]
        SEP["separator item\n20pt expanded / ~2x screen width collapsed"]
        HIDDEN["other apps' icons\npushed off-screen when collapsed"]
        ALWAYS["always-hidden separator\n(optional)"]
    end
    ARROW --- SEP --- HIDDEN --- ALWAYS

Key consequences of this design:

  • The menubar replicates on every display, so the collapse length derives from
    the widest screen (NSScreen.screens), never NSScreen.main, and is
    re-applied to the live item on didChangeScreenParametersNotification
    (display hot-plug).
  • The length is bounded: max(500, min(widestFrameWidth * 2, 10_000)). macOS
    enforces a hard 10,000pt maximum on NSStatusItem.length.
  • isCollapsed is derived state: separator.length > 20, deliberately not an
    equality check, so it survives the length being recomputed while collapsed.
  • Icons macOS inserts to the LEFT of the separator (where new status items
    appear) are in the hidden zone by default; that is inherent to the trick.

Topology

mermaid
flowchart TD
    AD[AppDelegate] -->|owns| SBC[StatusBarController]
    AD -->|registers| SM["SMAppService.mainApp\n(login item, macOS 13+)"]
    AD -->|global hotkey| HK[HotKey lib]
    SBC -->|3 status items| NSB[NSStatusBar.system]
    SBC -->|auto-hide| T["one-shot Timer\n(re-arms while pointer in menubar)"]
    SBC -->|opt-in| HM["global mouseMoved monitor\n(hover-to-expand, only if pref on)"]
    PREFS[Preferences facade] -->|UserDefaults| UD[(UserDefaults)]
    PREFS -->|posts| NC{{NotificationCenter\n.prefsChanged / .alwayHideToggle}}
    NC --> SBC
    PVC[PreferencesViewController] --> PREFS
    SBC -->|context menu| PVC
  • AppDelegate (entry): registers default prefs, sets up the global hotkey,
    runs the one-shot legacy login-item migration, owns the StatusBarController.
  • StatusBarController (the product, ~370 lines): the three status items,
    when to collapse/expand, auto-hide timer, interaction-awareness, hover-to-expand,
    self-restore of dragged-off items.
  • MenuBarEngine (Features/StatusBar/Engine/): how hiding is achieved.
    The controller calls collapse / expand / updateAlwaysHiddenSection /
    invalidateLayout and never writes a status-item length itself.
    MenuBarEngineFactory is the one place that picks an engine for the running
    OS; today that is always LegacyLengthEngine (the length trick below).
  • Preferences (facade enum): typed accessors over UserDefaults; setters
    post NotificationCenter notifications that the controller and prefs window
    observe. There is no other state store.
  • PreferencesViewController / PreferencesWindowController: the only
    window (storyboard-based), shown on demand from the context menu.

Behavior layers on the core trick

Layer Mechanism Cost when unused
Auto-hide one-shot Timer after expand; at fire, if the pointer sits in any screen's menubar band (visibleFrame.maxY ... frame.maxY), it re-arms instead of collapsing none (single point-in-rect check at fire)
Hover-to-expand (opt-in) global .mouseMoved monitor + 0.5s dwell timer; installed only when the hoverToExpand default is true at launch zero: monitor not installed
Self-restore isVisible = true forced on our items at launch; Cmd-dragging them off otherwise bricks the app (its only UI is those items) none
Always-hidden section a second separator item; its own length games, gated by alwaysHiddenSectionEnabled item not created

Autostart

macOS 13+ SMAppService.mainApp: the app registers itself; the login item is
visible and revocable in System Settings > General > Login Items. On first
launch after upgrade, a one-shot migration deauthorizes the legacy
com.dwarvesv.LauncherApplication helper registration (the BTM database never
garbage-collects those; see Apple TN3111). The helper app itself is gone.

Security posture

Sandboxed (com.apple.security.app-sandbox), hardened runtime, no network
entitlement, no file I/O, no IPC surface, no shell or subprocess use. The only
dependency is HotKey (a small Carbon RegisterEventHotKey wrapper) locked by
the committed Package.resolved. The opt-in hover monitor observes pointer
position only and discards event payloads. About-window links are hardcoded.
A full-tree audit (2026-06) scored 9/10 with hygiene-level findings only.

Known architectural limits

  • The notch: hidden icons sit "under" the notch area on notched Macs; the
    trick cannot reveal them there. The real fix is a spillover/second-bar design
    (tracked in issues #357/#341/#148; candidate implementations in PRs #350/#358).
  • macOS 27: the menu bar re-architecture in macOS 27 betas
    (NSMenuBarNavigationSceneExtension) breaks length-inflation hiding entirely
    (issue #360). A different mechanism may be required.
  • Other apps' open menus: interaction-awareness is pointer-position-based;
    a pointer deep inside another app's open dropdown is below the menubar band,
    so the collapse can still fire there.

BACKLOG (`docs/BACKLOG.md`)

Backlog

Durable, committed index of open work. The detailed planning layer
(_meta/megagoals/issue-list-clearing/ and .claude/) is local-only and gitignored,
so this file is the version that survives a machine switch and a fresh clone. Keep it
short: one line per item, pointing at the issue, SPEC, or file that holds the detail.

Source of the current state: the v1.11 issue-clearing pass (2026-06-12), branch
fix/v1-11-batch / draft PR #365, and SPEC-003. Core-model changes (separator length
math, collapse state machine) are HIGH RISK and require a mandatory review-team pass.

macOS 27 (#360)

  • Direct build ships native hiding (NativeVisibilityEngine, Debug-Direct /
    Release-Direct configurations). Uses private MenuBarClientCore; not App Store safe.
  • App Store build still broken on 27. The sandbox denies mach-lookup com.apple.axserver, so the sections cannot be read even with Accessibility granted
    (measured 2026-09-18). Options: a user-picked list of visible apps instead of ⌘-drag
    (no Accessibility, still private API), or a public mechanism if Apple ships one.
  • Direct build bundle id. Tested as com.dwarvesv.minimalbar.direct; decide whether
    release keeps com.dwarvesv.minimalbar (shared prefs, cannot coexist with the App
    Store copy) or ships separately.
  • Tutorial text still describes the | separator; the direct build on 27 uses the
    arrow as the boundary. Needs a per-build string.
  • Adaptive-width experiment (fix/macos27-adaptive-engine, local only): calibrating
    the separator width does not hide on a 1920pt non-notched display. Kept for reference.

Blocked on external-display hardware

  • #351 external-monitor visible-bar (26.4) verification. The widest-attached-screen
    fix is code-only; the 26.4 + external-display reproduction was never run. Confirm no
    full-width bar leak on a real second monitor.

Actionable now (no special hardware)

  • UAT + merge draft PR #365. Per the local UAT.md (one row per fix, click-through
    steps). Merge order matters (stacked dependency). Merge is Han's action, not the agent's.
  • Cut the v1.11 release. Version + CHANGELOG staged in #365. Needs a Developer ID for
    notarization + App Store submission. Shipping answers the "is this still maintained?"
    issues and unblocks the round-2 close sweep.
  • Upgrade-path BTM verification before any signed release. Install a pre-v1.11 build,
    update to v1.11, confirm Login Items shows no leftover LauncherApplication row (the
    one-shot SMLoginItemSetEnabled(..., false) deauth was added but never run on hardware).
  • AXPress accessibility defect. VoiceOver users cannot toggle the bar: the arrow's
    AXPress handler reads NSApp.currentEvent, which is nil under assistive synthesis.
  • hoverToExpand Preferences checkbox. Shipped as a Terminal-only defaults write;
    add a proper checkbox in PreferencesViewController.
  • Surface the SMAppService error contract in the prefs UI. On register() failure
    (unsigned build, or user denies in System Settings), the checkbox stays on while the
    system says off; the error is swallowed into NSLog. Fix when the prefs UI is next touched.
    Common/Util.swift:29-31.
  • Round-2 issue close sweep (~35 issues). Obsolete-OS + meta/support candidates,
    deferred until v1.11 ships so the closures carry the strongest answer.
  • 24h memory dogfood (#361). Instruments stress-cycling found no leak; run v1.11 as
    the daily driver for 24h on the Air to close the open report.
  • Old branch decision. feature/menubarDetection (PR #115) and feature/ghost-mode
    (PR #57) were kept per never-delete. Review or discard, Han's call.

v1.12 standalone wins (no Option D needed)

  • #207 show clock/date when collapsed. Loudest single feature ask (18+ comments).
  • #355 prefs window layout overlap. #324 single-instance guard. #276 Cmd+W
    closes the prefs window. Appearance bundle via community PR #194.

Architectural epic (Option D, #366)

  • Managed-overflow / second-bar redesign. The real fix that gates ~30 issues across
    four clusters: icon-drift (#28, #156, #181, #230, #231, #239, #252, #254, #275, #283,
    #321, #334), always-hidden (#171, #224, #242, #288), notch (#206, #225, #228, #245,
    #267, #269, #280, #292, #330), and macOS 27 (#360). Replaces length-inflation with a
    managed overflow bar, likely via Accessibility. Needs a design decision from Han +
    macOS 27 hardware. Design + folded M1 (pin icons, persist order) / M2 (decouple
    always-hidden from areSeparatorsHidden, recover stuck items) in SPEC-003.
  • Security + behavior review of community PRs #358 and #350 first. #358 (second bar,
    +1160 lines) and #350 (notch overflow, +429 lines) are the existing starting points.
    Do not merge on description alone; #358 especially needs a real review.
  • #242 permanent icon-loss repro. Needs a throwaway defaults profile (live repro
    risks losing real menu-bar icons). Required before the always-hidden decouple lands.

MANUAL (`docs/MANUAL.md`)

Manual

Everything Hidden Bar can do, including the parts with no UI.

Basics

  • Left-click the arrow (< / >): expand or collapse the hidden section.
  • Right-click the arrow or left-click the separator (|): context menu
    (Preferences, Toggle Auto Collapse, Quit).
  • ⌘-drag icons in the menu bar to move them across the separator: icons to
    the separator's left are hidden when collapsed.
  • Option-click the arrow: show/hide the separators and the always-hidden
    area without expanding.

macOS 27, direct download build

The direct (non-App Store) build hides icons natively on macOS 27, and the
arrow itself is the boundary: there is no | separator. ⌘-drag icons to
the arrow's left to hide them when collapsed, to its right to keep them
visible. The always-hidden separator still appears (while expanded) when that
section is enabled.

  • Needs Accessibility permission (System Settings β€Ί Privacy & Security β€Ί
    Accessibility) to see where your icons are. Without it the bar stays
    expanded.
  • Hiding is per app: an app with several icons hides or shows them together.
  • macOS's own items (clock, Wi-Fi, Sound, Control Center) always stay visible.
  • Run Hidden Bar from /Applications; macOS only recognizes that copy as
    Hidden Bar, and a copy elsewhere hides its own arrow.

Preferences window

Setting What it does
Start Hidden Bar when I log in Login item via System Settings (macOS 13+ SMAppService); revocable in System Settings > General > Login Items
Show preferences on launch Open this window at app start
Auto collapse Re-hide automatically after the chosen delay
Global shortcut System-wide expand/collapse hotkey (F-keys display as F18, not Fn18)
Enable always hidden section A second zone whose icons stay hidden even when expanded; revealed by option-clicking the arrow
Use full menu bar on expanding App becomes briefly "regular" while expanded (helps on tight menubars)

Always-hidden section, current behavior: items in the always-hidden zone
are reliably pushed off-screen only when "hide separators" is also on
(option-click the arrow). With the separators visible, always-hidden items can
still appear after expanding. This coupling is a known limitation being
reworked alongside the menu-bar redesign; for now, option-click to hide the
separators if always-hidden items keep showing. Avoid placing critical icons in
the always-hidden zone until the rework lands, since a stuck off-screen item has
to be recovered by ⌘-dragging it back (macOS persists its position per app).

Behaviors you get for free

  • It won't collapse mid-use: while your pointer is anywhere in the menu bar,
    the auto-collapse countdown defers and restarts; it resumes when you leave.
  • Self-repair: if the arrow or separator was ⌘-dragged off the bar (which
    used to make the app unreachable forever), they come back on next launch.
  • Display changes: plugging in or removing monitors re-sizes the hidden zone
    for the widest attached screen automatically.

Hidden settings (Terminal)

All via defaults; quit and relaunch the app after changing them.

sh
# expand by hovering the menu bar for ~0.5s (off by default)
defaults write com.dwarvesv.minimalbar hoverToExpand -bool true

# auto-collapse delay in seconds (the UI offers a fixed list; any value works)
defaults write com.dwarvesv.minimalbar numberOfSecondForAutoHide -float 5

# force the app language regardless of system order (issue #287)
defaults write com.dwarvesv.minimalbar AppleLanguages '(en)'

To undo any of them: defaults delete com.dwarvesv.minimalbar <key>.

Troubleshooting

Symptom Fix
Icons I want visible got hidden after an update ⌘-drag them to the right of the separator
Login item missing after denying it once System Settings > General > Login Items: re-enable Hidden Bar, then toggle the pref off/on
A ghost "LauncherApplication" login item from old versions Launch the current version once; it deauthorizes the legacy item automatically
App language stuck See the AppleLanguages command above, or System Settings > General > Language & Region > Applications
Nothing hides on a macOS 27 beta Known (issue #360); the menu bar re-architecture broke the hiding mechanism, fix under investigation
A new or just-updated app's icon shows up already hidden Expected, see "Why new icons start hidden" below; ⌘-drag it to the right of the separator once

Why new icons start hidden

Hidden Bar hides icons by widening its separator so everything to the left of
it slides off-screen. macOS always inserts a brand-new menu-bar icon at the
far-left slot, which is inside that hidden zone, so a freshly launched or updated
app can appear "swallowed". This is macOS positioning behavior, not Hidden Bar
moving your icon: there is no way for one app to reposition another app's menu-bar
icon. The one-time fix is to ⌘-drag the icon to the right of the separator;
macOS remembers that placement per app. A built-in way to keep chosen icons
pinned is being explored as part of the larger menu-bar redesign.

Requirements

macOS 13 Ventura or later. Pre-Ventura (10.13 - 12.x): use
v1.10, the last release
on the old autostart mechanism.


RUNBOOK (`docs/RUNBOOK.md`)

Maintainer runbook

Build, verify, and release Hidden Bar. Assumes current Xcode on macOS 13+.

Build

sh
# CI-style build, no signing required
xcodebuild -project 'Hidden Bar.xcodeproj' -scheme 'Hidden Bar' \
  -configuration Debug CODE_SIGNING_ALLOWED=NO build

# runnable local build (uses your Apple Development identity)
xcodebuild -project 'Hidden Bar.xcodeproj' -scheme 'Hidden Bar' \
  -configuration Debug build

Both must exit 0 with no MACOSX_DEPLOYMENT_TARGET override; the floor is
13.0 in the project file. The single expected warning is the deliberately
deprecated SMLoginItemSetEnabled(false) call that cleans up legacy installs.

Behavioral verification (no test target exists; this is the methodology)

The repo has no unit-test infrastructure; behavior is verified against the real
menu bar. Two building blocks make that scriptable:

  1. Truth signal: the separator's AX size.
    osascript -e 'tell application "System Events" to tell process "Hidden Bar" to get size of menu bar item 2 of menu bar 2'
    reads ~20pt expanded vs ~2x-screen-width collapsed. Item 1 is the arrow.
  2. Real clicks, not AXPress: AXPress on the arrow is a no-op because the
    action handler reads NSApp.currentEvent (nil under assistive synthesis;
    known accessibility defect). Post real CGEvent mouse clicks at the arrow's
    AX-reported coordinates instead.

Standard checks before any release:

  • expand/collapse toggle flips the separator size both ways;
  • with numberOfSecondForAutoHide set to 3, an expanded bar survives 2x the
    window while the pointer is parked in the menubar band, collapses within the
    window once the pointer leaves, and collapses normally if the pointer never
    entered;
  • hoverToExpand off: no monitor log line, hover does nothing; on: dwell
    expands (synthesize a mouseMoved stream: cursor warping alone fires no
    events);
  • autostart pref on -> AutoStart: SMAppService.mainApp.status = 1 on stderr;
    off -> = 0 (run the binary directly to capture stderr);
  • localization tables stay parseable: plutil -lint hidden/*.lproj/*.strings.

When testing on a machine that runs Hidden Bar daily: export the prefs domain
first (defaults export com.dwarvesv.minimalbar backup.plist), quit the
installed app, test the dev build, then re-import and relaunch.

Release

  1. Verify the stack: every PR reviewed, builds green, behavioral checks above run.

  2. Bump MARKETING_VERSION (all four Hidden Bar configurations) and
    CURRENT_PROJECT_VERSION in the project file.

  3. Archive the GitHub build with the Hidden Bar scheme
    (Release-Direct), then notarize (Developer ID), staple, zip, and publish a
    GitHub release with notes listing closed issues. The Hidden Bar App Store
    scheme archives Release, the sandboxed App Store build, which cannot hide
    on macOS 27. v1.11 shipped that build to GitHub by mistake. Before zipping,
    confirm the app is unsandboxed:

    sh
    codesign -d --entitlements - 'Hidden Bar.app' | grep app-sandbox  # must print nothing
  4. App Store (separate lane, Hidden Bar App Store scheme): the MAS listing
    has lagged GitHub since v1.8 (issues #281/#202); decide deliberately whether
    a release goes there too.

  5. Homebrew cask (brew install --cask hiddenbar) follows the GitHub release
    artifact; notarization matters (issue #219).

  6. Before any public release after the SMAppService migration: one
    upgrade-path run from a launcher-era build (v1.9 or older) verifying System
    Settings shows no ghost LauncherApplication login item.

Stacked-PR hygiene

Feature stacks land as chained PRs (develop <- A <- B). Merge the base PR
first, then retarget the next PR's base to develop BEFORE merging it;
deleting a merged branch auto-closes dependents otherwise.

Issue triage map

The live clusters and their code areas are documented at the end of
ARCHITECTURE.md: notch, macOS 27
mechanism break, and pointer-vs-open-menu limits. Memory reports (#361 et al.)
have so far not reproduced as leaks (constraint-leak fix landed; leaks clean
over toggle stress); re-check with a 24h+ uptime footprint sample before
chasing further.


--- METRICS ---