Cursor Agent b5b88db862 feat(ops): auto-deploy evOo-local on Evo with health check and rollback
Add idempotent deploy helper and GitHub workflow that runs on the
self-hosted Evo runner (no SSH secrets). Pulls main or a pinned SHA,
migrates, restarts via systemd/tmux/compose, probes :3100/:5173, and
resets on health failure.

Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
2026-09-23 22:58:14 +00:00

5.0 KiB

Evo auto-deploy (evOo-local)

Idempotent deploy helper for the source checkout on the Evo host (~/Projects/evOo-local, user cynar). Pulls main (or a pinned SHA), runs migrations, restarts the existing stack, health-checks API :3100 and web :5173, and rolls back on failure.

This is separate from production Docker deploys under /srv/rakazo (see docs/self-host.md and .github/workflows/ci.yml deploy-production).

Prerequisites on Evo

  1. Git checkout at ~/Projects/evOo-local (or set EVO_DEPLOY_DIR).
  2. .env with a working DATABASE_URL (Postgres reachable for pnpm db:migrate).
  3. A restart path the script can use (pick one):
    • systemd (recommended for unattended deploy): user unit, e.g. evoo-local.service, that starts pnpm dev or your stack wrapper. Set repo variable EVO_SYSTEMD_UNIT.
    • tmux: session evoo running pnpm dev (matches scripts/start-tmux.sh on Mac; on Evo set EVO_TMUX_SESSION if different).
    • compose: infra/compose/docker-compose.yml with api / web / worker (dev stack).
    • script: executable hook at EVO_RESTART_SCRIPT.
  4. Self-hosted GitHub Actions runner on Evo with labels [self-hosted, evoo-ci, Linux] (already used by CI).

No SSH keys or deploy secrets are stored in this repo. The workflow runs on the Evo runner against the local checkout.

Enable the workflow

  1. Merge this PR (or copy ops/evo-deploy/ and .github/workflows/evo-deploy.yml to main).
  2. In GitHub → Settings → Secrets and variables → Actions → Variables for cynarAI/evOo-local:
    • EVO_DEPLOY_ENABLED = true
    • Optional: EVO_DEPLOY_DIR (default ~/Projects/evOo-local on the runner user)
    • Optional: EVO_RESTART_MODE (auto, systemd, tmux, compose, script, none)
    • Optional: EVO_SYSTEMD_UNIT, EVO_TMUX_SESSION, health URLs, timeouts
  3. Confirm the runner user can read/write EVO_DEPLOY_DIR and restart services (systemctl --user or tmux).

Until EVO_DEPLOY_ENABLED is true, pushes to main do not deploy (workflow job is skipped).

Manual / dry-run

On Evo (or any machine with the checkout and stack):

cd ~/Projects/evOo-local

# Show what would happen (no git reset, migrate, restart, or health wait)
bash ops/evo-deploy/deploy.sh --dry-run

# Deploy main tip
bash ops/evo-deploy/deploy.sh

# Pin a SHA
EVO_DEPLOY_REF=abc1234 bash ops/evo-deploy/deploy.sh

# Force systemd restart
EVO_RESTART_MODE=systemd EVO_SYSTEMD_UNIT=evoo-local.service bash ops/evo-deploy/deploy.sh

GitHub: Actions → evo-deploy → Run workflow (optional ref, dry_run, skip_migrate).

Rollback behavior

  1. Before git fetch, the script records previousSha (current HEAD).
  2. After pull, migrate, and restart, it waits up to EVO_HEALTH_TIMEOUT_SEC (default 120s) for:
    • EVO_API_HEALTH_URL (default http://127.0.0.1:3100/health)
    • EVO_WEB_HEALTH_URL (default http://127.0.0.1:5173/)
  3. On failure: git reset --hard to previousSha, restart services again, exit non-zero.
  4. Last outcome is written to .evo-deploy/state.json under the checkout.

Manual rollback to a known good SHA:

cd ~/Projects/evOo-local
git reset --hard <good-sha>
EVO_RESTART_MODE=systemd EVO_SYSTEMD_UNIT=evoo-local.service bash ops/evo-deploy/deploy.sh --skip-migrate --ref HEAD

(or restart your unit/tmux session by hand, then verify health URLs).

Autopilot / Grok Bot after merge

After a PR merges to main:

  1. Preferred: rely on the evo-deploy workflow (once EVO_DEPLOY_ENABLED=true). No SSH step required.
  2. Fallback (manual): SSH to Evo and run:
    cd ~/Projects/evOo-local && bash ops/evo-deploy/deploy.sh
    
  3. Verify: API curl -fsS http://127.0.0.1:3100/health, web curl -fsS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:5173/.

Do not commit host passwords, tokens, or SSH private keys. Configure restart targets via repo variables or env on the runner host only.

Environment reference

Variable Default Purpose
EVO_DEPLOY_DIR $HOME/Projects/evOo-local Git checkout root
EVO_DEPLOY_REF main Branch name or commit SHA
EVO_RESTART_MODE auto systemd / tmux / compose / script / none
EVO_SYSTEMD_UNIT (empty) Required for systemd mode
EVO_SYSTEMD_SCOPE user user or system
EVO_TMUX_SESSION evoo tmux session name
EVO_TMUX_COMMAND pnpm dev Command started in new tmux session
EVO_MIGRATE true Run pnpm db:generate + pnpm db:migrate
EVO_INSTALL true Run pnpm install --frozen-lockfile after checkout
EVO_API_HEALTH_URL http://127.0.0.1:3100/health API health probe
EVO_WEB_HEALTH_URL http://127.0.0.1:5173/ Web health probe
EVO_HEALTH_TIMEOUT_SEC 120 Per-check timeout (seconds)

If EVO_RESTART_MODE=auto cannot detect systemd, tmux, compose, or a restart script, deploy fails with a clear error — set EVO_RESTART_MODE and the matching unit/session explicitly.