install.md 12 KB

Installing OliveTin on macOS

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.adoc and macos_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.


1. Choose the right download

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.


2. Extract and place the binary

# 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.


3. Clear the Gatekeeper quarantine

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.


4. Create a configuration file

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

5. Run OliveTin

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.


6. Run OliveTin as a background service (launchd)

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:

  • LaunchAgent (local user) — runs as your user and starts when you log in. No sudo required, and everything lives under your home folder. Best for a desktop Mac. See Local user installation.
  • LaunchDaemon (system-wide) — runs as 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.

Local user installation (no root)

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. Replace YOUR_USERNAME with the output of whoami in 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/bootout replace the deprecated launchctl load/unload. They take a domain target: gui/$(id -u) is your own per-user GUI domain (id -u is 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

System-wide installation (requires root)

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.yaml in the directory given by the -configdir flag, which defaults to the current directory. The service definition below passes -configdir /usr/local/etc/OliveTin explicitly, and sets WorkingDirectory so the webui and var folders 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/bootout replace the deprecated launchctl load/unload. The domain target for a LaunchDaemon is system.

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

Troubleshooting

"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

  • Running in Terminal: the log is printed directly to the window.
  • Running under launchd as a local user: tail -f ~/Library/Logs/OliveTin/olivetin.log
  • Running under launchd system-wide: tail -f /usr/local/var/log/olivetin.log
  • You can raise detail by setting logLevel: "DEBUG" in config.yaml.

Still stuck? Ask in the OliveTin Discord or open an issue on GitHub.


Next steps