Skip to content

Omarchy-style AeroSpace tiling on Ctrl - #6

Open
fmontes wants to merge 23 commits into
mainfrom
aerospace-desktop-layout
Open

fmontes wants to merge 23 commits into
mainfrom
aerospace-desktop-layout

Conversation

@fmontes

@fmontes fmontes commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Rebuilds the desktop from a fixed one-app-per-workspace track into an Omarchy/Hyprland-style tiling setup, and moves window management onto Ctrl.

main currently has no aerospace.toml at all, so this is the whole config.

Tiling

Workspaces are generic contexts, not app slots. Nothing is assigned anywhere — an app opens on whichever workspace has focus and tiles into it. Three things had to go for that to work:

  • accordion + accordion-padding = 0, which made a second window cover the first at full size — the reason everything looked fullscreen.
  • All seven app→workspace routing rules.
  • The if = 'true' catch-all that exiled unmatched windows to slot 0, which was what stopped a new window ever joining the workspace you were on.

persistent-workspaces is also gone, so a workspace exists only while it holds a window. Ctrl+5 creates workspace 5 on demand and it disappears when you close its last window — which is what makes the cycling keys visit only occupied workspaces.

Six rules remain, all for windows that need behaviour they cannot get alone: Slack and MacWhisper forced back into tiling (macOS reports their windows as panels), and System Settings, 1Password, Cap and krisp floating. Finder, Notes and Messages no longer float — they are windows you work in.

Keys

Ctrl for navigation, Ctrl+Shift for manipulation:

Keys Action
Ctrl + arrows Focus
Ctrl+Shift + arrows Move window
Ctrl + 19 Switch workspace
Ctrl+Shift + 19 Send window to workspace
Ctrl+Shift + [ ] Prev / next occupied workspace
Ctrl+Shift + , . Send window to prev / next workspace
Ctrl+Shift + F T J / \ Fullscreen, float, split orientation, accordion, flatten
Ctrl+Shift + - = Resize

No plain Ctrl+letter is bound anywhere, so ^A ^C ^D ^R ^W keep working. Plain Ctrl is confined to arrows and digits, neither of which carries a control character. Option+←/→ word navigation and all Cmd shortcuts are untouched.

This modifier took three attempts. Plain Option ate Option+arrow word navigation. Caps Lock via Raycast's Hyper Key was worse: Raycast's Hyper is fixed at ctrl+alt+shift+cmd, consuming all four modifiers AeroSpace supports, so Caps+Shift was byte-identical to Caps — no second chord level existed, and moving a window had to become a toggled mode with no visual indicator. Ctrl has neither problem.

The macOS shortcuts this needs off

scripts/06-macos.sh now disables ten Mission Control symbolic hotkeys. Without this the bindings silently do nothing on a fresh machine, because system shortcuts win over app-registered hotkeys.

Ids 80 and 82 are the trap: System Settings shows one checkbox per "Move left/right a space" row, but macOS registers two hotkeys behind it — Ctrl+arrow and Ctrl+Shift+arrow — and the Shift variants have no UI control anywhere. They survive turning the visible ones off.

Idempotent, and applied with activateSettings so no logout is needed.

Also

  • restore-layout — resets apps onto workspaces 1–5, opening what is missing and moving what has drifted. Personal to one machine (it hardcodes Chrome profile directories).
  • aerospace-track deleted. Its TRACK/LABELS arrays encoded the slot model, and AeroSpace's own workspace --wrap-around next|prev covers the navigation now that empty workspaces do not exist. spaces becomes a plain list-windows alias with nothing to keep in sync.
  • No focus indicator. on-focus-changed moving the cursor to each focused window was tried and removed — it fires on every focus change, so a transient window that appears and vanishes drags the cursor away and abandons it.

Still manual on a new machine

AeroSpace needs Accessibility permission granted by hand, as do the other apps that require it. restore-layout's Chrome profile directories (Profile 1 = work, Default = personal) are assigned in signup order and may differ.

🤖 Generated with Claude Code

fmontes and others added 2 commits August 12, 2026 19:08
Pins every app to a fixed workspace slot across two horizontal tracks,
so closing and reopening an app never shifts anything else:

  Work      1 Chrome  2 Orca  3 Slack  4 Calendar  5 Warp  6 VS Code
  Personal  7 Chrome Canary   8 cmux   9 VS Code Insiders
  Overflow  0 anything not in the layout

persistent-workspaces keeps empty slots alive, so slot 4 stays slot 4
whether Calendar is running or not. on-window-detected routes each app
back to its own slot on launch.

AeroSpace matches windows by bundle ID, so the two tracks use distinct
apps rather than distinct profiles — Chrome/Chrome Canary and VS Code/
Insiders. Chrome profiles could not work here: a Chrome window title
carries no profile information, so the two profiles are indistinguishable.
The rules use '=' (exact) rather than '~=' (substring) so that
com.google.Chrome does not capture com.google.Chrome.canary.

aerospace-track adds the spatial navigation AeroSpace has no concept of:
alt-a/alt-d step within a track and clamp at its edges, alt-w/alt-s swap
tracks and resume each one's last slot. Per-track memory is recorded from
exec-on-workspace-change into ~/.local/state/aerospace/. Written for bash
3.2, since that is what macOS ships.

Accordion layout with zero padding keeps one app per screen instead of
tiling, and every slot is pinned to the main display so the layout is
identical on the laptop screen and on an external monitor.

Orca has no Homebrew cask (the 'orca' cask is Plotly's unrelated tool),
so it stays a manual step alongside granting Accessibility access.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…file

Replaces the two-track Work/Personal model with one linear track of slots:

  1 Desktop  2 Calendar  3 Slack  4 Orca  5 Chrome Work  6 Chrome Me
  7 Warp     8 VS Code   0 Overflow

Slot 1 is deliberately empty, and login lands there.

Chrome now splits by profile rather than by app. Chrome appends the signed-in
account name to every window title once more than one profile is running, so
the title is a usable discriminator where the bundle ID is not:

  test %{app-bundle-id} = com.google.Chrome && test %{window-title} ~= "..."

That supersedes the earlier claim that Chrome window titles carry no profile
information, which was wrong. It also removes the reason for running a second
browser and a second editor, so Chrome Canary, cmux and VS Code Insiders are
uninstalled and dropped from the Brewfile.

The patterns must be anchored: bare 'Freddy' is a prefix of 'Freddy
(dotcms.com)' and matches both profiles. A third rule matching the bundle ID
alone catches the single-profile case, where Chrome drops the suffix, so an
unlabelled window lands on Work instead of falling through to overflow.

With one track there is nothing to move up and down between, so ctrl-w and
ctrl-s are unbound (returning both to the shell) and the per-track memory is
gone entirely — no record subcommand, no exec-on-workspace-change hook, no
state under ~/.local/state. ctrl-a and ctrl-d now loop around the ends of the
single track rather than clamping at its edges.

Adds `aerospace-track overview`, aliased to `spaces`, because AeroSpace has no
overview GUI: its tray icon shows only the active workspace, and it parks
inactive windows off-screen rather than using native macOS Spaces, so Mission
Control cannot stand in either. The focused slot is marked with brackets as
well as colour so the output survives being piped.

Adds alt-/ to split the current slot side by side and back, for the occasional
two-window comparison. It affects only the focused slot; everywhere else stays
stacked, since the point of the layout is one app per screen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@fmontes fmontes changed the title Add AeroSpace desktop layout with two-track WASD navigation Add AeroSpace desktop layout with fixed app slots Aug 13, 2026
fmontes and others added 19 commits August 13, 2026 07:28
Three slots were empty at once (the desktop, Warp, VS Code) and all three
looked identical: a bare screen. Landing on one gave no clue where you were,
so reaching Calendar took one keypress from the desktop but three from Warp's
empty slot.

ctrl-a / ctrl-d now skip slots with no windows. Slot 1 is exempt, being the
intentional desktop, so there is exactly one blank screen you can land on and
it is always the same one. The trade-off is that the number of presses between
two apps changes as apps open and close; the slots themselves never move, and
alt-N still jumps straight to one.

Warp leaves the layout and VS Code takes slot 7. Warp has no rule now, so the
catch-all sends it to overflow along with anything else unlisted.

  1 Desktop  2 Calendar  3 Slack  4 Orca  5 Chrome Work  6 Chrome Me
  7 VS Code  0 Overflow

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
macOS reports the huddle as a utility panel, so AeroSpace floats it and it
covers whatever slot you are looking at. A rule matching "^Huddle:" in the
window title forces it back into tiling and switches slot 3 to horizontal
tiles, so the huddle and the channel sit side by side.

The rule has to precede the general Slack rule, since first match wins, and
the title anchor keeps it from catching the main window.

Slot 3 stays h_tiles once the huddle ends. That is invisible with a single
window, which fills the screen under either layout; alt-/ switches it back.

Also documents `aerospace run-callback`, which re-applies routing rules to
windows that are already open. That is both the way to test a rule against a
live window and a replacement for restarting AeroSpace after a config change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three AeroSpace features the setup was not using:

alt-shift-e disables window management. Key events stop being intercepted,
which is the only way to hand ctrl-a and ctrl-d back to the terminal short of
quitting, and hidden workspaces return to the screen — useful when screen
sharing. It is one-way: while disabled the server rejects every command except
`aerospace enable on`, so the key cannot undo itself. Verified that all
windows return to their original slots when re-enabled.

alt-1 through alt-7 gain --auto-back-and-forth, so pressing the key for the
slot you are already on returns you to the previous one. Every jump key
becomes a toggle at no cost.

alt-tab moves from workspace-level to window-level back-and-forth, chained as
`focus-back-and-forth || workspace-back-and-forth` because the former exits
non-zero once the previous window is gone. This matters when a slot holds two
windows, such as Slack during a huddle.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The "^Huddle:" rule never fired. Slack sets that title a moment after the
window appears, so at on-window-detected time the title is something else and
the pattern cannot match. Re-running the callback later worked, which made the
rule look correct while it did nothing in practice.

Confirmed it was a detection-time miss rather than AeroSpace re-floating the
window afterwards: once tiled, the huddle stayed tiled across repeated checks,
so nothing was undoing the rule.

Tiling every Slack window removes the race — there is no title to wait for.
The huddle is effectively the only second window Slack opens, and a popped-out
thread tiling alongside is no loss.

Verified from the exact failing state: slot stacked, huddle floating, rule
fired against the huddle window alone — both windows end up h_tiles side by
side.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Routing runs only when a window is first detected, so a window that ends up in
the wrong slot stays there. An accidental alt-shift-N, a window dragged across,
or an app opened before its rule existed all leave a window stranded with
nothing to correct it.

alt-shift-r re-applies every rule to every open window. Verified by moving the
main Slack window into slot 2 and pressing it: the window returns to slot 3 and
tiles beside the huddle again.

This came out of a report that the huddle rule had failed. It had not — the
huddle tiled correctly in slot 3, but the main Slack window had drifted to slot
2, so there was nothing in slot 3 to sit beside.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
zsh already routes scp through _remote_files, which reads remote-access
with `zstyle -T` — true when unset. So this is on by default and the line
changes nothing today; it is here to document that the behaviour is wanted
and to survive a framework or plugin that sets the style to false.

What actually gates remote completion is non-interactive key auth:
_remote_files shells out to ssh with BatchMode=yes, so a host that prompts
fails silently mid-Tab. The ~/.ssh/config side (key in the agent, plus the
`Host *` ControlMaster block that keeps each Tab near 0.1s instead of a
fresh handshake) is machine-local and stays out of the repo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
These four fell through to the catch-all rule and were dragged to slot 0,
which is wrong for transient controls: Cap's recording overlay and krisp's
mic widget would jump workspaces mid-recording. Floating leaves them on the
slot they open on without letting them claim one.

Messages needs com.apple.MobileSMS rather than com.apple.Messages, so that
rule carries a note — the wrong ID silently never matches.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The plural path has never existed, so nothing was ever auto-trusted and any
clone carrying an [env] block failed to load until it got a manual
`mise trust`. Tool-only configs load untrusted, which is why this went
unnoticed for so long — only configs with env, tasks or hooks demand trust.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`try init` defines a shell function named `try`, which then shadows the
binary. On the next `source ~/.zshrc` the line called that function, so
`init` reached try.rb as a search query and the interactive selector opened
instead of any shell code being printed. `command -v` was no guard: it
matches the function too.

`whence -p` looks only at $PATH and `command try` skips the function, so
both halves now name the binary and the line is idempotent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`brew bundle` exits non-zero if any single entry fails, and install.sh runs
under `set -e`, so one bad cask killed the bootstrap at step 02 — symlinks,
oh-my-zsh, mise, the macOS defaults and post-install never ran. A cask fails
this way whenever its app was installed by hand, since Homebrew will not
overwrite an app it does not track.

Report the unmet entries and continue instead, naming `--adopt` as the fix
for that case. Also default DOTFILES_DIR so the script works run directly
and not only through install.sh, which is what exports it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Added by the Railway CLI installer; committing it so the block survives a
fresh bootstrap rather than being re-appended per machine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The desktop was built as a fixed track: one app per workspace, accordion
layout with zero padding so a second window covered the first at full size.
That is the opposite of a tiling workflow, and the routing rules enforced it
on every window.

Rebuild it around Omarchy/Hyprland's model so the muscle memory transfers.

Tiling:
  - 'tiles' root layout with 'auto' orientation, replacing accordion. Wide
    containers split side by side, tall ones stack.
  - accordion-padding 0 -> 30, since accordion is now the opt-in stack on
    alt-/ rather than a disguise for fullscreen.
  - 6px gaps, uniform inside and out.

Workspaces:
  - Drop all seven app-to-workspace rules. Nothing is assigned anywhere; a
    window opens on the focused workspace and tiles into it.
  - Drop the 'if = true' catch-all that exiled unmatched windows to slot 0.
    It was what stopped a new window ever joining the workspace you were on.
  - Drop persistent-workspaces, so a workspace exists only while it holds a
    window. alt-N creates one on demand, and ctrl-a/ctrl-d visit only
    occupied ones.

Keys, mirroring Omarchy with alt as Super:
  - alt+arrows focus, alt+shift+arrows move, alt+-/= resize.
  - alt+1..9 / alt+shift+1..9 for workspaces, extended from 1..7.
  - alt+f fullscreen, alt+t float toggle, alt+j split orientation.
  - alt+tab is now plain workspace-back-and-forth.
  - Costs Option+arrow word navigation, traded for arrows matching Hyprland.

Rules kept only where a window needs behaviour it cannot get alone: Slack,
whose huddle macOS mislabels as a panel, and four utilities that float.
Finder, Notes and Messages no longer float -- they are windows you work in.

Focus indicator: AeroSpace draws no borders, so on-focus-changed moves the
cursor to the focused window. JankyBorders was considered and skipped; it
leans on private APIs that major macOS releases break.

Scripts:
  - Delete aerospace-track. Its TRACK/LABELS arrays encoded the slot model,
    and AeroSpace's own 'workspace --wrap-around next|prev' covers the
    navigation now that empty workspaces do not exist. 'spaces' becomes a
    plain list-windows alias with nothing to keep in sync.
  - Rewrite restore-layout as a reset rather than a router. It moves drifted
    windows to their workspace, launches missing apps there, and flattens
    what it touched, so the end state depends only on its plan and not on how
    far things had drifted.
macOS does not report MacWhisper's window as an ordinary resizable one, so
AeroSpace auto-floated it and it hovered over a workspace rather than sharing
it -- most visibly next to Chrome. It tiles perfectly well when told to, so
give it the same `layout tiling` override Slack's huddle window already uses.
Give each modifier one job: Caps for the window manager, Option for text
navigation, Ctrl for the terminal, Cmd for app shortcuts. Previously every
binding sat on plain Option, which cost Option+arrow word navigation, and
workspace cycling sat on ctrl-a/ctrl-d, which shadowed readline.

Raycast's Hyper Key emits ctrl+alt+shift+cmd for Caps Lock -- measured by
polling CGEventSource.flagsState while it was held, not assumed -- so every
binding is written against that literal four-modifier sequence.

Removed: all 37 alt-* bindings, plus ctrl-a and ctrl-d. Option+arrow word
navigation and terminal ctrl-a/ctrl-d are now untouched, and no bare cmd-*
or ctrl-* binding remains.

Added the same set under Caps, plus two substitutions forced by the modifier
layout:

  - Workspace cycling is Caps+tab / Caps+backtick. Caps+Shift+Tab is
    unavailable because Hyper already contains Shift; backtick sits directly
    above Tab and reads as its reverse. Former workspace moves to Caps+B,
    since Caps+Ctrl+Tab is unavailable for the same reason.

  - Moving a window becomes a mode, entered with Caps+A. Hyper consumes all
    four modifiers AeroSpace supports and it rejects fn, so no second chord
    level exists -- Caps+Shift+Left is byte-identical to Caps+Left. In the
    mode, arrows nudge the window and numbers send it to a workspace, as i3
    and sway do for resize.

Setting Raycast's Hyper to ctrl+alt+cmd without Shift would make Caps+Shift a
distinct combination again and allow plain chords; that is a Raycast-side
change and is left alone.
Moving a window was a toggled mode: Caps+A in, arrows, esc out. Two problems
with that. It costs two keystrokes for the most frequent operation, and a
toggled mode has no visual indicator -- "am I in move mode?" is
indistinguishable from "is this broken?", which is exactly how it read in use.

A held chord is what was wanted, and AeroSpace cannot express hold-to-activate
modes at all: it fires hotkeys on key down only, its config rejects any key-up
option, and its binary contains no hotkey-release event. The only thing that
behaves like "hold" is a modifier chord.

So move becomes Caps+h/j/k/l -- hold Caps, tap a direction. The arrows stay on
focus and cannot be shared, because Raycast's Hyper contains Shift and so
Caps+Shift+Left is byte-identical to Caps+Left. hjkl is the same direction set
Hyprland and vim use.

Split orientation moves from Caps+J to Caps+O, since J is a direction now.

Sending a window to another workspace becomes relative, Caps+comma and
Caps+period, wrapping around. By-number would need Caps+Shift+N, and no other
single key set maps cleanly onto 1-9 without worse mnemonics.

The move mode and its table are deleted; there are no modes left but service.
Third and final modifier: plain Option ate Option+arrow word navigation, and
Caps Lock via Raycast's Hyper was worse -- Raycast's Hyper is fixed at
ctrl+alt+shift+cmd, consuming all four modifiers AeroSpace supports, so
Caps+Shift was byte-identical to Caps and moving a window had to become a
toggled mode with no visual indicator.

Ctrl has neither problem. Shift is free, so move is a plain chord again and
direct send-to-workspace comes back, which the Hyper layout could not express
at all.

The split is by modifier depth:

  Ctrl          window navigation -- arrows and digits ONLY
  Ctrl + Shift  window manipulation -- everything else
  Option        text navigation, untouched
  Cmd           macOS and apps, untouched
  Ctrl + letter terminal, untouched

No plain Ctrl+letter is bound anywhere, so ctrl-a, ctrl-c, ctrl-d, ctrl-r and
ctrl-w keep working. Plain Ctrl is confined to arrows and digits, neither of
which carries a control character.

Dropped rather than rehomed: next/previous workspace cycling. Ctrl+Tab belongs
to browsers and editors and Ctrl+backtick is VS Code's integrated terminal;
nothing else was clean enough to invent. Former-workspace survives on
Ctrl+Shift+B, and the relative window sends on Ctrl+Shift+comma/period.

Tiling, workspace model, window rules, monitor assignment and startup are
untouched -- the only change outside the Keys section is the header key map.
The Ctrl migration dropped next/previous workspace navigation rather than
inventing a scheme: Ctrl+Tab belongs to browsers and editors, and
Ctrl+backtick is VS Code's integrated terminal.

Brackets are the answer -- prev/next is what they mean nearly everywhere, and
they pair with the existing ctrl-shift-comma/period: brackets take you to a
workspace, comma/period take the window there.

Bound only with Shift on purpose. Plain ctrl-[ is the ESC control character
and plain ctrl-] is GS, so neither belongs to a window manager.
on-focus-changed fires on every focus change, not just the ones you asked for.
A transient window that appears, takes focus and disappears -- an unarchiving
progress dialog is the case that surfaced it -- drags the cursor across the
screen and leaves it stranded there.

It was there because AeroSpace draws no borders and the cursor was the only
focus indicator available. Having no indicator beats having one that yanks the
pointer around on its own.

on-focused-monitor-changed stays: it fires only when the focused display
changes, which no short-lived window on the current display can trigger.
AeroSpace binds plain Ctrl+arrows for focus, Ctrl+Shift+arrows to move a
window and Ctrl+1..9 for workspaces. macOS claims every one of those for
Spaces and Mission Control, and system shortcuts win over app-registered
hotkeys, so on a fresh machine the bindings silently do nothing.

Ids 80 and 82 are the trap. System Settings shows one checkbox per "Move
left/right a space" row, but macOS registers two hotkeys behind it --
Ctrl+arrow and Ctrl+Shift+arrow -- and the Shift variants have no UI control
anywhere. They survive turning the visible ones off, which is exactly what had
happened here.

Written through `defaults import` rather than `defaults write -dict-add`: the
old-style syntax stores the parameters as strings and this table wants
integers. Idempotent -- an entry already disabled keeps its parameters
untouched, a missing one is created disabled -- and applied with
activateSettings so no logout is needed.

Also drops the Brewfile's description of the deleted per-app slot model.
@fmontes fmontes changed the title Add AeroSpace desktop layout with fixed app slots Omarchy-style AeroSpace tiling on Ctrl Aug 27, 2026
Two issues a Codex review of the branch surfaced.

home/.zshrc sourced ~/.railway/env unguarded. The Railway CLI writes that file
on first login, so on a fresh machine every interactive shell printed "no such
file or directory". Every other optional integration in this file already
guards with `2>/dev/null || true`; this one now matches.

scripts/06-macos.sh only disabled symbolic hotkey ids 118-121, which are
Switch to Desktop 1-4, while AeroSpace binds Ctrl+1..9. macOS adds entries for
higher desktops as Spaces are created and their ids are not documented, so
rather than guess at ids, the script now also scans the existing table and
disables anything that is a bare Ctrl or Ctrl+Shift chord on a key AeroSpace
claims.

Excluding Cmd and Option from that match is what keeps it away from the
Ctrl+Shift+Cmd+3 and Ctrl+Shift+Cmd+4 screenshot shortcuts, which share the
digit keycodes. Unit-tested against twelve real hotkey shapes.

The known-id list stays, so ids macOS has not created yet are pre-disabled.
@fmontes

fmontes commented Aug 27, 2026

Copy link
Copy Markdown
Owner Author

Codex review pass

Ran codex review --base main. Three findings, two acted on.

P2 — unguarded ~/.railway/env source. Real, fixed in 91f4011.

home/.zshrc:100 sourced the file with no guard. The Railway CLI only writes it on first login, so a fresh machine printed no such file or directory on every interactive shell. Every other optional integration in that file already guards with 2>/dev/null || true — this one now matches.

P2 — Mission Control shortcuts for desktops 5–9. Right in principle, fixed differently in 91f4011.

The observation was correct: the script only disabled ids 118–121 (Switch to Desktop 1–4) while AeroSpace binds Ctrl+1..9. But those higher ids don't exist on this machine, and macOS's ids for desktops 5+ aren't documented, so hardcoding guesses would write meaningless entries into the hotkey table.

Instead the script is now data-driven: it scans the existing table and disables anything that is a bare Ctrl or Ctrl+Shift chord on a keycode AeroSpace claims, then still pre-disables the known ids so ones macOS hasn't created yet are covered.

Excluding Cmd and Option from that match is the load-bearing part — it keeps the scan away from Ctrl+Shift+Cmd+3/4, the screenshot shortcuts, which share the digit keycodes. Unit-tested against twelve real hotkey shapes including those; verified idempotent and confirmed the screenshot entries are untouched.

P1 — SSH signing key in .gitconfig. False positive, no change.

Codex reviewed the dirty working tree. home/.gitconfig is not touched by any commit in this PR, and the committed version carries placeholders:

[user]
	name = Your Name
	email = your@email.com

The real identity and signingkey live only as an uncommitted local modification, by design, so git status shows a permanent M there. Nothing to fix.

The Dock reset already stripped every Apple app a new Mac ships with --
persistent-apps for the left side, persistent-others for the Downloads stack,
show-recents for the middle. That part was fine.

What was not fine is re-pinning blindly. Apps.app exists only on macOS 26 and
later, where it replaced Launchpad.app, so installing on an older release
pinned a path that is not there and left a broken "?" tile in the Dock.

Check each path before pinning it, and list both Apps.app and Launchpad.app so
whichever the release actually has gets used.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant