Files
zopu-code/deploy/vds/zopu-agents.service
2026-08-04 17:37:50 +05:30

73 lines
3.2 KiB
Desktop File

# zopu-agents.service — single Zopu intelligence runtime for the VDS.
#
# One process hosts both the Hono/Flue server and the AgentOS registry running
# in native envoy mode (Rivet Mode A):
#
# zopu-agents (this unit)
# └─ node /srv/zopu/current/packages/agents/dist/server.mjs
# ├─ Hono HTTP server on 127.0.0.1:3000
# ├─ Flue 2.0 conversation agents + SQLite at /srv/zopu/data/flue
# └─ AgentOS registry in envoy/native mode (registry.startAndWait)
#
# The AgentOS actor is hosted in-process: the Hono/Flue process is also the
# envoy that connects outbound to the Rivet Engine. There is no separate
# runner process and no Rivet HTTP handler route.
#
# The Rivet Engine is a SEPARATE private service on 127.0.0.1:6420, managed
# by its own unit/compose. This unit does not start or own it; it only waits
# for the engine health endpoint before binding (ExecStartPre below).
# RIVET_ENDPOINT is the engine control plane (http://127.0.0.1:6420).
#
# The release is a self-contained bundle under /srv/zopu/releases/<id> with
# /srv/zopu/current as the live symlink. This unit always runs `current`; the
# release script swaps it atomically, then the operator restarts this service.
[Unit]
Description=Zopu agents intelligence runtime (Hono + Flue + in-process envoy)
# Soft network ordering. The real gate on the separate Engine is the health
# probe in ExecStartPre. If the engine is itself a named systemd unit on this
# host, add an explicit ordering here, e.g.:
# After=rivet-engine.service
# Wants=rivet-engine.service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=zopu
Group=zopu
WorkingDirectory=/srv/zopu/current
# Secrets and runtime config live in /etc/zopu/agents.env (chmod 600, owner
# root:zopu). See agents.env.example for the full schema; never commit real
# values. NODE_ENV is pinned here so a release can never accidentally start in
# development mode.
Environment=NODE_ENV=production
EnvironmentFile=/etc/zopu/agents.env
# Wait for the separate Rivet Engine control plane to report healthy before
# binding. The engine is NOT managed by this unit; this probe is the startup
# dependency on its health. Bounded to ~60s.
ExecStartPre=/usr/bin/env bash -c 'i=0; until curl -fsS -o /dev/null http://127.0.0.1:6420/health; do i=$$((i+1)); [ "$$i" -ge 60 ] && { echo "rivet engine not healthy at http://127.0.0.1:6420/health" >&2; exit 1; }; sleep 1; done'
# Built release artifact. Node is the verified VDS install at
# /opt/zopu/node/bin/node (Node 24). PATH is anchored on that directory so the
# Node binary and its bundled toolchain (corepack/pnpm) resolve deterministically.
Environment=PATH=/opt/zopu/node/bin:/usr/local/bin:/usr/bin:/bin
ExecStart=/opt/zopu/node/bin/node /srv/zopu/current/packages/agents/dist/server.mjs
Restart=always
RestartSec=5
# --- Hardening ---------------------------------------------------------------
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
# Writable state: Flue SQLite + project workspaces. The release tree under
# /srv/zopu/current is treated read-only at runtime.
ReadWritePaths=/srv/zopu/workspaces /srv/zopu/data
[Install]
WantedBy=multi-user.target