
You said getting the mini to come back on its own sounded like more trouble than it was worth. It is one file and one checkbox.

## The file

A LaunchAgent is a plist in `~/Library/LaunchAgents/`. Four keys matter. `ProgramArguments` is the command. `RunAtLoad` starts it at login. `KeepAlive` restarts it when it exits. `EnvironmentVariables` sets `PATH`, because launchd does not read your shell profile and `claude` and `tmux` are not on its default path. Logs go where `StandardOutPath` and `StandardErrorPath` point. The starter in [Downloads](downloads.html) is exactly that.

```bash
cp net.psm.claude-agent.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/net.psm.claude-agent.plist
launchctl list | grep psm
```

A LaunchAgent runs inside your login session, which is what Claude Code needs for the keychain. A LaunchDaemon runs before login as root and is the wrong tool here. If the mini asks for a password on boot, turn on automatic login for your user so the agent session exists without you.

## The tmux wrapper

Claude Code is interactive, so the plist starts a tmux session and then waits on it. When the session dies, the wait ends, launchd sees the exit, and KeepAlive starts it again. You attach with `tmux attach -t agent` from any terminal, including over SSH from your laptop on Tailscale, and detach with `Ctrl-b d` without stopping anything.

## The checkbox

A Mac does not power back on after an outage unless you tell it to. System Settings, Energy, "Start up automatically after a power failure," or from a terminal:

```bash
sudo pmset -a autorestart 1
```

Without this the UPS buys you the short outages and nothing else. With it, a long outage ends with the mini booting, logging in, launchd loading, tmux starting, Claude reconnecting the channel, and your bot answering again, with nobody home.

## Two traps

Claude Code's native installer updates itself in the background and applies the update on the next launch, which for an always-on session means the next time launchd restarts it. That is fine until an update changes behaviour under you. If you want to control when that happens, install with Homebrew instead, which does not auto-update, or set `DISABLE_AUTOUPDATER=1` in the plist's environment.

Two installs on one Mac is the other one. Homebrew and the native installer both put a `claude` on your path, and `claude update` can report success while `claude --version` in your plist's PATH says otherwise. `which -a claude` shows both. Keep one.

## How you know it worked

`launchctl list | grep psm` shows a PID. `tmux ls` shows `agent`. Reboot, wait a minute, text the bot.

## Read more

- [launchd.info](https://www.launchd.info/), the readable reference
- [Apple, creating launch daemons and agents](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html)
- [Claude Code setup and auto-updates](https://code.claude.com/docs/en/setup)
