SPB Git

Repository Public

deployment.md 6.6 KB 109 lines markdown

1# Deployment — agent.spboucher.ai on MacLustr23Agent OS is deployed like every other MacLustr app: a manifest on the gateway (M1M32), `mld` picks /4syncs / builds / starts with PM2, and the MacLustr Tunnel (Caddy on BHS64) publishes the domain.5Nothing here is specific to a node except the pin (default **M4M64c**).67| Item | Value |8|---|---|9| mld app | `agent-os` |10| Domain / port | `agent.spboucher.ai` → `<node>:8640` (health `GET /api/v1/health`) |11| App dir on the node | `~/apps/agent-os` (a git clone once adopted — remote-first) |12| Data dir | `~/agent-os-data` (setup token, artifacts under `artifacts/`, per-run temp dirs) |13| Workspace root | `~/agent-workspace` (one directory per project) |14| PostgreSQL 17 (local) | role and database `agent_os` |15| PM2 | `agent-os-server` (`apps/server/dist/main.js`), `agent-os-worker` (`apps/worker/dist/main.js`, `kill_timeout` 20000), `agent-os-backup` (cron 04:05, `deploy/backup.sh`) |16| Secrets | `~/apps/agent-os/.env` (0600): `DATABASE_URL`, `AOS_SECRET_KEY` (from the manifest) + provider keys appended from `~/.config/agent-os/keys.env` on the node |1718## Where each secret lives1920- **Database password, `AOS_SECRET_KEY`**: generated by `deploy/make-manifest.py` on the gateway, reused21  from the existing manifest on later runs, written to `.env` (0600) on the node by the `post_sync` hook.22  They are in the manifest (`M1M32:~/dispatch/apps/agent-os.json`, keep it 0600) and nowhere else. The23  PM2 environment holds **no** secret.24- **Provider keys** (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`): never pass through the gateway or the manifest.25  The operator creates `~/.config/agent-os/keys.env` (0600) **on the node**; `post_sync` appends it to26  `.env`. Changing a key = edit that file, redeploy (or append to `.env` by hand and restart both processes).27- **How the processes get them**: PM2 sets `AOS_ENV_FILE=~/apps/agent-os/.env`; `apps/server/src/main.ts`28  and `apps/worker/src/main.ts` load that file at start (`env-file.ts`: `KEY=VALUE`, `#` comments,29  optional quotes; a variable already set in the environment wins; no other file is ever read).30- The sandboxed shell cannot read `.env`: `~/apps` is in `AOS_SANDBOX_EXTRA_DENY_READ`, and `~/.config`31  is denied by the built-in profile.3233## Environment (names actually read by the code)3435| Variable | Read by | Value in production |36|---|---|---|37| `NODE_ENV` | server | `production` (enforces https origin, `DATABASE_URL`, 64-hex `AOS_SECRET_KEY`) |38| `DATABASE_URL` | server, worker, kernel, `migrate-cli` | `.env` |39| `AOS_SECRET_KEY` | server | `.env` (64 hex; AES-256-GCM key of TOTP secrets) |40| `AOS_DATA_DIR` | server, worker (must be absolute), kernel | `/Users/…/agent-os-data` |41| `AOS_WORKSPACE_ROOT` | server, worker, engine | `/Users/…/agent-workspace` |42| `AOS_PORT`, `AOS_HOST` | server | `8640`, `0.0.0.0` (reached by the tunnel over `wg1`) |43| `AOS_PUBLIC_ORIGIN` | server | `https://agent.spboucher.ai` |44| `AOS_TRUSTED_PROXIES` | server | `127.0.0.1,::1,10.67.0.1` |45| `AOS_WEB_DIR` | server | `~/apps/agent-os/apps/web/out` |46| `AOS_MAX_CONCURRENT_RUNS` | worker | `4` |47| `AOS_WORKER_ID` | worker | unset (hostname-pid) |48| `AOS_SANDBOX_EXTRA_DENY_READ` | engine (worker) | `~/apps,~/backups,~/Desktop,~/Documents,~/Downloads,~/dispatch,~/srv` as absolute paths |49| `AOS_ENV_FILE` | server, worker, `backup.sh` | `~/apps/agent-os/.env` |50| `AOS_LOG_LEVEL` | all | `info` |51| `ANTHROPIC_API_KEY`, `OPENAI_API_KEY` | providers (worker); server records presence only | `.env`, from `keys.env` |52| `AOS_MIGRATIONS_DIR` | kernel `migrate` | unset (found by walking up to `db/migrations`) |5354Audit result (2026-11-10): every name listed in `docs/CONTRACT.md` §1 is read under that name; no renamed55or dead name. Read but not listed there: `AOS_SANDBOX_EXTRA_DENY_READ`, `AOS_MIGRATIONS_DIR`,56`AOS_ENV_FILE`, `NODE_ENV`. Defaults differ between processes when a variable is unset (`AOS_DATA_DIR`:57server `~/agent-os-data`, kernel `$TMPDIR/aos-data`, worker refuses to start; `AOS_WORKSPACE_ROOT`:58server `~/workspace`) — the manifest sets both explicitly for both processes.5960## First deployment6162```bash63# 0. DNS (GoDaddy): A agent.spboucher.ai → 51.161.112.616465# 1. On the node (M4M64c): provider keys, never through the gateway66ssh M4M64c 'mkdir -p ~/.config/agent-os && chmod 700 ~/.config/agent-os && umask 077 && cat > ~/.config/agent-os/keys.env' <<'EOF'67ANTHROPIC_API_KEY=…68OPENAI_API_KEY=…69EOF7071# 2. Manifest, generated ON the gateway (secrets are created / reused there)72scp deploy/make-manifest.py M1M32:/tmp/agent-os-make-manifest.py73ssh M1M32 'python3 /tmp/agent-os-make-manifest.py --node M4M64c > ~/dispatch/apps/agent-os.json.new \74  && mv ~/dispatch/apps/agent-os.json.new ~/dispatch/apps/agent-os.json && chmod 600 ~/dispatch/apps/agent-os.json'75#    (write to .new first: a direct "> agent-os.json" would truncate the manifest before its secrets are read)7677# 3. Stage and deploy78~/Desktop/cluster-skill/mld stage ~/Desktop/Cluster/projets/agent-spboucher-ai agent-os79~/Desktop/cluster-skill/mld deploy agent-os --node M4M64c80```8182`post_sync` on the node: creates role / database `agent_os` (only when a new database password was83generated), writes `.env`, appends `keys.env`, runs84`pnpm install --frozen-lockfile && pnpm -r --workspace-concurrency=1 build`, checks the four build85outputs, then `node packages/kernel/dist/migrate-cli.js` (a failed migration fails the deploy). `mld`86then starts the PM2 processes, checks health locally, routes `https://agent.spboucher.ai` to the node and87checks health publicly.8889Then follow `docs/operations.md` → "First run".9091## Later deployments9293The node's `~/apps/agent-os` is the source of truth (remote-first): change, build and commit there, or94push to spbgit and `git pull` on the node, then `pnpm -r --workspace-concurrency=1 build`,95`node packages/kernel/dist/migrate-cli.js`, `pm2 restart agent-os-worker agent-os-server`.96`mld deploy agent-os` from a staging copy is refused when the node's clone has diverged97(`mld fetch agent-os --from <node>` first).9899Restarting the **worker** is safe at any time: it stops claiming, in-flight runs stay `running` with a100lease that the new process takes over (≤ 90 s). Restarting the **server** only drops WebSockets; the101console reconnects and resumes from its cursor.102103## Not verified by a real deployment104105The manifest generator was run locally only (fresh and against a stubbed existing manifest: valid JSON,106secrets reused, role/db creation only with a new password, no provider key anywhere). `mld deploy`, the107build on the node, PM2 `kill_timeout`, the tunnel route and `backup.sh` / `restore.sh` against a real108database have **not** been exercised yet.109
Files main
Menu

Theme