Draft — local Markdown draft kept in sync with the AsciiDoc docs at https://docs.olivetin.app/install/macos.html and https://docs.olivetin.app/install/macos_service.html (
docs/modules/ROOT/pages/install/macos.adocandmacos_service.adoc).
OliveTin runs natively on macOS on both Apple Silicon (M1/M2/M3/M4) and Intel Macs. It is a single self-contained binary written in Go — there is no installer and no background dependencies to install.
macOS builds are published on the GitHub releases page. Pick the archive that matches your Mac's processor:
| Your Mac | Archive |
|---|---|
| Apple Silicon (M-series) | OliveTin-darwin-arm64.tar.gz |
| Intel | OliveTin-darwin-amd64.tar.gz |
Not sure which you have? Run this in Terminal:
uname -m
arm64 → Apple Silicon, x86_64 → Intel.
If you download the wrong architecture, macOS will refuse to run it with a "Bad CPU type in executable" error.
# Move to your Downloads folder (adjust if needed)
cd ~/Downloads
# Extract — replace arm64 with amd64 on Intel
tar -xzf OliveTin-darwin-arm64.tar.gz
cd OliveTin-darwin-arm64
For a quick try-out you can run it straight from this folder. To install it properly, see step 6 — you can install it as your own user (no root) or system-wide.
Because the binary is downloaded from the internet and is not notarized by Apple, macOS Gatekeeper will block the first run with a message like "OliveTin can't be opened because Apple cannot check it for malicious software."
Remove the quarantine attribute so it will run:
xattr -dr com.apple.quarantine ./OliveTin
Alternatively, the first time only, you can right-click the binary in Finder → Open, or approve it under System Settings → Privacy & Security.
OliveTin looks for a file named config.yaml in its config directory, which
defaults to the current directory (.). You can point elsewhere with
-configdir /path/to/dir.
A minimal config.yaml to confirm everything works:
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
logLevel: "INFO"
actions:
- title: Hello macOS
icon: terminal
shell: echo "Hello from $(scutil --get ComputerName)!"
popupOnStart: execution-dialog-stdout-only
For a fuller, macOS-tuned starting point — with working examples for
notifications (osascript), caffeinate, pmset, disk usage, the unified
system log, and Docker — see the config.macos.yaml that ships alongside
this guide. Copy it in place with:
cp config.macos.yaml config.yaml
From the folder that contains both OliveTin and config.yaml:
./OliveTin
Then open the web interface at:
http://localhost:1337
(or http://<your-mac-hostname>:1337 from another device on your network).
Press Ctrl-C in the Terminal to stop it.
On Linux, OliveTin is managed by systemd. The macOS equivalent is launchd. launchd offers two ways to run a background service, and which one you pick decides whether you need root:
sudo required, and everything lives under your home folder. Best for a
desktop Mac. See Local user installation.root and starts at boot, before any
user logs in. Requires sudo. Best for a headless, always-on Mac. See
System-wide installation.You only need to follow one of the two sections below.
Everything — the binary, configuration, the var data folder, and the webui
folder — is kept together under ~/Library/Application Support/OliveTin, so you
never need sudo.
Install the files (run from the extracted archive directory):
# Create the application folder and a place for logs
mkdir -p ~/Library/Application\ Support/OliveTin/var
mkdir -p ~/Library/Logs/OliveTin
# Copy in the binary, your config, and the bundled web UI
cp OliveTin ~/Library/Application\ Support/OliveTin/
cp config.yaml ~/Library/Application\ Support/OliveTin/
cp -R webui ~/Library/Application\ Support/OliveTin/
This gives you the following layout, all owned by your user:
~/Library/Application Support/OliveTin/
├── OliveTin # the binary
├── config.yaml # your configuration
├── webui/ # the web interface assets (shipped in the archive)
└── var/ # runtime data OliveTin writes (logs, etc.)
~/Library/Logs/OliveTin/olivetin.log # service stdout/stderr
Create the service definition. Create a file named
app.olivetin.olivetin.plist with the contents below.
Important: launchd does not expand
~, so the paths must be absolute. ReplaceYOUR_USERNAMEwith the output ofwhoamiin every path.
<?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>app.olivetin.olivetin</string>
<key>ProgramArguments</key>
<array>
<string>/Users/YOUR_USERNAME/Library/Application Support/OliveTin/OliveTin</string>
<string>-configdir</string>
<string>/Users/YOUR_USERNAME/Library/Application Support/OliveTin</string>
</array>
<key>WorkingDirectory</key>
<string>/Users/YOUR_USERNAME/Library/Application Support/OliveTin</string>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/YOUR_USERNAME/Library/Logs/OliveTin/olivetin.log</string>
<key>StandardErrorPath</key>
<string>/Users/YOUR_USERNAME/Library/Logs/OliveTin/olivetin.log</string>
</dict>
</plist>
WorkingDirectory makes the relative webui and var folders resolve inside
the application folder, KeepAlive restarts OliveTin if it exits (like systemd's
Restart=always), and RunAtLoad starts it as soon as the service is loaded.
Register and start the service:
cp app.olivetin.olivetin.plist ~/Library/LaunchAgents/
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/app.olivetin.olivetin.plist
bootstrap/bootoutreplace the deprecatedlaunchctl load/unload. They take a domain target:gui/$(id -u)is your own per-user GUI domain (id -uis your numeric user ID).
To stop and disable it:
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/app.olivetin.olivetin.plist
Restart after a change. After editing config.yaml or replacing the
binary, restart the service so the change takes effect. To restart in place:
launchctl kickstart -k gui/$(id -u)/app.olivetin.olivetin
If you changed the plist itself, kickstart is not enough — boot the service
out and back in so launchd re-reads it (bootstrap errors if the service is
still loaded):
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/app.olivetin.olivetin.plist
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/app.olivetin.olivetin.plist
Verify — open http://localhost:1337. If the page does not load, check the service log:
tail -f ~/Library/Logs/OliveTin/olivetin.log
Use this for a headless or shared Mac that should start OliveTin at boot, before
anyone logs in. It installs the binary on the system PATH and runs as root
via a LaunchDaemon, so the commands use sudo.
Install the files:
sudo cp OliveTin /usr/local/bin/OliveTin
sudo mkdir -p /usr/local/etc/OliveTin
sudo cp config.yaml /usr/local/etc/OliveTin/config.yaml
sudo cp -R webui /usr/local/etc/OliveTin/
OliveTin looks for
config.yamlin the directory given by the-configdirflag, which defaults to the current directory. The service definition below passes-configdir /usr/local/etc/OliveTinexplicitly, and setsWorkingDirectoryso thewebuiandvarfolders resolve there.
Create the service definition. Create a file named
app.olivetin.olivetin.plist with the following contents. Adjust the paths if
you installed OliveTin elsewhere.
<?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>app.olivetin.olivetin</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/OliveTin</string>
<string>-configdir</string>
<string>/usr/local/etc/OliveTin</string>
</array>
<key>WorkingDirectory</key>
<string>/usr/local/etc/OliveTin</string>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>/usr/local/var/log/olivetin.log</string>
<key>StandardErrorPath</key>
<string>/usr/local/var/log/olivetin.log</string>
</dict>
</plist>
KeepAlive restarts OliveTin if it exits (like systemd's Restart=always), and
RunAtLoad starts it as soon as the service is loaded.
Register and start the service:
sudo mkdir -p /usr/local/var/log
sudo cp app.olivetin.olivetin.plist /Library/LaunchDaemons/
sudo chown root:wheel /Library/LaunchDaemons/app.olivetin.olivetin.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/app.olivetin.olivetin.plist
bootstrap/bootoutreplace the deprecatedlaunchctl load/unload. The domain target for a LaunchDaemon issystem.
To stop and disable it:
sudo launchctl bootout system /Library/LaunchDaemons/app.olivetin.olivetin.plist
Restart after a change. After editing config.yaml or replacing the
binary, restart the service so the change takes effect. To restart in place:
sudo launchctl kickstart -k system/app.olivetin.olivetin
If you changed the plist itself, kickstart is not enough — boot the service
out and back in so launchd re-reads it (bootstrap errors if the service is
still loaded):
sudo launchctl bootout system /Library/LaunchDaemons/app.olivetin.olivetin.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/app.olivetin.olivetin.plist
Verify — open http://localhost:1337. If the page does not load, check the service log:
tail -f /usr/local/var/log/olivetin.log
"Bad CPU type in executable" — you downloaded the wrong architecture. Get
the arm64 build for Apple Silicon, amd64 for Intel (see step 1).
Gatekeeper still blocks it — re-run the xattr -dr com.apple.quarantine
command in step 3, or approve the app under System Settings → Privacy &
Security.
It runs but the page won't load — check that nothing else is using port
1337 (lsof -i :1337), and that you're browsing to http:// (not https://).
Reading the logs
tail -f ~/Library/Logs/OliveTin/olivetin.logtail -f /usr/local/var/log/olivetin.loglogLevel: "DEBUG" in config.yaml.Still stuck? Ask in the OliveTin Discord or open an issue on GitHub.