Documentation

Everything SpacePill does, and what it needs from macOS.

SpacePill is a menu bar app for navigating macOS Spaces: a colour-coded pill for the Space you're on, plus hotkeys to relabel it, jump to another one, and take notes. One native executable, no dependencies, no network access.

On this page
  1. Requirements
  2. Install
  3. Switching between Spaces
  4. Permissions
  5. Setup & Preferences
  6. Hotkey reference
  7. The menu bar pill
  8. Quick Edit
  9. Quick Switch
  10. Space Notes
  11. The spacepill CLI
  12. The settings file
  13. Troubleshooting
  14. Uninstall

Requirements#

Operating systemmacOS 13 Ventura or later
ArchitectureApple silicon and Intel
PermissionsAccessibility (required for switching) · Input Monitoring (optional, for responsiveness)
System configurationmacOS "Switch to Desktop N" shortcuts, which the Setup window helps you turn on — see below
Disk footprintThe app, plus plain text files under ~/.spacepill/
NetworkNone. The app contains no networking code.

Install#

Install script (recommended)

Terminal
$ curl -fsSL https://spacepill.dev/install.sh | sh

Downloads the latest signed release, installs SpacePill.app into /Applications, launches it, and offers to put the spacepill CLI on your PATH. macOS only.

Direct download

Download SpacePill.dmg from the latest release, open it, and drag SpacePill into Applications. Releases are Developer ID signed and notarised by Apple, so they open with no warnings.

Build from source

Clone the repository and run ./bin/start.sh, which builds, bundles, signs, and launches the app. Don't run the bare swift build binary — without a bundle it has no bundle identifier, so Launch at Login and the permission grants won't behave like the real app. See CONTRIBUTING for the details.

First launch

SpacePill has no Dock icon and no main window — it is a menu bar item only. On first launch it opens a short Setup window that walks you through the permissions and shortcuts below. If the pill shows ?, switch Spaces once so it can read the current one. Only one instance runs at a time; a second launch detects the first and exits.

Switching between Spaces#

macOS exposes no API for activating a Space, so the only way any app can move you to a Desktop is to press the keys you would press yourself. SpacePill replays your own Switch to Desktop N keyboard shortcuts. These live under System Settings → Keyboard → Keyboard Shortcuts → Mission Control, one checkbox per Desktop — and Apple ships them turned off. SpacePill's Setup window checks whether they are on and, if any are off, sends you straight to the right pane.

The Mission Control section of macOS Keyboard Shortcuts, with Move left/right a space and Switch to Desktop 1 through 5 all ticked, bound to Control plus the desktop number
One checkbox per Desktop: tick "Switch to Desktop N" for every Space you want to jump to.

To do it by hand: open Keyboard Shortcuts, select Mission Control, and tick Switch to Desktop 1, Switch to Desktop 2, and so on. SpacePill re-reads this configuration every time you open Quick Switch or Preferences, so changes take effect immediately, with no relaunch.

The default binding is ⌃ plus the Desktop number (⌃1, ⌃2, …), but you can bind anything you like — SpacePill reads whatever you actually configured and replays that, so rebinding is safe.

Checking what macOS thinks is enabled

The bindings live in the com.apple.symbolichotkeys preference domain. To inspect Desktop 1 (ID 118):

Terminal
# 118..127 = "Switch to Desktop 1..10"
$ /usr/libexec/PlistBuddy -c "Print :AppleSymbolicHotKeys:118" \
    ~/Library/Preferences/com.apple.symbolichotkeys.plist

An absent entry means the factory default, which for these IDs is off. Writing this domain with defaults write does not take effect until the WindowServer re-reads it at login — enable the shortcuts through the System Settings UI, which registers them live.

Permissions#

SpacePill asks for two grants, both under System Settings → Privacy & Security. They do different jobs, and failing to grant them fails differently.

Permission What it's for Without it
Accessibility Posting the synthetic keystrokes that change Spaces. Switching has no API, so SpacePill sends the same key presses you would make yourself. Quick Switch cannot change Spaces. The bar still opens and lists your Spaces; pressing ⏎ just does nothing.
Input Monitoring A keyboard event tap that notices ⌃←/⌃→ so the pill can update at the start of the native transition animation instead of after it. Everything still works. The pill simply lags roughly a second behind arrow-key switches instead of moving instantly.

Input Monitoring is the scarier-sounding of the two, and it is genuinely optional: it exists only to make the indicator feel immediate. If you'd rather not grant it, don't — SpacePill also polls and listens for the system's active-space notification, so the pill stays correct either way.

SpacePill also uses private SkyLight/CoreGraphics APIs to read Space IDs and detect transitions. That is a read-only observation of your window server state; nothing is transmitted anywhere.

Setup & Preferences#

Start with the Setup window. On first launch SpacePill opens a Setup window that checks everything on this page at once — both permissions, whether your "Switch to Desktop" shortcuts are enabled, and whether Quick Switch and Space Notes are on — with a button through to each System Settings pane. It re-checks whenever you return to it, so you can fix something and watch it turn green. Reopen it any time by right-clicking the pill → Setup…

Open Preferences by right-clicking the pill and choosing Preferences…

The SpacePill Preferences window: three recordable hotkey fields for Quick Edit, Quick Switch, and Space Notes, plus toggles for Launch at Login, Enable Quick Switch Bar, Enable Space Notes, Match Space Color for Notes Border, a Max Notes Height slider at 300px, and a Reset All Space Labels and Colors button
Preferences: hotkeys on top, feature toggles below.
SettingDefaultEffect
Launch at LoginOffRegisters SpacePill as a login item.
Enable Quick Switch BarOffRegisters the Quick Switch hotkey and prompts for Accessibility if needed.
Enable Space NotesOffRegisters the Notes hotkey and allows the floating notes panel to appear.
Match Space Color for Notes BorderOnDraws the notes panel border in the current Space's colour.
Max Notes Height300 pxCeiling for the auto-sizing notes panel, adjustable from 100 to 800 px.
HotkeysSee belowEach of the three hotkeys can be re-recorded. The Quick Switch and Notes rows only appear once those features are enabled.
Reset All Space Labels & Colors—Clears every per-Space label and colour. Notes are not touched.

Hotkey reference#

Global hotkeys. All three are rebindable in Preferences.
Action Default Availability
Quick Edit Space ⌘ ⇧ S Always registered
Quick Switch Bar ⌘ ⇧ J Only when Quick Switch is enabled
Space Notes ⌘ ⇧ N Only when Space Notes is enabled
Mouse and in-panel keys.
WhereInputDoes
Menu bar pillLeft clickOpens Quick Edit
Menu bar pillRight clickContext menu: Setup…, Preferences…, Quit
Quick Switch Bar↑ ↓Move the selection
Quick Switch Bar⏎Switch to the selected Space
Quick Switch BarescClose without switching
Quick Edit⏎Save label and colour
Quick Edit⌫Clear this Space's label and colour
Space Notes⌘ ⇧ NToggle the panel for this Space

Rebinding

In Preferences, click a hotkey field and press the combination you want. SpacePill registers global hotkeys through the system, so a combination already claimed by macOS or another app will not register — if a new binding does nothing, try a different one. Bindings are stored in ~/.spacepill/settings.json.

The menu bar pill#

The pill is a capsule showing two things: a circular badge with the Space's 1-based index across all displays, and the Space's label in uppercase. Its fill is the colour you assigned; the badge is a darker shade of it.

The SpacePill menu bar pill: a red capsule labelled CODE with the number 3 in a dark circular badge
Space 3, labelled Code, coloured red.

A Space you have never configured shows a neutral translucent pill with just the number. If SpacePill cannot determine the current Space at all, the pill shows ? — switch Spaces once and it will pick it up.

Detection combines three sources: the system's active-space notification, a two-second poll, and (with Input Monitoring granted) a keyboard event tap that makes an optimistic guess the moment you press ⌃←/⌃→, so the pill turns over at the start of the animation rather than the end. If the guess turns out wrong, it reverts within a couple of seconds.

The index is positional: it renumbers whenever Spaces are added, removed, or reordered in Mission Control. Labels and colours are keyed by the Space's stable UUID instead, so they follow the Space rather than the slot.

Quick Edit — label and colour a Space#

Press ⌘ ⇧ S (or left-click the pill) to open a small popover for the Space you are currently on.

  • Label — free text, shown uppercased in the pill and searchable from Quick Switch.
  • Colour — preset swatches plus the system colour picker for anything else.
  • Save (⏎) writes the label and colour against this Space's UUID.
  • Clear (⌫) removes the configuration, returning the pill to its neutral state.

When you open Quick Edit on an unconfigured Space, SpacePill pre-selects the first preset colour no other Space is using, so a run of new Spaces ends up visually distinct without you choosing anything.

Quick Switch — jump to a Space by name#

Press ⌘ ⇧ J to open a search bar listing every Space across every display, each with its number badge and colour.

  • Fuzzy-match a label: the matcher is subsequence-based, so dcs finds Docs and eml finds Email. It is case- and accent-insensitive, and ranks the closest match first.
  • Type a number to jump straight to that Space's index.
  • ↑ ↓ to move, ⏎ to switch, esc to dismiss.

Greyed-out rows

Before showing the list, SpacePill re-reads your System Settings shortcut configuration and works out which Spaces it can actually reach. Rows it cannot reach are dimmed, marked with a "no entry" symbol, and refuse to activate. The footer explains the specific reason for whichever row is selected.

The Quick Switch panel with Space 7 selected but greyed out and marked with a no-entry symbol; the footer reads: Enable 'Switch to Desktop 7' in Keyboard Shortcuts to jump here
An unreachable Space refuses loudly — the footer names the exact fix.
Footer messageFix
"Enable Switch to Desktop N in Keyboard Shortcuts to jump here" Tick that Desktop's checkbox — see Switching between Spaces.
"Can't jump here — macOS has no shortcut past Desktop 10" Nothing to fix; macOS defines no such shortcut. Reduce your Space count, or reorder so the ones you jump to sit in the first ten.

This deliberately fails loudly. A jump that silently does nothing is indistinguishable from a bug, so SpacePill would rather tell you it is refusing.

Space Notes#

Press ⌘ ⇧ N to open a floating scratchpad anchored under the pill. Each Space has its own note, and the panel swaps content the instant you change Space.

  • Markdown highlighting for headings, bold, italics, inline code, fenced code blocks, and list markers.
  • Auto-continued lists: press ⏎ on a -, *, + or numbered list item and the next line starts with the same marker at the same indent.
  • Saves as you type — there is no save button and no unsaved state.
  • Remembers scroll position per Space, so returning puts you back where you were.
  • Auto-sizing panel that grows with the content up to the Max Notes Height set in Preferences.
  • Per-Space open state: leave the panel open on a Space and it reappears when you come back, staying hidden on Spaces where you closed it.
  • The border can take the Space's colour, so you always know whose notes you're looking at.

Notes are plain Markdown files on disk:

Path
~/.spacepill/space_<index>/notes.md

The spacepill CLI#

spacepill is a companion command line tool that lets scripts do from a terminal what the hotkeys do from the keyboard. It ships inside the app bundle and talks to the running app over a local Unix socket — it holds no state of its own, so the app must be running (commands exit with code 3 otherwise). The installer offers to put it on your PATH; you can also run spacepill install-cli at any time to symlink it into /usr/local/bin.

Terminal
$ spacepill list
  1  ● Inbox
  2  ● Email
  3  ● Code      ← current
  4  ● Docs

$ spacepill jump docs
Switched to Space 4 · Docs

$ spacepill notes --set <<< "- [ ] review the release PR"

Commands

CommandDoes
current [--json]Show the Space you are on
list [--json]List every Space with its number, label, and colour
jump <number|label>Jump to a Space by number or fuzzy label (aliases: switch, j)
label <text> [--space N] [--color <hex>]Label (and optionally colour) the current or given Space
label --clear [--space N]Remove a label and colour
notes [--space N]Print a Space's notes
notes --set [--space N]Replace notes with stdin (or a quoted argument)
notes --edit [--space N]Edit notes in $EDITOR
notes --path [--space N]Print where the notes file lives
doctorCheck permissions and shortcuts — run this first when switching doesn't work
update [--check]Update SpacePill from the latest verified release
versionPrint the version
install-cliSymlink the CLI into /usr/local/bin
helpFull usage, straight from your installed version

Omitting --space always means the Space you are on right now, and --json prints the raw response object for scripting. Jumping is subject to exactly the same constraints as the in-app Quick Switch: the corresponding "Switch to Desktop N" shortcut must be enabled, and Desktops past the tenth cannot be reached — see Switching between Spaces.

Exit codes

CodeMeaning
0Success
1Error
2Bad usage
3SpacePill.app is not running
4That Space cannot be switched to
5No such Space

Updating

spacepill update compares your installed version against the latest GitHub release and installs it only after verifying the download's code signature — an unverifiable build is refused rather than installed. spacepill update --check reports what's available without changing anything.

The settings file#

Everything SpacePill persists lives in one directory:

~/.spacepill/
~/.spacepill/settings.json          # hotkeys, toggles, per-Space label + colour
~/.spacepill/space_1/notes.md       # notes for the Space at index 1
~/.spacepill/space_2/notes.md
~/.spacepill/space_<N>/notes.md
~/.spacepill/spacepill.sock         # CLI socket, only while the app runs

settings.json is written by the app whenever anything changes. You can read it freely; if you edit it by hand, quit SpacePill first, or your changes will be overwritten on the next save.

~/.spacepill/settings.json
{
  "isQuickSwitchEnabled": true,
  "isNotesEnabled": true,
  "matchSpaceColorForNotesBorder": true,
  "maxNotesHeight": 300,
  "quickEditHotKey":   { "keyCode": 1,  "modifiers": 768 },
  "quickSwitchHotKey": { "keyCode": 38, "modifiers": 768 },
  "notesHotKey":       { "keyCode": 45, "modifiers": 768 },
  "spaceConfigs": {
    "1A2B3C4D-5E6F-7081-9A0B-C1D2E3F40506": {
      "label": "Agents",
      "hexColor": "FF007AFF",
      "isNotesOpen": true,
      "scrollPosition": 0
    }
  }
}

Fields

isQuickSwitchEnabled bool, default false
Whether the Quick Switch Bar and its hotkey are active.
isNotesEnabled bool, default false
Whether Space Notes and its hotkey are active.
matchSpaceColorForNotesBorder bool, default true
Draw the notes panel border in the current Space's colour rather than a neutral hairline.
maxNotesHeight number, default 300
Maximum height of the notes panel in points. The Preferences slider ranges from 100 to 800 in steps of 50.
quickEditHotKey / quickSwitchHotKey / notesHotKey
Each is { "keyCode": <virtual key code>, "modifiers": <Carbon modifier mask> }. The masks are 256 Command, 512 Shift, 2048 Option, 4096 Control, summed — so 768 is Command + Shift. Key codes are the usual macOS virtual key codes: 1 = S, 38 = J, 45 = N. Recording a hotkey in Preferences is much easier than editing this by hand.
spaceConfigs
A map from a Space's UUID to its configuration. Keying by UUID is what makes labels and colours survive reordering Spaces in Mission Control.
spaceConfigs[uuid].label string, optional
The name shown in the pill (uppercased) and matched by Quick Switch.
spaceConfigs[uuid].hexColor string, optional
Written as 8 hex digits in AARRGGBB order — FF007AFF is opaque system blue. Plain RGB and RRGGBB values are also accepted when reading.
spaceConfigs[uuid].isNotesOpen bool, optional
Whether the notes panel should reappear when you return to this Space.
spaceConfigs[uuid].scrollPosition number, optional
Saved vertical scroll offset of the notes panel for this Space.

Deleting settings.json and relaunching resets SpacePill to defaults — which also turns Quick Switch and Space Notes back off. Notes files are not touched by that.

Troubleshooting#

Quick Switch opens but pressing Return doesn't move me

This is almost always one of three things, in order of likelihood:

  1. The "Switch to Desktop N" shortcuts are not enabled. They are off on every fresh macOS install. Enable them → If the row you selected is greyed out, this is definitely it.
  2. Accessibility permission is missing. Check System Settings → Privacy & Security → Accessibility and make sure SpacePill is listed and ticked.
  3. The target Space is past Desktop 10. macOS defines no shortcut for it, so it can never be jumped to.

spacepill doctor checks all three at once from the terminal.

Some Spaces are greyed out in the list

Deliberate. Either that Desktop has no shortcut enabled, or it sits past Desktop 10. Select the row and read the footer hint — it names the specific reason.

⌘ ⇧ J or ⌘ ⇧ N does nothing

Those hotkeys are not registered until the corresponding feature is switched on. Right-click the pill → Preferences → tick Enable Quick Switch Bar and/or Enable Space Notes.

If a feature is enabled and the hotkey still does nothing, the combination may be claimed by macOS or another app — global hotkey registration fails when something else already owns it. Record a different one in Preferences.

Hotkeys worked, then stopped after an update

Permissions are bound to the app's code signature, and a new build can read as a new app. Reset and re-grant:

Terminal
$ tccutil reset Accessibility com.jake.SpacePill
$ tccutil reset ListenEvent   com.jake.SpacePill

Then relaunch SpacePill and approve the prompts.

The pill shows ?

SpacePill has not identified the current Space yet. Switch Spaces once. If it stays as ?, the private APIs it reads may have changed in your macOS version — please open an issue with your macOS version.

The pill lags about a second behind ⌃←/⌃→

The keyboard event tap could not be created, which normally means Input Monitoring has not been granted. Everything still works — the pill just updates after the transition instead of during it. Grant Input Monitoring to get the snappy behaviour back. In the log you will see:

Log
[com.jake.SpacePill:spaces] Failed to create space switch event tap

My notes turned up on the wrong Space

Note files are named by positional index, so adding, deleting, or reordering Spaces can shift them. Quit SpacePill and rename the ~/.spacepill/space_<index> directories to match the new numbering. See Space Notes.

Reading the log

SpacePill logs to the unified system log under its bundle identifier:

Terminal
# live
$ log stream --predicate 'subsystem == "com.jake.SpacePill"'

# the last five minutes
$ log show --predicate 'subsystem == "com.jake.SpacePill"' --last 5m

Categories are app, spaces, hotkeys, ui, settings, and notes. Space labels and note text are deliberately redacted as <private>.

Starting over

Quit SpacePill, delete ~/.spacepill/settings.json, and relaunch. That restores every default, including turning Quick Switch and Space Notes back off.

Uninstall#

Terminal
# 1. Quit SpacePill from the pill's right-click menu, then:
$ rm -rf /Applications/SpacePill.app

# 2. The CLI symlink, if you installed it:
$ rm -f /usr/local/bin/spacepill

# 3. Settings and notes (this deletes your notes — back them up first):
$ rm -rf ~/.spacepill

# 4. Revoke the permission grants:
$ tccutil reset Accessibility com.jake.SpacePill
$ tccutil reset ListenEvent   com.jake.SpacePill

If you enabled Launch at Login, removing the app clears the login item; you can confirm under System Settings → General → Login Items & Extensions.

The "Switch to Desktop" shortcuts you enabled are a macOS setting, not a SpacePill one. They stay on unless you untick them yourself — which is usually what you want.