Systemd (non-NixOS)
For hosts without the NixOS module, the unit below is a
drop-in that mirrors what the module generates with
services.omw.hardening = true (in the repo: assets/omw.service):
[Unit]
Description=OMW agent runtime
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=omw
Group=omw
WorkingDirectory=/var/lib/omw
EnvironmentFile=/etc/omw/env
ExecStart=/usr/local/bin/omw loop --config /etc/omw/omw.toml
Restart=on-failure
RestartSec=5s
StateDirectory=omw
# Systemd sandboxing. Mirrors `services.omw.hardening = true` from the NixOS
# module. `MemoryDenyWriteExecute` is deliberately absent: it would break the
# wasmtime JIT and nodejs MCP servers. `PrivateDevices=false` keeps /dev
# usable for MCP servers and bwrap wrappers. `LimitMEMLOCK=infinity` is
# required: secrets are mlock()ed and the empty `CapabilityBoundingSet`
# drops CAP_IPC_LOCK, so a zero memlock limit would fail every secret with
# EPERM. Add `BindReadOnlyPaths=` entries if brains or the config live outside
# /var/lib/omw, and `ReadWritePaths=` entries for filesystem MCP workspaces
# outside the state directory.
NoNewPrivileges=true
PrivateDevices=false
PrivateIPC=true
ProtectClock=true
ProtectControlGroups=true
ProtectHome=true
ProtectKernelModules=true
ProtectProc=invisible
ProtectSystem=strict
RemoveIPC=true
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
SystemCallArchitectures=native
UMask=0077
LimitMEMLOCK=infinity
CapabilityBoundingSet=
AmbientCapabilities=
[Install]
WantedBy=multi-user.target
Install it (the assets/… paths are repo-relative):
sudo useradd -r -d /var/lib/omw omw
sudo install -m 644 assets/omw.service /etc/systemd/system/omw.service
sudo mkdir -p /etc/omw
sudo install -m 600 assets/omw.example.toml /etc/omw/omw.toml
sudo install -m 600 assets/omw.example.env /etc/omw/env
sudo systemctl daemon-reload
sudo systemctl enable --now omw
Secrets live in /etc/omw/env as OMW__-prefixed variables (see the
deployment overview); they layer over /etc/omw/omw.toml at
runtime. Put brains and the filesystem tooling workspace under /var/lib/omw
(the unit’s StateDirectory + WorkingDirectory).
Hardening
The unit carries the same sandbox as the NixOS module (see the NixOS module for the rationale):
NoNewPrivileges,RestrictSUIDSGID,RestrictRealtime,LockPersonality, empty capability sets plusLimitMEMLOCK=infinity(for allowing secret protection against swapping) — safe, and compatible withbwrap-wrapped MCP servers.ProtectSystem=strict+ProtectHome+ProtectProc=invisible+PrivateIPC— the filesystem is read-only outside API mounts and the state directory; allow-list extras withBindReadOnlyPaths=(brains or config outside/var/lib/omw) andReadWritePaths=(filesystem MCP workspaces elsewhere).RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6— provider egress plus local stdio MCP sockets.MemoryDenyWriteExecuteis deliberately absent: it would break the wasmtime JIT and nodejs MCP servers.PrivateDevices=falsekeeps/devusable for MCP servers andbwrapwrappers.