hausfold

haus

Changing your Mac with an agent

Your machine is text and every rebuild is reversible, so an AI agent can reconfigure it safely: the skill haus ships, the loop it follows, and the one rebuild it refuses.

Point an AI agent at a normal Mac and it brew installs things, writes dotfiles, and clicks through System Settings on your behalf. On a haus machine most of that would be silently undone by the next rebuild, with no record of what changed.

Declarative config flips that. Every change is text in one file, haus rebuild builds before it switches so a broken edit never reaches the running system, and haus rollback puts the last one back in seconds. That makes yours the rare machine an agent can reconfigure without it being reckless.

The safety was always there; the missing half was knowledge. So haus ships it.

The skill haus writes

Every rebuild writes a skill called haus into the skills directory of each client in haus.ai.clients: ~/.claude/skills/haus for Claude Code, ~/.codex/skills/haus for Codex, ~/.config/opencode/skills/haus for OpenCode. Name no clients at all (or turn the room off, which resolves to the same empty list) and all three get a copy, so the skill is never the missing piece. One body, one copy per client:

FileWhat it is
SKILL.mdThe loop, the boundaries, the traps.
references/options.mdEvery haus.* option, generated from the exact revision you're pinned to.
references/this-machine.mdYour host: hostname, host-file path, which rooms are on, your theme and keys, your app roster and its taken leader keys, plus the rebuild hazards specific to this machine.
references/recipes.mdWorked examples for the common asks.
consumer-AGENTS.mdA starter AGENTS.md for your own config repo.
consumer-CLAUDE.mdIts one-line @AGENTS.md pointer, for the client that reads only CLAUDE.md.

The option reference being generated is the point: it can only describe options that exist on your revision (a confidently-wrong option name costs you a failed build), and haus update regenerates it with the rest.

Check it's there

haus doctor has an Agents section: whether the skill is installed (it checks every client's directory and names the copy it found), whether your config repo has an AGENTS.md and the CLAUDE.md pointer beside it, and whether the app you're running from can write macOS's protected settings.

The loop it follows

Orient: read references/this-machine.md and your host file, and check haus status.

Find the option: grep the generated reference. If it isn't listed, it doesn't exist on your revision, and the agent should say so rather than guess.

Edit ~/.config/nix/hosts/<hostname>/default.nix, the one file you own.

Apply with haus rebuild: the build gates the switch.

Verify, or haus rollback.

What to ask for

Ordinary requests, in your own words:

  • "Install Slack and give it its own workspace" → an entry in haus.roster for the leader key and the Homebrew cask, paired with one in haus.workspaces for the workspace and its bar pill.
  • "Everything's too small"haus.ui.scale.
  • "Switch to light mode"haus.theme.flavor plus haus.theme.systemAppearance, so macOS's own Light/Dark moves with the rest.
  • "Hide the weather in the bar" → the matching haus.sill.items.* toggle.
  • "Bind a key to open my notes"haus.keys.leaderExtras.

The skill tells the agent to prefer a haus.* option over a raw nix-darwin setting, and to say so when nothing covers what you asked, because that's a gap in haus, not something to bolt onto your machine.

What it won't do

  • Touch identity or secrets without asking: git identity, signing keys, haus.secrets.*.
  • Edit haus itself, flake.lock, or anything in /nix/store. Pulling a newer revision is haus update, not a hand edit.
  • Uninstall apps behind your back. Removing an app from your config stops haus managing it; the app stays on disk until you brew uninstall --zap it.

The one rebuild it will refuse

If your host file sets system.defaults.universalaccess.* directly, haus rebuild refuses to run whenever the app it runs under lacks Full Disk Access, and tells you how to get past it.

That domain is TCC-protected, and the grant belongs to the app the rebuild runs under, not to you and not to root. So this is not an agent rule: an agent pane inside a terminal that holds the grant rebuilds perfectly well, and you at that same keyboard, in a terminal nobody has granted, are refused identically. Without the grant the write fails partway through activation and takes everything after it down too: your bar, tiling and palette come back dead, with the symptom nowhere near the cause. Refusing is the kinder failure: nothing is changed, and your edit is still on disk.

The way past it is always to stop writing the domain by hand. haus.accessibility.* reaches every key in it that macOS actually honours (seven of them, which since August 2026 is every key nix-darwin types there, so the raw form no longer reaches anything the safe one doesn't) with a guarded write, so without the grant you lose that setting and nothing else, and the rebuild runs from anywhere. Otherwise: run it from an app that holds the grant, or set HAUS_FDA_ANYWAY=1 when you know better (HAUS_AGENT_REBUILD=1, the name this had while the check was agent-scoped, still works).

haus plan tells you which grant a rebuild wants before it runs, and haus doctor's Permissions section says whether this app has it. haus.theme.contrast is a different thing again: haus's own palette axis, painted into the apps haus themes rather than into macOS, so it always applies.

What a rollback doesn't undo

haus rollback rewinds everything Nix manages, instantly. It does not rewind macOS system settings a rebuild wrote (Dock, keyboard, Finder), and it does not rewind Homebrew casks; those live outside Nix generations entirely. A good agent says which kind of change it's about to make.

An AGENTS.md for your own config

~/.config/nix is your own git repo, your machine in text. Dropping an AGENTS.md in it orients any agent you open there, whether or not it found the skill. A starter pair ships inside the skill; nothing writes it for you, because it's your repo:

# whichever of these exists on your machine; the copies are identical:
#   ~/.claude/skills/haus · ~/.codex/skills/haus · ~/.config/opencode/skills/haus
skill=~/.claude/skills/haus
install -m 644 "$skill"/consumer-AGENTS.md ~/.config/nix/AGENTS.md
install -m 644 "$skill"/consumer-CLAUDE.md ~/.config/nix/CLAUDE.md

install -m 644, not cp: the starter pair are symlinks into the Nix store, whose files are read-only. A plain cp preserves that mode, so you land on an AGENTS.md your editor refuses to save, on the one file the whole point of copying is to then edit.

Two files, because the tools disagree about the filename. AGENTS.md carries the rules: Codex, OpenCode, Cursor, Zed, Copilot and everything else that speaks agents.md reads it directly. Claude Code reads only CLAUDE.md, so the second file is a one-line @AGENTS.md import and nothing else. Copy one and you orient some of your tools and not others.

Your own instructions, in every client

haus.ai.instructions is the other half of what haus writes into an agent's home: your always-on operating context, rendered once per installed client at the path that client reads (~/.claude/CLAUDE.md, ~/.codex/AGENTS.md, ~/.config/opencode/AGENTS.md), under a short generated preamble.

haus.ai.instructions = ''
  # Global instructions

  Ship small, verified changes. Ask before anything hard to reverse…
'';

Write it client-neutrally: the same text reaches whichever agent your ⌘A pane spawned, so a line about one client's flags is noise in the other two. Empty (the default) writes nothing at all, so a hand-managed instructions file is never touched. Setting it on a machine that already has one, though, moves yours aside to <file>.backup. And haus.ai.skill = false; stops the skill being written at all, for when you'd rather own each client's skills directory yourself.

(Both were haus.claude.globalMd and haus.claude.skill until August 2026; the old names still evaluate, with a warning.)

It's still your machine

An agent that can rebuild your Mac can change how your Mac behaves. The safety here is real, but it is recovery, not prevention: the build gates the switch and the rollback is atomic, so mistakes are cheap, not impossible. Read the diff before you say yes, exactly as you would for any other change to your config.

On this page