Install
One line scaffolds your config. A second command activates it. Nothing is activated without your say-so.
curl -fsSL https://hausfold.co/haus.sh | bashThat installs Nix if you don't have it, asks you a few questions (including which desktop you want), and writes your config. It does not change your Mac on its own: it writes files, prints the one command that activates them, and asks before running it for you.
So the whole install is two moves, and you can stop between them and read what
the first one wrote. (The pipe doesn't cost you the questions: the installer
reaches your terminal directly, so | bash interviews you like any other form.
In CI, a container, or a run whose output you've captured to a file, no one is
watching, so it takes the defaults and never offers to switch.)
If you already know which desktop you want
Every desktop has its own URL, and typing it answers the question before it's asked:
curl -fsSL https://hausfold.co/hacker.sh | bash # the full desktop
curl -fsSL https://hausfold.co/everyday.sh | bash # for someone who doesn't write code
curl -fsSL https://hausfold.co/minimal.sh | bash # just the themed shellThey're the same script: the URL sets the desktop and the installer skips that
one question. haus.sh is the one that asks. A Mac runs exactly one desktop,
and whichever you pick, changing your mind later is a line in your own config,
not a reinstall.
Piping to bash passes no arguments, which is why the desktop rides in the URL
rather than on a flag. If you'd rather use the flag, give bash a -s --:
curl -fsSL https://hausfold.co/haus.sh | bash -s -- --desktop=minimalA desktop is not a lock-in
Every desktop is a set of values for the same options. Anything one of them chose, your own file overrides in a line, so picking is a starting point, not a commitment.
Before you start
- A Mac on Apple Silicon, running a recent macOS. Intel isn't supported.
- Xcode Command Line Tools. The installer prompts for them if they're missing, then asks you to re-run.
- 10–15 minutes and a few GB of download for the first build.
You don't need Nix first
The bootstrap installs Determinate Nix for you. If you already run stock Nix it stops and explains rather than touching your install.
Read it first, if you like
curl … | bash runs whatever the URL serves, so it's fair to want to look.
The URL only proxies
bootstrap.sh from
the public repo; it's boring on purpose.
curl -fsSL https://hausfold.co/haus.sh | less
# or pin an exact release and diff it against GitHub
curl -fsSL 'https://hausfold.co/haus.sh?ref=v2026.07.18' | lessA desktop's URL serves that same file with two lines added at the top, saying
which desktop you asked for. haus.sh adds nothing at all, so it's the one to
diff against GitHub.
By default you get the latest release tag. Releases are date-tagged, so
?ref=v2026.07.18 pins a specific day, and a release tag is the only thing
?ref= accepts. Anything else is refused rather than fetched, which is what
stops a link with someone else's commit in it from serving you a script off
this domain.
What it does
Takes a snapshot
Confirms you're on macOS and takes a Time Machine local snapshot as a coarse rewind point. Non-fatal if Time Machine is off.
Asks you a few things
Your git name and email, a desktop (hacker / everyday / minimal / custom), an accent colour, a wallpaper, and an editor: helix, neovim, vim or nano, and haus installs the one you name. It also asks whether to keep your current Dock, keyboard and Finder settings, and whether to adopt the Homebrew casks you already have.
Shows you what would change
A read-only report before anything is written: which dotfiles get backed up, which macOS settings change, and which casks it found. No app you installed is ever removed.
Writes your config
Creates ~/.config/nix/ (a small flake that imports haus, plus a host file
holding your answers) and commits it to git.
Nothing is active yet. Wherever there's a terminal to ask on, piped or not,
the last thing it asks is whether to change that: say yes and it runs the two
commands below for you, then haus doctor. Unattended, it stops here and prints
them.
Build and switch
cd ~/.config/nix
nix build .#darwinConfigurations.$(scutil --get LocalHostName).system \
&& sudo ./result/sw/bin/darwin-rebuild switch --flake .The build runs first, and a failed build never touches your system. When it
succeeds, everything lands at once: apps install, the bar and tiling start,
your terminal is themed, and haus joins your PATH.
The first run is slow; it's downloading the world. After that, haus rebuild
is the only command you need.
If you regret it
| To undo | Use |
|---|---|
| The macOS settings | the snapshot from step 1 |
| Everything haus did | haus rollback (atomic, previous generation) |
| Apps | yours. haus never uninstalls one you added |
| All of it | Leaving, every exit in turn, smallest first |
Unattended installs
Every question has an environment variable, so the whole thing can run without a prompt:
HAUS_NONINTERACTIVE=1 \
HAUS_GIT_NAME="Ada Lovelace" \
HAUS_GIT_EMAIL="ada@example.com" \
HAUS_ACCENT="mauve" \
bash -c "$(curl -fsSL https://hausfold.co/haus.sh)"| Variable | Effect |
|---|---|
HAUS_NONINTERACTIVE=1 | Skip the questions, take the defaults |
HAUS_DRY_RUN=1 | Print the config it would write, write nothing. Still asks the questions if you have a terminal; pair it with --defaults for a silent run |
HAUS_DESKTOP | Which desktop to select (hacker, everyday, minimal, blank), or --desktop=<name> on the command line. Setting it skips that question even in an interactive run, which is what a desktop's own URL does for you |
HAUS_ROOMS | Which rooms to turn on, one by one, instead of taking a desktop's selection |
HAUS_ACCENT / HAUS_WALLPAPER / HAUS_EDITOR | The look and the editor |
HAUS_KEEP | macOS settings to leave alone (dock,keyboard,finder) |
HAUS_DIR | Scaffold somewhere other than ~/.config/nix |
HAUS_FROM | Restore an existing config instead of scaffolding |
If you already scripted this with the old names
Every variable above was spelled NEBELHAUS_* until 2026-08-14, and the old
spelling is still read: the installer promotes it before anything else runs,
with the new name winning if both are set. Same for the desktop names it
accepts: hacker was nebelhaus, and the pre-desktops HAUS_PRESET=full still
selects it. Nothing you already automated needs changing.
These are also what you want if you hand the install to a coding agent: the
questions are a terminal UI, and a tool driving it blind is how someone else's
git identity ends up in your config. An agent can do everything up to the
build; the two sudo steps are yours.