- cayce-ops-plan.service/.timer (daily): the @ template cannot express publisher plan, so it gets its own unit - DECISIONS: D13 no non-human approvals; D14 signatures bind content + deployment; D15 negation veto classifier
systemd deployment (VPS)
This is the primary deployment path (docker-compose is for local dev).
sudo useradd -r -m -d /srv/cayce-ops cayce
rsync -a --exclude .venv ./ cayce@vm:/srv/cayce-ops/
sudo -u cayce uv sync --frozen
sudo -u cayce cayceops db upgrade # alembic to head
sudo cp deploy/systemd/cayce-ops@.service deploy/systemd/cayce-ops@.timer /etc/systemd/system/
# Every daemon has a `run` subcommand now:
# scanner run · executor run · maild run (poll + send-approved)
# publisher run (publish-due) · monitor run (build)
# cadence per daemon (edit OnCalendar in each timer copy):
# scanner hourly executor */10 min maild */5 min
# publisher */5 min monitor */1 min
# NOTE: `publisher plan` (fills the calendar) is a SEPARATE timer:
# OnCalendar=daily -> ExecStart=/srv/cayce-ops/.venv/bin/cayceops publisher plan
for d in scanner executor maild publisher monitor; do
sudo cp deploy/systemd/cayce-ops@.timer /etc/systemd/system/cayce-ops@$d.timer
done
# adjust OnCalendar per timer, then:
sudo systemctl daemon-reload
sudo systemctl enable --now cayce-ops@{scanner,executor,maild,publisher,monitor}.timer
The unit hardens the daemon (NoNewPrivileges, ProtectSystem=strict) and reads
secrets only from /srv/cayce-ops/.env (never in the repo).