macOS Agent
The Hermes agent runs on Apple Silicon Macs as well as on Windows and Linux. On a Mac it
installs as a system LaunchDaemon called com.athena.hermes-agent, connects
to the server over the same secured agent connection as the rest of your fleet, and takes part in
inventory, software deployment, remote commands, compliance and agent updates. This page covers what you
need before you start, how to install it (interactively or unattended), where it keeps its files, how to manage it with
launchctl, what works on macOS and what doesn't, and how to troubleshoot and remove it.
Macs with Apple Silicon (M1 or later) are supported. Macs with an Intel processor are not: the server refuses an Intel agent file, and the installer stops on an Intel Mac before it changes anything. To check a Mac, open Apple menu → About This Mac — Apple Silicon Macs show Chip (for example Apple M1), Intel Macs show Processor.
Requirements#
- A Mac with Apple Silicon (M1 or later).
- An administrator account on the Mac that can use sudo — the installer must run as root.
- Network access from the Mac to the server on the API port (default 8443) and the agent port (default 8444). See Network Ports & Firewall.
- An Admin account in the console: the installer signs in with it to create its own registration token. For an unattended install, a registration token and an API token take its place.
- A macOS agent binary uploaded and active on the server (next section).
Upload the macOS agent binary#
Open Settings → Agents → Updates, set Operating System to macOS, choose the agent file and upload it, then make it active. See Agent Binaries & Updates for the general upload and activation flow.
- Upload the Apple Silicon (arm64) agent file itself — not a ZIP. A ZIP uploaded as macOS is refused.
- An Intel build is refused with Intel (x86_64) macOS agents are not supported; upload the Apple Silicon (arm64) build. A universal file is accepted only if it contains the Apple Silicon build; otherwise the message starts with Universal macOS binary has no Apple Silicon (arm64) slice.
- The downloadable install bundle (ZIP) is available for Windows only. On a macOS binary the bundle button is disabled with the tooltip macOS bundle coming soon — use the one-line installer.
- In PowerShell,
Send-AthenaAgentBinaryandGet-AthenaAgentBinaryacceptMacOSas the operating system. See PowerShell Module.
Install the agent#
In the console, open Settings → Agents → Configuration and, in the Agent Installer card (shown to Admins only), click macOS. If the button is disabled, no active macOS binary exists yet; the hint reads No macOS agent binary uploaded yet — upload one in Agent Binaries first. Copy the one-liner and run it in Terminal on the Mac. Like the Linux installer, it downloads first and then runs, so its prompts work:
curl -fsSLk https://<server>:8443/api/agent-binaries/install-script/macos -o /tmp/athena-macos-agent-install.sh && sudo bash /tmp/athena-macos-agent-install.sh
The installer then:
- Asks for the server host (pre-filled), the API port (default
8443), the Agent (gRPC) port (default8444), and your console Username and Password. The password is masked and is never written to the install log. - Checks that the certificate on the agent port belongs to this server and names the host you typed — before it sends your password. If it doesn't, it stops. Type a host name the server certificate lists rather than an IP address. See Server TLS Certificate.
- Signs in, finds the latest active macOS agent, and creates a single-use registration token
valid for 10 minutes, labelled
bootstrap: <hostname>. - Downloads the agent and checks its SHA-256 hash against the value the server reports; a mismatch or a file that isn't a Mac executable stops the install.
- Installs the agent and the server's CA certificate, signs the agent on the Mac (see below), writes its settings, installs the LaunchDaemon and starts it, then waits up to 20 seconds for it to be running.
Look for Agent installed - running in green. That message means the service is running
on the Mac — it doesn't ask the server — so confirm the Mac appears under Agents. If a
step fails, the script prints FAILED: <step> - <reason>, for example
FAILED: login - Login rejected …. A transcript is written to
/Library/Logs/Hermes/athena-install.log.
You can run the one-liner again on the same Mac: it stops and replaces the existing service and rewrites its settings with a fresh token.
The agent file is not signed by Apple. macOS will only start it once it carries a signature, so the installer removes the "downloaded from the internet" (quarantine) mark and gives the agent a local (ad-hoc) signature on that Mac. Every self-update signs the new file the same way.
Unattended install (no terminal)#
The one-liner above expects someone at a Terminal to answer its prompts. To install or reinstall the agent
where nobody is at the keyboard — from a script runner that executes as root, a one-shot LaunchDaemon, or an
Athena command sent to a Mac that is already enrolled — run the same installer script in
unattended mode. It turns on when the ATHENA_REGISTRATION_TOKEN environment
variable is set. The script then asks nothing, doesn't need a terminal, doesn't sign in with a username and
password, and doesn't create a registration token of its own.
Environment variables#
| Variable | Required | What it is |
|---|---|---|
ATHENA_REGISTRATION_TOKEN | Yes | An agent registration token. Setting it is what switches the script to unattended mode. The agent uses it to enroll. Create a short-lived one with a usage limit that matches the number of Macs. See Registration Tokens. |
ATHENA_API_TOKEN | Yes | An API token (ath_…). The script needs it to look up the latest macOS agent and download it, because a registration token can't do that. The token's owner must hold binaries.view and binaries.manage. Limit the token to those two permissions. |
ATHENA_HOST | No | Server host name. Defaults to the host built into the script when the server serves it — the same value the interactive prompt pre-fills. |
ATHENA_API_PORT | No | API port. Default 8443. |
ATHENA_AGENT_PORT | No | Agent (gRPC) port. Default 8444. |
If the host or the API token is missing, the script stops before it contacts the server. Otherwise it runs
the same checks as an interactive install. It checks the API-port certificate and the agent-port certificate
before it sends the API token, and it checks the SHA-256 hash of the downloaded agent. Then it installs and
signs the agent, writes your registration token into the agent's settings, and starts the LaunchDaemon. The
transcript goes to /Library/Logs/Hermes/athena-install.log, as in an interactive run. Without
ATHENA_REGISTRATION_TOKEN, the script behaves exactly as described in
Install the agent.
Prepare the two tokens#
In PowerShell, connected to the server with an account that may create both kinds of token:
# Registration token: one use, valid for one hour
$reg = New-AthenaRegistrationToken -Description "mac unattended: mac-042" -ValidityHours 1 -MaxUsages 1
# API token for the binary download: one day, only the two permissions it needs
$api = New-AthenaApiToken -Name "mac unattended install" -ExpiresInDays 1 -Permission binaries.view, binaries.manage
You can also create them in the console: a registration token under Settings → Security → Token, and an API token from your Profile. For several Macs, raise the registration token's usage limit. A single API token can serve the whole batch until it expires.
Run it#
From any process that already runs as root, download the script and run it with the variables set. To
download it, use the fetch part of the console one-liner. When the server can pin its certificate, that
fetch pins it with --pinnedpubkey, so the script body is protected too.
curl -fsSLk https://<server>:8443/api/agent-binaries/install-script/macos -o /tmp/athena-macos-agent-install.sh
ATHENA_REGISTRATION_TOKEN='<registration token>' \
ATHENA_API_TOKEN='ath_<api token>' \
/bin/bash /tmp/athena-macos-agent-install.sh
Reinstalling from an Athena command#
The installer stops and replaces the agent service that is already running on the Mac. If you start the
installer straight from a command sent to that agent, it stops the agent that is running it. Instead, let
the command start a one-shot LaunchDaemon that runs the installer on its own, and return
straight away. Send this as a command to the Mac. Commands run as root, under /bin/zsh:
cat > /tmp/com.athena.reinstall.plist <<'EOF'
<?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>com.athena.reinstall</string>
<key>ProgramArguments</key><array><string>/bin/bash</string><string>-c</string>
<string>curl -fsS --insecure -o /tmp/athena-install.sh https://athena.example.com:8443/api/agent-binaries/install-script/macos && /bin/bash /tmp/athena-install.sh</string></array>
<key>EnvironmentVariables</key><dict>
<key>ATHENA_REGISTRATION_TOKEN</key><string>REG_TOKEN_HERE</string>
<key>ATHENA_API_TOKEN</key><string>ath_API_TOKEN_HERE</string>
</dict>
<key>RunAtLoad</key><true/>
<key>StandardOutPath</key><string>/tmp/athena-reinstall.log</string>
<key>StandardErrorPath</key><string>/tmp/athena-reinstall.log</string>
</dict></plist>
EOF
chown root:wheel /tmp/com.athena.reinstall.plist && chmod 600 /tmp/com.athena.reinstall.plist
launchctl bootout system/com.athena.reinstall 2>/dev/null; launchctl bootstrap system /tmp/com.athena.reinstall.plist
Replace the host and the two token placeholders. In the plist, && must be written as
&&, as shown. Because --insecure skips certificate checks on this
download, the script body itself isn't verified. The script then pins the API-port certificate before it
sends the API token. To protect the download too, use -k --pinnedpubkey sha256//… from the
console one-liner in its place. Progress is written to /tmp/athena-reinstall.log and to the
installer transcript.
Both tokens appear in plain text in the command and in the plist. After the Mac shows up under
Agents, unload and delete the one-shot job, and revoke the API token (for example with
Revoke-AthenaApiToken):
sudo launchctl bootout system/com.athena.reinstall
sudo rm -f /tmp/com.athena.reinstall.plist /tmp/athena-install.sh
Only the macOS installer script has unattended mode. The Linux and Windows one-line installers still prompt for their settings. On Windows, use the install bundle for installs where nobody is at the keyboard.
Files & service layout#
| Path | What it holds |
|---|---|
/Library/Application Support/Hermes/ | Program and data folder — the agent (Hermes.Agent), its appsettings.json, local state, and the per-server certificates under servers/. |
/Library/Application Support/Hermes/deployments/ | Working area where deployment packages are staged and run. |
/Library/Logs/Hermes/ | Daily agent logs (hermes-YYYYMMDD.log, 30 days kept), plus stdout.log and stderr.log from launchd. |
/Library/Logs/Hermes/athena-install.log | Transcript from the one-line installer. |
/Library/LaunchDaemons/com.athena.hermes-agent.plist | The LaunchDaemon that runs the agent as root. |
appsettings.json is created readable by root only, because it holds the registration token
until the Mac has enrolled. The agent keeps its connection certificate as a file in its data folder, not in
the macOS keychain. For the settings inside appsettings.json, see
Agent Configuration File.
Managing the service#
The LaunchDaemon starts at boot and is kept alive: launchd starts the agent again whenever it exits,
waiting at least 10 seconds between starts. Manage it with launchctl in the
system domain:
# Status (look for "state = running" and the pid)
sudo launchctl print system/com.athena.hermes-agent | grep -E "state =|pid ="
# Restart
sudo launchctl kickstart -k system/com.athena.hermes-agent
# Stop and unload (stays stopped until loaded again or the Mac restarts)
sudo launchctl bootout system/com.athena.hermes-agent
# Load and start again
sudo launchctl bootstrap system /Library/LaunchDaemons/com.athena.hermes-agent.plist
Viewing logs#
# Follow the agent log
tail -f /Library/Logs/Hermes/hermes-*.log
# If the service keeps restarting, read launchd's error output too
tail -50 /Library/Logs/Hermes/stderr.log
What works on macOS#
| Capability | On a Mac |
|---|---|
| Inventory | Operating system, hardware, processors, memory, storage and physical disks, network interfaces and shares, installed software, services (launchd jobs), environment variables, local groups, containers, boot & security, and pending software updates. See Inventory on a Mac. |
| Software Updates | The agent's updates section is titled Software Updates on a Mac and lists pending updates reported by macOS. See below. |
| Software deployment | Runs deployment packages with the step types listed in Deployments on a Mac. |
| Remote commands | Runs ad-hoc commands and scripts. See Shells and Remote Command Execution. |
| Services | Lists launchd jobs (including disabled ones) and starts, stops, restarts, enables and disables them. See Remote Services Control. |
| File browser | Starts at /. Some private user folders need Full Disk Access (see below). See Remote File Browser. |
| Compliance | Evaluates assigned baselines and reports results. See Compliance & Baselines. |
| FileVault recovery key | With agent 1.2.123 or later, escrow, rotate and reveal the Mac's FileVault personal recovery key from its FileVault tab. Licensed with BitLocker. See FileVault Recovery-Key Escrow. |
| Agent updates | Push a newer macOS binary or let automatic updates do it, as on the other systems. See Updates & signing. |
| Not available | The built-in screen share is Windows-only, so its button isn't shown for a Mac. BitLocker, Sysmon and Power Management are Windows-only policies and don't apply to Macs. |
Inventory on a Mac#
Mac inventory comes from the standard macOS tools — for example system_profiler for hardware
and applications, pkgutil for installed packages, diskutil for disks,
launchctl for services, and dscl for local groups. It feeds the same Inventory
views, Collections and Reports as your Windows and Linux machines. On a Mac, the
Boot & Security view adds Mac rows such as System
Integrity Protection, FileVault, Gatekeeper, the firewall, and MDM enrollment.
Software Updates#
The agent asks macOS for available updates (softwareupdate --list) and caches the answer for
6 hours, because the check contacts Apple's servers. The Software Updates section shows
pending updates only: there is no installed-update history, no KB column and no release date, and a
Details column shows the version and restart note macOS reports. Linux agents have no
updates section. For Windows update management, see Windows Update
Management.
Deployments on a Mac#
| Step type | On a Mac |
|---|---|
| Install Application | Installs a .pkg or .mpkg with macOS's installer. For a .dmg it mounts the image read-only, installs the first .pkg inside — or, if there is none, copies the first .app to /Applications — and always unmounts it. Any other file type fails. A package that asks for a restart is not restarted for you; add a Reboot step. |
| Uninstall | Not supported — macOS has no package manager that removes a package's files. The step fails with that reason; use a Run Command or Shell step with the vendor's uninstaller instead. |
| Run Command, Shell | Run under /bin/bash. |
| Start / Stop / Restart Service | Act on launchd jobs. |
| Copy Files, Reboot, Wait, Trigger Inventory | Supported. |
| PowerShell, Batch | Not supported — the step fails with a message to use a Shell step instead. |
- Step OS condition: mark a step for Macs with the macOS option. A Mac never matches a Linux-only step, so Linux steps are skipped on Macs. See Deployment Package Steps.
- Run As a stored credential is not supported on a Mac. Such a step is refused and is not run — it never falls back to running as root.
Shells#
Ad-hoc commands from the console run under /bin/zsh, the default macOS shell (falling back to
bash, then sh). Python commands run with python3 (or python if /usr/bin/python3 is missing). Deployment Shell and
Run Command steps run under /bin/bash, which on macOS is bash 3.2 — keep
scripts for those steps compatible with it.
Updates & signing#
Upload a newer macOS binary in Settings → Agents → Updates and push it, or let automatic
updates and staged rollouts deliver it. On the Mac, the agent stages the
new file, removes its quarantine mark and signs it locally, keeps a copy of the old agent as
Hermes.Agent.backup, swaps the new file in, and restarts itself through launchd.
Full Disk Access (optional)#
Inventory, commands, package installs and updates work without Full Disk Access. Without it the agent
can't read some private user folders — such as Mail, Messages, Safari data and parts of Desktop, Documents
and Downloads — so the file browser is denied there. To allow it, open System Settings → Privacy
& Security → Full Disk Access, click + and add
/Library/Application Support/Hermes/Hermes.Agent.
Because the agent is signed on the Mac, macOS treats each updated agent as a new program and drops the Full Disk Access grant after every update. Add it again if you rely on it.
Troubleshooting#
"This Mac has an Intel processor. Athena supports Apple Silicon Macs only."#
The installer stopped at its platform check before changing anything. The agent can't be installed on an Intel Mac.
"Run with sudo."#
The script was not run as root. Run the one-liner as shown (it includes sudo) from an administrator account.
The macOS button in Agent Installer is disabled#
No active macOS agent binary exists. Upload one and make it active.
The agent stops with "Killed: 9"#
macOS refused to start the agent because its signature is missing or broken — usually because the file was copied or changed by hand. Re-sign it and restart the service:
sudo codesign --force -s - "/Library/Application Support/Hermes/Hermes.Agent"
sudo launchctl kickstart -k system/com.athena.hermes-agent
A Mac agent stopped connecting after an update#
Mac agents before version 1.2.116 kept their connection key in the System keychain, tied to
that exact agent file. After a self-update the new file can't use the key, every connection fails, and the
agent log shows AppleCrypto+SslException: Internal error. Because the agent can't reach the
server, repair it on the Mac:
- List the identities in the System keychain and note the SHA-1 thumbprint of the agent's identity:
sudo security find-identity -v /Library/Keychains/System.keychain - Delete that identity and restart the agent:
sudo security delete-identity -Z <thumbprint> /Library/Keychains/System.keychain sudo launchctl kickstart -k system/com.athena.hermes-agent - When the agent is back online, push version 1.2.116 or later to it straight away, then repeat step 2 once more. From 1.2.116 the agent no longer uses the System keychain.
Unattended install fails at "unattended settings"#
FAILED: unattended settings - ATHENA_HOST is not set and this script carries no server host: setATHENA_HOST.FAILED: unattended settings - ATHENA_API_TOKEN is not set …: unattended mode needs an API token as well as the registration token. See Environment variables.FAILED: resolve latest binary - no active MacOS agent binary on the serverwhen a macOS binary is active: the API token was rejected or lacksbinaries.view. Check that it isn't expired or revoked and that its scope includesbinaries.view.FAILED: download binary - download failed … (HTTP 403): the API token lacksbinaries.manage.No interactive terminal. Re-run with the one-liner …:ATHENA_REGISTRATION_TOKENwas not set in the script's environment, so the script fell back to interactive mode. Withsudo, pass the variables aftersudo(for examplesudo ATHENA_REGISTRATION_TOKEN=… ATHENA_API_TOKEN=… bash …), becausesudonormally drops your environment.
The service runs but the Mac never appears#
- Check that the Mac reaches the agent port:
nc -vz <server> 8444. - Read
/Library/Logs/Hermes/hermes-*.logfor the reason — most often a token that expired or was already used, a server name the Mac can't resolve, or a licence that is missing, expired or at its agent limit. - Run the one-liner again; it writes a fresh single-use token.
Removing the agent#
Run these in Terminal on the Mac. They stop the service and remove the agent; the logs in
/Library/Logs/Hermes are kept.
sudo launchctl bootout system/com.athena.hermes-agent
sudo rm -f /Library/LaunchDaemons/com.athena.hermes-agent.plist
sudo rm -rf "/Library/Application Support/Hermes"
# Remove the hermescli link, but only if it points to the agent's CLI
[ "$(readlink /usr/local/bin/hermescli)" = "/Library/Application Support/Hermes/HermesCLI" ] && sudo rm -f /usr/local/bin/hermescli
The Mac stays listed in Agents until you remove it there. See Retiring & Removing Agents. To enroll it again later, run the installer again — it registers the Mac as a new agent.
Related#
- Agent Enrollment — generating installers and enrolling hosts.
- Agent Binaries & Updates — uploading and promoting agent builds.
- Windows Agent and Linux Agent — the other platforms.
- Deployment Package Steps — step types and OS conditions.
- Network Ports & Firewall — ports the agent needs.