---
title: macOS
sidebarTitle: macOS
description: Running IronClaw on macOS with Homebrew, Keychain, and launchd
---

IronClaw supports macOS natively with Homebrew installation, macOS Keychain for secure key storage, and launchd for background service management.

---

## Installation

### Homebrew (Recommended)

```bash
# Add the IronClaw tap
brew tap ironclaw-ai/tap

# Install IronClaw
brew install ironclaw
```

### Shell Script

```bash
curl -fsSL https://install.ironclaw.ai | bash
```

Installs to `~/.local/bin/ironclaw`. Add to PATH:

```bash
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
```

### Cargo (Build from Source)

```bash
# Install Rust if needed
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Build and install
cargo install ironclaw
```

### Verify Installation

```bash
ironclaw --version
ironclaw doctor
```

---

## First Launch: Gatekeeper

macOS Gatekeeper may block the binary on first launch if it was downloaded directly rather than installed through Homebrew.

**To allow it:**

1. Right-click `ironclaw` in Finder and choose **Open**
2. Click **Open** in the security dialog

Or via the terminal:

```bash
xattr -d com.apple.quarantine ~/.local/bin/ironclaw
```

<Note>
Binaries installed via `brew install ironclaw` are automatically notarized and will not trigger the Gatekeeper warning.
</Note>

---

## macOS Keychain Integration

IronClaw stores its encryption master key in the macOS Keychain. This keeps the key off disk and protected by your login password and Touch ID.

### First Run Dialogs

On first run you will see two system dialogs:

1. **"Enter your password to unlock the login keychain"** — Unlock the keychain to read/write items. Enter your macOS login password.
2. **"ironclaw wants to use your confidential information stored in 'IronClaw Master Key' in your keychain"** — Click **Always Allow** to prevent repeated prompts on future launches.

<Warning>
Clicking **Allow** instead of **Always Allow** causes this dialog to appear on every launch. Choose **Always Allow** the first time to avoid repeated interruptions.
</Warning>

### Managing the Keychain Entry

View the entry in Keychain Access (open via Spotlight: `keychain access`):
- Category: **Passwords**
- Name: `IronClaw Master Key`
- Account: `ironclaw`

To delete and regenerate the master key (this invalidates all stored secrets):

```bash
security delete-generic-password -a ironclaw -s "IronClaw Master Key"
ironclaw onboard  # Re-run wizard to generate a new key
```

### Headless / CI Environments

For non-interactive macOS environments (CI, build machines), use the environment variable fallback:

```bash
export IRONCLAW_MASTER_KEY=$(openssl rand -base64 32)
```

---

## launchd Service

launchd is the macOS equivalent of systemd. It manages background services and can restart IronClaw automatically on failure or system reboot.

### User-Level Service (Recommended)

Create `~/Library/LaunchAgents/ai.ironclaw.plist`:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>ai.ironclaw</string>

  <key>ProgramArguments</key>
  <array>
    <string>/usr/local/bin/ironclaw</string>
    <string>run</string>
  </array>

  <key>EnvironmentVariables</key>
  <dict>
    <key>DATABASE_BACKEND</key>
    <string>libsql</string>
    <key>LLM_BACKEND</key>
    <string>nearai</string>
    <key>GATEWAY_ENABLED</key>
    <string>true</string>
    <key>GATEWAY_HOST</key>
    <string>127.0.0.1</string>
    <key>GATEWAY_PORT</key>
    <string>3000</string>
    <key>RUST_LOG</key>
    <string>ironclaw=info</string>
  </dict>

  <key>RunAtLoad</key>
  <true/>

  <key>KeepAlive</key>
  <dict>
    <key>Crashed</key>
    <true/>
    <key>SuccessfulExit</key>
    <false/>
  </dict>

  <key>StandardOutPath</key>
  <string>/tmp/ironclaw.stdout.log</string>

  <key>StandardErrorPath</key>
  <string>/tmp/ironclaw.stderr.log</string>

  <key>WorkingDirectory</key>
  <string>/Users/YOUR_USERNAME</string>
</dict>
</plist>
```

Replace `YOUR_USERNAME` with your actual macOS username (`whoami`).

<Note>
Sensitive values (API keys, auth tokens) should not be placed in the plist directly since it is a plain text file. Store them in the Keychain and have IronClaw read them at startup, or use `launchctl setenv` to inject them at runtime.
</Note>

### Load and Manage the Service

```bash
# Load the service (starts immediately due to RunAtLoad)
launchctl load ~/Library/LaunchAgents/ai.ironclaw.plist

# Unload (stop and disable)
launchctl unload ~/Library/LaunchAgents/ai.ironclaw.plist

# Reload after editing the plist
launchctl unload ~/Library/LaunchAgents/ai.ironclaw.plist
launchctl load ~/Library/LaunchAgents/ai.ironclaw.plist

# Check status
launchctl list | grep ironclaw

# Start / stop manually
launchctl start ai.ironclaw
launchctl stop ai.ironclaw
```

### Homebrew Services (Alternative)

If installed via Homebrew:

```bash
# Start now and on login
brew services start ironclaw

# Stop
brew services stop ironclaw

# Restart
brew services restart ironclaw

# View status
brew services list | grep ironclaw
```

---

## Docker Desktop for macOS

The Docker sandbox requires Docker. On macOS, use [Docker Desktop](https://www.docker.com/products/docker-desktop/).

### Install Docker Desktop

1. Download from [docker.com/products/docker-desktop](https://www.docker.com/products/docker-desktop/)
2. Drag to Applications and open
3. Complete the setup wizard
4. Verify: `docker run --rm hello-world`

### Resource Limits

Docker Desktop runs inside a Linux VM on macOS. Configure the VM resource allocation in **Docker Desktop → Settings → Resources**:

| Setting | Minimum | Recommended |
|---------|---------|-------------|
| CPUs | 2 | 4 |
| Memory | 4 GB | 8 GB |
| Disk | 20 GB | 40 GB |

<Note>
Docker on macOS has more overhead than native Linux due to the VM layer. Sandbox container startup is typically 1-3 seconds slower than on Linux. This is expected behavior.
</Note>

---

## Viewing Logs

```bash
# Stream logs in real time (unified log)
log stream --predicate 'process == "ironclaw"' --level info

# Show recent messages
log show --predicate 'process == "ironclaw"' --last 1h

# View launchd stdout/stderr files
tail -f /tmp/ironclaw.stdout.log
tail -f /tmp/ironclaw.stderr.log
```

---

## Next Steps

<CardGroup cols={3}>
  <Card title="VPS Hardening" icon="shield" href="/platforms/vps">
    Securing IronClaw on a public-facing server
  </Card>
  <Card title="Docker Compose" icon="layers" href="/platforms/docker-compose">
    Production Docker Compose with PostgreSQL
  </Card>
  <Card title="Logging" icon="file-text" href="/ops/logging">
    RUST_LOG levels and log streaming
  </Card>
</CardGroup>
