Troubleshooting
The handful of things that go sideways on macOS (a wedged agent, a missing grant, a stubborn cask), and the exact command that unsticks each one.
Almost every haus problem is one of a few known macOS quirks with a known fix. Start here, whatever the symptom:
haus doctor # Nix, the Xcode tools, every GUI agent, cask drift, the
# launcher's Accessibility grant, the theme ports and your
# secrets, in one passEvery agent also keeps a log in /tmp: aerospace, sketchybar,
sill-bottom and pounce each write <name>.out.log and <name>.err.log
there. Reading the error log is usually faster than restarting blind, and an
agent that dies again ten seconds after a kick is telling you something that
only shows up in it.
⌘Space does nothing
Pounce is a launchd user agent. If it isn't answering, kick it. This is the clean recovery for any wedged agent, and the rest of this page reuses it with a different label:
launchctl list | grep pounce # is it running at all?
launchctl kickstart -k gui/$(id -u)/com.hausfold.pounceIf the palette opens but clipboard and emoji paste don't work, it's missing the Accessibility grant:
pounce --request-accessibility # approve the system dialog
pounce --check-accessibility # prints true once grantedSet haus.pounce.signingIdentity so that grant survives rebuilds; see
Granting Accessibility. If
⌘Space still opens Spotlight, log out and back in once so the
symbolic-hotkey reassignment takes.
Palette opens, but slowly?
Another hotkey tool (skhd, AeroSpace, Raycast) bound to the same key grabs it
with an event tap ahead of Pounce, so every summon spawns a fresh client
instead of hitting the daemon's fast path. Registration still reports success
and the palette still opens, which is what makes it hard to spot. pounce doctor names the culprit and tells you what to unbind.
One line of its output is wrong on a haus machine: if the daemon isn't running
it suggests brew services start pounce, which is the advice for a standalone
Homebrew install. Here the daemon is the launchd agent above; kick that
instead.
Windows won't tile
Almost always the cold-boot race: an agent that launched before the desktop session was ready parked itself instead of starting. Kick it:
launchctl kickstart -k gui/$(id -u)/org.nixos.aerospaceThe smaller ones:
- Scrambled after sleep, or a window on the wrong workspace? Tap ⇪ then ` to re-sort everything to its roster home.
- A binding you changed didn't take? A rebuild rewrites the config, but the
live daemon holds the old one until it reloads. Force it with
aerospace reload-config, or run Reload AeroSpace from the ⌘Space palette.
The bar is blank or missing
launchctl kickstart -k gui/$(id -u)/org.nixos.sketchybar
launchctl kickstart -k gui/$(id -u)/org.nixos.sill-bottom # if you run the bottom barIf /tmp/sketchybar.err.log says could not acquire lock-file … already running?, a stray brew services copy of SketchyBar is holding the lock. Every
rebuild evicts it, so haus rebuild is the fix.
Running, but stale (a pill you added isn't there, or a colour change didn't land)? The easy fix is Reload SketchyBar, from the ⌘Space palette or from the haus menu on a left-click of the logo pill. By hand:
sketchybar --reload ~/.config/sketchybar/sketchybarrc # the menu-bar bar
sill-bottom --reload ~/.config/sketchybar/sill-bottomrc # the bottom bar, if enabledAlways name the rc, and reload each bar
--reload on its own doesn't mean "re-read your config"; it means re-run the
path you resolved at startup, and that path is a symlink into /nix/store
resolved once. So a bare reload can quietly replay the config from the
generation the bar booted on while exiting 0 and logging success. Naming the
path re-resolves it now. And the two bars are separate instances: a lone
sketchybar --reload leaves the bottom one exactly as it was.
If you'd rather not run a custom bar at all, haus.sill.enable = false brings
the native macOS menu bar back.
After a macOS upgrade, every agent is dead
If the bar, tiling and ⌘Space all come up dead at once right after upgrading to
macOS 26 Tahoe or later, the culprit is Background Task Management.
Tahoe gates login items whose executable isn't Apple-signed, and every Nix agent
launches through /bin/sh -c "…", which BTM files under "unidentified
developer" and can silently refuse to start. They register fine; they just never
run.
haus btm # no-op before Tahoe; on Tahoe+ it reads the BTM store and instructsThere is no declarative fix: the toggle lives in macOS's own BTM store,
which has no CLI to set it. So it's a one-time manual step: in System Settings
▸ General ▸ Login Items & Extensions, scroll to Allow in the Background,
find the entries named sh (subtitled Item from unidentified developer),
switch them on and reboot. Already on but still blocked? Flip off, then on, to
force a database write.
You can read the store yourself at any time:
sudo sfltool dumpbtm | grep -B2 -A8 -iE "nixos|hausfold|darwin-store"Look for disallowed, and search all three names: the launcher registers under
com.hausfold.pounce while tiling and the bar are still org.nixos.*, so a
grep for nixos alone reports a clean store while the launcher is the thing
that's blocked.
Every agent is dead, and macOS didn't change
Same symptom, different cause, and this one needs no upgrade: a rebuild that
aborted before it got to them. If your host file writes
system.defaults.universalaccess.*, activation writes those keys two thirds of
the way through, and without Full Disk Access that write fails, takes the rest
of activation with it, and never reaches the launchd agents. The failure is
nowhere near the symptom.
haus doctor's Permissions section reports the grant, haus plan says
whether this rebuild needs it before you run one, and haus rebuild refuses up
front whenever the app it runs under lacks it, agent pane or plain terminal
alike, since the grant follows the app. Better still, sidestep the domain:
haus.accessibility.* reaches every key in it that macOS actually honours
(all seven, which is every key nix-darwin types there) with a guarded write,
which costs you the setting and nothing else when the grant is missing. Changing your Mac with an
agent has the detail.
Touch ID for sudo beachballs inside a multiplexer
The pam_reattach shim isn't loading. It ships with the collar room and is
on by default; check the order in /etc/pam.d/sudo_local: reattach must come
before the Touch ID line. Outside tmux or zellij, Touch ID should just work;
cancel the prompt to fall back to your password. Touch
ID has the rest.
"Refusing to load cask … from an untrusted tap"
Third-party taps fail Homebrew's trust check under a sudo-driven activation.
haus turns that requirement off globally
(HOMEBREW_NO_REQUIRE_TAP_TRUST=1 in /etc/homebrew/brew.env), so seeing this
means the file didn't land. Re-run haus rebuild, or export the variable in
your shell for a one-off.
An app I removed from my config is still installed
By design. haus.homebrew.cleanup is "none", so nothing you installed is ever
auto-deleted, and haus rollback doesn't rewind Homebrew apps, because
they aren't in Nix generations. Remove one by hand:
brew uninstall --zap <cask>For a machine where an undeclared cask is removed on the next rebuild, set Customize a desktop.
A rebuild broke something
haus rollback # atomically back to the previous generation
haus generations # what you can roll back tohaus rebuild always builds before it switches, so a config with an error in
it can't activate: you get a build failure and a machine exactly as it was. For
macOS settings rather than packages, haus revert-settings puts back the
snapshot haus capture took, and the APFS snapshot from install time is the
coarser rewind.
Want to go further than one generation (switch a room off, or remove haus entirely)? Leaving walks each exit, smallest first.
"Found a Nix at /nix that isn't Determinate"
haus is built on Determinate Nix, and the
installer stops on any /nix that Determinate didn't create (single-user or
multi-user daemon install alike, it's the flavour it checks) rather than risk
breaking the Nix you already have. If you
have a Nix you don't need, uninstall it and re-run the one-liner; if you want to
keep it, migrating to Determinate is the supported path. A fresh Mac needs none
of this; the bootstrap installs Determinate for you.
Still stuck?
The haus CLI
doctor, plan, diff, capture: the read-only commands that show you what a change would do before it does it.
Customize a desktop
Every dial worth knowing, and the rooms you can switch off when one of them isn't for you.
Still nothing? Open an issue with the
output of haus doctor.
The haus CLI
Every haus command. Apply, update, undo, and the read-only ones that show you a change before you make it.
How the flakes fit together
Nothing on your Mac changes until you say so. This is the machinery behind that, from the config the installer scaffolds to the exact commit every input is pinned at.