Aegis Orchestrator
Deployment

Edge Daemon Installation

Install the AEGIS edge daemon on Linux (systemd user unit), macOS (launchd plist), or Windows (NSSM service), with the hardened service templates.

Edge Daemon Installation

The AEGIS edge daemon ships as part of the standard aegis CLI binary. Installation on a host is a two-step process: drop the binary in place, then register a service-manager unit so it runs in the background as a user service. This page documents the unit templates and platform-specific details.

This page is the deployment-reference view of the daemon binary and its host service-manager unit. It documents the install commands, the systemd / launchd / NSSM unit specs, and the hardening flags applied to each — independent of whether the daemon is enrolled against a self-hosted controller or against the Zaru SaaS Relay Coordinator.

Looking to enroll a daemon against MyZaru SaaS? The end-to-end Zaru SaaS flow — issuing an enrollment token from the Zaru Vault → Edge Hosts UI, redeeming it against relay.myzaru.com, and confirming the host appears connected — is documented at Edge Host Setup. This page covers the underlying binary and service-manager wiring that flow depends on.


Binary install

Linux (x86_64, aarch64)

curl -fsSL https://get.100monkeys.ai | bash

The installer drops aegis into /usr/local/bin (or ~/.local/bin if running unprivileged). Verify:

aegis --version
which aegis

For air-gapped installs, download the static binary tarball from the release artifact registry and extract into your preferred path.

macOS (x86_64, arm64)

brew install aegis-cli

Or via the install script (Homebrew not required):

curl -fsSL https://get.100monkeys.ai | bash

Windows (x86_64)

iwr -useb https://get.100monkeys.ai | iex

The installer drops aegis.exe into %LOCALAPPDATA%\Programs\aegis\, prepends it to user PATH, and registers the NSSM helper.


Service registration

aegis edge service install is the canonical entry point — it auto-detects the OS and writes the appropriate unit. The sections below show what it produces on each platform.

Linux — systemd user unit

Path: ~/.config/systemd/user/aegis-edge.service

[Unit]
Description=AEGIS Edge Daemon
Documentation=https://docs.100monkeys.ai/deployment/edge-daemon-installation
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
ExecStart=%h/.local/bin/aegis edge run --config %h/.aegis/edge/aegis-config.yaml
Restart=on-failure
RestartSec=5
TimeoutStartSec=30

# Hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=%h/.aegis/edge
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
SystemCallArchitectures=native

# Resource hints (override per host as needed)
LimitNOFILE=65535

[Install]
WantedBy=default.target

Enable lingering so the unit keeps running across logout:

loginctl enable-linger "$USER"
systemctl --user daemon-reload
systemctl --user enable --now aegis-edge.service

To check status:

systemctl --user status aegis-edge.service
journalctl --user -u aegis-edge.service -f

macOS — launchd plist

Path: ~/Library/LaunchAgents/io.aegis.edge.plist

<?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>io.aegis.edge</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/local/bin/aegis</string>
      <string>edge</string>
      <string>run</string>
      <string>--config</string>
      <string>/Users/USERNAME/.aegis/edge/aegis-config.yaml</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <dict>
      <key>SuccessfulExit</key>
      <false/>
      <key>NetworkState</key>
      <true/>
    </dict>
    <key>StandardOutPath</key>
    <string>/Users/USERNAME/.aegis/edge/logs/aegis-edge.out.log</string>
    <key>StandardErrorPath</key>
    <string>/Users/USERNAME/.aegis/edge/logs/aegis-edge.err.log</string>
  </dict>
</plist>

Load the plist:

launchctl load ~/Library/LaunchAgents/io.aegis.edge.plist
launchctl start io.aegis.edge

To check status:

launchctl list | grep io.aegis.edge
log show --predicate 'process == "aegis"' --last 10m

Windows — NSSM service

Path: managed by NSSM under the service name aegis-edge.

The NSSM descriptor template:

{
  "name": "aegis-edge",
  "displayName": "AEGIS Edge Daemon",
  "description": "AEGIS edge daemon — receives MCP tool calls via SEAL.",
  "executable": "%LOCALAPPDATA%\\Programs\\aegis\\aegis.exe",
  "arguments": "edge run --config %USERPROFILE%\\.aegis\\edge\\aegis-config.yaml",
  "startup": "automatic",
  "stdout": "%USERPROFILE%\\.aegis\\edge\\logs\\aegis-edge.out.log",
  "stderr": "%USERPROFILE%\\.aegis\\edge\\logs\\aegis-edge.err.log",
  "rotateLogs": true,
  "rotateLogsBytes": 10485760
}

Install and start:

aegis edge service install
Start-Service aegis-edge
Get-Service aegis-edge

Local state layout

Wherever the daemon runs, the on-disk layout under ~/.aegis/edge/ is the same:

~/.aegis/edge/
├── aegis-config.yaml          # merged hierarchical config
├── node.key                   # Ed25519 private key (mode 0600)
├── node.key.pub
├── node.token                 # NodeSecurityToken
├── enrollment.jwt             # short-lived; consumed once by enroll
├── logs/                      # service-manager log destination
├── secrets/                   # local KV store (mode 0700)
└── archive/                   # rotated keys retained during overlap window

Permission expectations:

PathMode
~/.aegis/edge/0700
~/.aegis/edge/secrets/0700
~/.aegis/edge/node.key0600
~/.aegis/edge/node.token0600
Everything else0644 (default)

aegis edge enroll enforces these on bootstrap; if the daemon detects a mode that's too permissive at startup, it logs a warning and chmods to the expected mode.


Network requirements

DirectionPortDestination
Outbound443relay.myzaru.com (SaaS) or your controller endpoint (OSS)
InboundnoneThe daemon does not bind any listening port

The daemon multiplexes all traffic — heartbeats, capability updates, command results, command progress streams — over a single long-lived h2 gRPC connection. There is no ancillary fallback channel and no peer-to-peer.

For corporate networks: the daemon respects standard HTTPS_PROXY, https_proxy, and NO_PROXY environment variables when it dials the controller. Set them in the service unit's Environment= directives (Linux) or via launchctl setenv (macOS) if your network requires a proxy.


Resource footprint

ResourceIdleActive (one in-flight tool call)
CPU≤1% of one coreBounded by the tool itself
RSS~30–50 MB+20–40 MB for the gRPC streaming machinery
Disk (state)~few KB+log volume
Network≤1 KB/s heartbeatsBounded by tool I/O

The daemon is small — it is a thin SEAL/gRPC wrapper around the existing AEGIS executor. The footprint is dominated by whatever tool runs underneath.


Updating the daemon

Updates ship as a new aegis CLI binary. To upgrade:

  1. Replace the binary (re-run the install script, brew upgrade aegis-cli, or the Windows installer).
  2. Restart the service:
    • Linux: systemctl --user restart aegis-edge.service
    • macOS: launchctl kickstart -k gui/$UID/io.aegis.edge
    • Windows: Restart-Service aegis-edge

The active gRPC stream is dropped; the daemon reconnects with the existing key and token. Tools that were in flight are reported back as EdgeDisconnected to the dispatcher.

For rolling fleet upgrades, see edge operational patterns.


Uninstalling

aegis edge logout              # local revocation: deletes node.token, node.key
aegis edge service uninstall   # removes the service unit / plist / NSSM entry
rm -rf ~/.aegis/edge           # purge any remaining state

The remote EdgeDaemon row remains in the controller until an operator runs aegis edge keys revoke-remote <node-id> (or it cascades from tenant deletion). Uninstalling the local daemon does not by itself revoke the binding — but the daemon will never reconnect, so the row will appear Disconnected indefinitely.


What's next

On this page