> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mspilot.io/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> MSPilot enrolls technician Windows machines and Apple Silicon Macs so Claude Desktop and ChatGPT run through one governed gateway. Seat words are standard seat and power seat. ConnectWise PSA import is not available. HIPAA is not a self-serve switch.

# macOS

> Install the agent on Apple Silicon Macs, what it puts on disk, how it keeps itself current, and how to fix a failed run.

The macOS agent enrolls a Mac with the gateway and writes the settings for the apps on each signed-in user. You install it with a script from your RMM, from Terminal on one Mac, or with a package and profile from an [MDM](/integrations/mdm/macos).

## Requirements

* An Apple Silicon Mac. The script refuses an Intel Mac with `refused: Apple Silicon (arm64) required`, and the package will not install on one.
* macOS 12 (Monterey) or later, for every install method: RMM script, Terminal, and MDM. The script does not check the version, but older versions are not tested or supported.
* For an MDM that pre-approves the agent's background items: macOS 13 or later and user-approved MDM enrollment. See [macOS MDM](/integrations/mdm/macos).
* Root. RMM scripts run as root (the System context in most RMMs). Nobody needs to be signed in for the install or the enroll.

**Deployment** does not install apps on macOS yet. When you tick apps under **AI applications** and pick **macOS**, **Deployment** says the script installs and enrolls the MSPilot agent only.

## Install

Open the client and go to **Deployment**. Under **Install the MSPilot agent**, set the seat cap and create or reuse an enrollment key. In the install step, pick **macOS**.

| Where                                           | What you get                             | How it runs                                                                            |
| ----------------------------------------------- | ---------------------------------------- | -------------------------------------------------------------------------------------- |
| NinjaOne, Datto, ConnectWise RMM, Level, Syncro | **Copy script** (`mspilot-bootstrap.sh`) | A bash script in the RMM, run as root                                                  |
| N-sight RMM                                     | **Download mspilot-bootstrap.sh**        | An Automated Task for macOS                                                            |
| MDM                                             | **MDM (profile + package)**              | A configuration profile and a signed package. See [macOS MDM](/integrations/mdm/macos) |
| No RMM                                          | **Download mspilot-enroll.sh**           | Terminal with `sudo` on one Mac                                                        |

The enrollment key, the gateway URL, and the channel are already inside the script you copy. Leave the RMM's script variables or parameters empty. **Deployment** lists the exact fields for your RMM, and each RMM page repeats them: [NinjaOne](/integrations/rmm/ninja-one), [Datto](/integrations/rmm/datto), [ConnectWise RMM](/integrations/rmm/connectwise-rmm), [Level](/integrations/rmm/level), [Syncro](/integrations/rmm/syncro), [N-sight RMM](/integrations/rmm/n-sight).

MSPilot's ImmyBot installer is Windows only. When ImmyBot is the connected RMM, the **macOS** choice on **Deployment** is turned off and shows **MSPilot's ImmyBot installer is Windows only**.

Give the job at least 600 seconds (10 minutes) so the agent can download. Enroll refuses to run as a signed-in user. If the RMM runs the script as the user, it prints `refused: enroll must run as root (set the RMM script to run as System)` and exits 2.

You do not schedule a pull job on macOS. You can schedule the same script daily if you like. Running it again is a safe repair: it brings the binary up to date and registers the jobs again.

After you choose **I've run it in** plus your RMM's name (for example **I've run it in NinjaOne**), **Deployment** watches this client for check-in for 10 minutes. If it times out, check the RMM job output against the [exit codes](#script-exit-codes), then choose **Watch again**.

### One Mac without an RMM

Installer links and emails are Windows only. On a Mac, download the script and run it in Terminal.

1. Choose **Download mspilot-enroll.sh**. macOS saves it to your Downloads folder.
2. Open Terminal: **Finder → Applications → Utilities → Terminal**.
3. Run the file, then type the Mac's administrator password:

   ```bash theme={"system"}
   sudo bash ~/Downloads/mspilot-enroll.sh
   ```

Keep Terminal open until the script finishes, then choose **I ran the installer**. **Deployment** watches for the Mac to check in. If it times out, check the script's output in Terminal on the Mac, then retry.

## What gets installed

| Path                                                         | What it is                                                         |
| ------------------------------------------------------------ | ------------------------------------------------------------------ |
| `/Library/Application Support/MSPilot/mspilot-agent`         | The agent. Owned by root.                                          |
| `/Users/Shared/MSPilot`                                      | Shared device state that every user's pull reads. Created by root. |
| `/Library/LaunchAgents/io.mspilot.agent.pull.plist`          | The per-user pull job.                                             |
| `/Library/LaunchDaemons/io.mspilot.agent.update.plist`       | The daily self-update job.                                         |
| `/Library/LaunchDaemons/io.mspilot.agent.enroll-retry.plist` | The enroll retry job. Present only while enrollment is waiting.    |
| `/Library/Logs/MSPilot`                                      | Logs for the root jobs.                                            |

The script downloads the agent from `https://downloads.mspilot.io/agent/<channel>/` and checks it against that channel's `SHA256SUMS` before it runs it. The default channel is `latest`.

## Scheduled jobs

| Job                             | Runs as             | When                    | What it does                                                                     |
| ------------------------------- | ------------------- | ----------------------- | -------------------------------------------------------------------------------- |
| `io.mspilot.agent.pull`         | Each signed-in user | At sign-in, then hourly | Fetches gateway config and writes that user's app settings                       |
| `io.mspilot.agent.update`       | root                | Daily at 03:00          | Updates the agent from its channel                                               |
| `io.mspilot.agent.enroll-retry` | root                | Every 15 minutes        | Retries enroll while the Mac is waiting. It removes itself once the Mac enrolls. |

The pull and update jobs wait a random delay of up to 5 minutes before they run, so a fleet does not call the gateway at the same second.

## Per-user configuration

The enroll runs as root and saves the device state. The signed-in user's AI apps are configured right away; other users at their next sign-in, then hourly. There is no RMM step per user.

On an RMM install, macOS 13 and later can show **Background Items Added** for the agent's jobs, and a user can switch them off in **System Settings → General → Login Items**. The [MDM profile](/integrations/mdm/macos) pre-approves the jobs so users cannot switch them off. That needs macOS 13 or later and user-approved MDM enrollment.

## Self-update

The update job runs every day at 03:00, plus the random delay. It compares the installed agent with the channel's `SHA256SUMS` and replaces it when they differ. A successful update writes `agent_updated` to `/Library/Logs/MSPilot/update.log`. Running the install script again also brings the agent up to date.

## Logs

| File                                     | Written by                      |
| ---------------------------------------- | ------------------------------- |
| `/Library/Logs/MSPilot/install.log`      | The package install from an MDM |
| `/Library/Logs/MSPilot/enroll-retry.log` | The enroll retry job            |
| `/Library/Logs/MSPilot/update.log`       | The daily self-update           |

An RMM run writes its output to the RMM job, not to a file. The per-user pull job does not keep a log. To check a Mac by hand, run this as the signed-in user:

```bash theme={"system"}
"/Library/Application Support/MSPilot/mspilot-agent" status
```

## Script exit codes

| Exit | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0    | Success: the output shows `enrolled device_id=…` or `already_enrolled`. `mspilot_pending: queued for sync/approval` also exits 0: the Mac is waiting for sync or approval and retries every 15 minutes.                                                                                                                                                                                                                                                                                      |
| 1    | Download, checksum, or setup failure: not a Mac, a Mac that is not Apple Silicon, a bad argument or channel, no connection to `downloads.mspilot.io` or no valid entry in its `SHA256SUMS`, a failed download, or a checksum mismatch. Without `downloads.mspilot.io` the script fails with exit 1 until downloads.mspilot.io is reachable, even when the agent is already installed; the RMM job or retry runs it again. The agent also returns 1 for a missing key or no machine identity. |
| 2    | Not run as root.                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| 3    | The gateway rejected the enrollment or could not be reached. The output names the reason after `enroll_error`, for example `enroll_error invalid_enrollment_key`.                                                                                                                                                                                                                                                                                                                            |
| 5    | Refused because `/Users/Shared/MSPilot` could not be made safe to use.                                                                                                                                                                                                                                                                                                                                                                                                                       |

Later retries and daily updates log to `/Library/Logs/MSPilot/enroll-retry.log` and `/Library/Logs/MSPilot/update.log`.

The agent's own exit 4, pending, never reaches the RMM. The script turns it into exit 0 and prints `mspilot_pending`.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Exit 5: refused /Users/Shared/MSPilot">
    `/Users/Shared` is writable by every user. Before the agent keeps state there, the script checks that `/Users/Shared/MSPilot` is a real folder owned by root. When it finds a symlink, a file, or a folder a user owns, it moves it aside into `/Users/Shared/.MSPilot.stale.<random>` and creates a fresh folder. Exit 5 means the script could not move it aside (`refused: cannot move aside`), could not create the fresh folder (`refused: cannot create`), or found that the folder changed while it was setting it up (`changed during setup`). The agent does not run after a refusal.

    Run the script again. If it repeats, check what is at `/Users/Shared/MSPilot`: sign in as an administrator and run `ls -ldO /Users/Shared/MSPilot`, which shows the owner and any file flags. Rename or remove what is there, then run the script again.

    On an MDM install, `install.log` shows `mspilot_pkg_postinstall_exit rc=5` and `mspilot_pkg_postinstall_no_fallback reason=bootstrap_refused`. No retry job is set up after a refusal, so fix the folder, then deploy the package again from the MDM.
  </Accordion>

  <Accordion title="The job printed mspilot_pending">
    The gateway accepted the key and queued the Mac. It is waiting for approval at the seat cap, or for the RMM to report the Mac. The job still exits 0.

    Approve the Mac on the client's **Devices** tab, or raise **Seat cap** on **Deployment**. See [the FAQ](/faq). You do not run the script again. The enroll retry job tries every 15 minutes and finishes the enroll once the Mac is approved or reported. It then removes itself.
  </Accordion>

  <Accordion title="Exit 2: enroll must run as root">
    The RMM ran the script as the signed-in user. Set the script to run as root. NinjaOne and Syncro call this **System**, and Level calls it **Local system**. Then run it again.
  </Accordion>

  <Accordion title="Exit 3: invalid key or wrong region">
    `enroll_error wrong_region` means the key belongs to a different gateway region. `enroll_error invalid_enrollment_key` means the gateway does not accept the key: it is revoked or mistyped, or it was sent to another region's gateway. Regions do not share a database, so another region cannot look the key up.

    Copy the script again from the client's **Deployment** tab. That copy carries your organization's gateway URL and a live key. Do not edit the gateway URL by hand.

    When the gateway could not be reached, `enroll_error` is followed by the network error instead of a reason code. Run the script again once the Mac can reach the gateway.
  </Accordion>

  <Accordion title="Exit 1: Apple Silicon required">
    The Mac has an Intel processor. MSPilot supports Apple Silicon Macs only.
  </Accordion>
</AccordionGroup>

To take a Mac's seat back, open the client's **Devices** tab and choose **Disable** on that row. There is no macOS unenroll or uninstall script in Admin; the scripts under **Maintenance scripts** are Windows PowerShell only.
