Thane ships as a single Go binary with production-grade service definitions for macOS and Linux. Go's cross-compilation means Thane runs anywhere — these are the platforms with tested service configs today.
User launch agent — zero sudo required.
For production use, create a dedicated macOS user account for Thane
(standard or administrator). This keeps Thane's data, config, and runtime
isolated from your personal account. Everything lives under ~/Thane/ in
that user's home directory — Finder-visible, easy to inspect and back up.
just install # -> ~/Thane/bin/thane
just service-install # -> ~/Library/LaunchAgents/info.nugget.thane.plist
launchctl load ~/Library/LaunchAgents/info.nugget.thane.plist
just logs # Tail ~/Thane/thane.logYou must grant Local Network permission in System Settings > Privacy & Security > Local Network for Thane to access LAN services like Home Assistant and Ollama.
macOS silently blocks unsigned binaries from accessing LAN hosts. This was
a tricky diagnosis — see
issue #53. The
justfile ad-hoc signs macOS builds (codesign -s -) to reduce friction,
and the release recipes can use a Developer ID Application certificate,
a Developer ID Installer certificate, notarytool, and stapler when
THANE_CODESIGN_IDENTITY, THANE_INSTALLER_IDENTITY, and
THANE_NOTARY_PROFILE are configured. The Local Network permission still
needs manual approval.
A native macOS companion app is in early development at thane-agent-macos. The companion app aims to simplify deployment on macOS — managing the Thane process, handling permissions, and providing a native menu bar presence.
systemd with dedicated service user and full security hardening:
sudo just install # -> /usr/local/bin/thane
sudo just service-install # Creates thane user, installs unit, enables service
sudo cp examples/config.example.yaml /etc/thane/config.yaml
# Edit /etc/thane/config.yaml with your settings
sudo systemctl start thaneThe systemd unit includes comprehensive sandboxing:
ProtectSystem=strict— read-only filesystem except allowed pathsNoNewPrivileges— no privilege escalationPrivateTmp— isolated temp directoryMemoryDenyWriteExecute— W^X enforcementSystemCallFilter— restricted syscalls- Dedicated user with no login shell
Thane listens on three ports (configurable):
| Port | Service | Required |
|---|---|---|
| 8080 | Native API + web dashboard | Yes |
| 11434 | Ollama-compatible API (for HA) | Yes |
| 8843 | CardDAV server | Optional (contact sync) |
Thane also needs outbound access to:
- Your Home Assistant instance (REST + WebSocket)
- Your MQTT broker
- Your Ollama instance (if on a different host)
- Anthropic API (if cloud models are configured)
Build for any supported target:
just build linux arm64 # Linux on ARM (e.g., Raspberry Pi 4)
just build linux amd64 # Linux on x86
just build darwin arm64 # macOS Apple Silicon
just build darwin amd64 # macOS Intel
just build-all # All release targetsRelease artifacts are prepared on a local macOS release workstation with the
just release recipes. That keeps Developer ID signing, installer packaging,
Apple notarization, and stapling in local control while still producing Linux
amd64 and arm64 artifacts for GitHub Releases. The macOS artifacts are
flat installer product archives that install thane into ~/Thane/bin for
the current macOS account, advertise the intended CPU family to Installer,
avoid a machine-wide admin prompt, and carry first-party
welcome/readme/license metadata for inspection. The tagged GitHub workflow
publishes the multi-arch container image and its provenance attestation.
For the human-facing operator workflows, see Release Engineering. The preferred paths are:
just release-github <version>for real GitHub releases from a clean main checkoutjust deploy-macos-pkg user@hostfor pkg-based live-host testing on another macOS Tahoe system
Thane also ships as a multi-arch container image on GHCR:
docker run --rm \
-p 8080:8080 \
-p 11434:11434 \
-v "$PWD/config:/config" \
-v thane-data:/data \
ghcr.io/nugget/thane-ai-agent:latest serveContainer conventions:
- Put your config at
/config/config.yaml - The container runs with
/dataas its working directory, so the defaultdata_dir: ./dbpersists to/data/db - If you override
data_dir, set it explicitly to a path under/dataif you want state on the mounted volume - Ensure the mounted
/datapath is writable by the non-rootthaneuser before first boot - Publish
8080for the native API and dashboard - Publish
11434for the Ollama-compatible Home Assistant endpoint