6.0 KiB
Server deploy changes (box + terminal + dotfiles + webhooks + notifications)
Everything the production host / compose / .env needs for the per-user box, the
terminal, the personalized dev environment, GitHub webhooks, and notifications.
Most items have safe defaults; the Required ones are the only must-dos.
Required
-
Build-time env for the Next image — add to the build env file (the one CI /
scripts/build-next-apppasses as build args; e.g.DOTENV_PROD):NEXT_PUBLIC_SPOON_AGENT_WORKER_WS_URL=wss://worker.spoon.gbrown.orgThis is a
NEXT_PUBLIC(build-time) var — it must be present when thespoon-nextimage is built, not just at runtime. Already wired intodocker/Dockerfile+docker/compose.ymlbuild args. Without it, the workspace Terminal tab shows "not configured". -
nginx: expose the worker for the terminal WebSocket. Add a TLS server block proxying the worker domain to the worker on the shared network, with WS upgrade:
server { listen 443 ssl; server_name worker.spoon.gbrown.org; # + your ssl_certificate lines location / { proxy_pass http://spoon-agent-worker:3921; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_read_timeout 86400s; proxy_send_timeout 86400s; } } -
Rebuild + redeploy all three images (CI does this on push to
main):spoon-next,spoon-agent-worker, andspoon-agent-job(now Fedora). The worker auto-docker pulls the job image once per process, so a worker restart picks up the new Fedora job image. Make sure the prod registry has the newspoon-agent-job:latest. -
Deploy Convex functions (new tables
userDotfiles,userEnvironment,notifications,notificationPreferences).SPOON_ENCRYPTION_KEY(orINSTANCE_SECRET) is already required and is what encrypts dotfiles at rest — no change, just confirm it's set. -
Confirm
SPOON_AGENT_HOST_WORKDIRon thespoon-agent-workerservice is the absolute host path backingSPOON_AGENT_WORKDIR(the fix from the terminal work). The per-user homes live under${SPOON_AGENT_WORKDIR}/homes/{username}and are bind-mounted into the box via the host daemon — this only resolves if the host-workdir translation is correct. (No new var; just verify.) -
Configure the GitHub App webhook. Set the App's webhook URL to
<CONVEX_SITE_URL>/webhooks/githuband setGITHUB_APP_WEBHOOK_SECRETin the Convex production env (the signature-verifiedhttpActionruns in Convex, not the worker). Without the secret the endpoint fails closed (HTTP 503) and drift only refreshes via the hourly cron.pushrefreshes affected Spoons;installation/installation_repositoriesupdate connection status. -
Notifications email (optional). In-app notifications work with no config. To also send email, set
USESEND_API_KEY,USESEND_URL, andUSESEND_FROM_EMAILin the Convex env. Per-user, per-kind email toggles live inSettings → Notifications; unset preferences default to on. -
Claude Code runtime. The box image pins
@anthropic-ai/claude-code, so Anthropic provider profiles (API key oranthropic_oauth_jsoncredential snapshot) can drive theclauderuntime with no extra host env. Anthropic API-key auth flows throughANTHROPIC_API_KEY; OAuth snapshots are written to~/.claude/.credentials.jsonin the box.
Optional (safe defaults — only set to override)
On the spoon-agent-worker service:
| Var | Default | Purpose |
|---|---|---|
SPOON_AGENT_TERMINAL_SECRET |
falls back to SPOON_AGENT_WORKER_INTERNAL_TOKEN |
HMAC secret for terminal/box tokens (must match the Next app's, which also falls back). Leave unset to use the shared token. |
SPOON_AGENT_BOX_IDLE_MS |
1800000 (30m) |
How long a per-user box survives idle before being reaped. |
No new env is needed for dotfiles, the per-user home, or the Nerd Font.
SPOON_AGENT_TERMINAL_IMAGE and SPOON_AGENT_TERMINAL_IDLE_MS were removed —
the box uses SPOON_AGENT_JOB_IMAGE and SPOON_AGENT_BOX_IDLE_MS.
Notes / one-time cleanup
- Layout change: thread checkouts moved from
${WORKDIR}/{jobId}/repoto${WORKDIR}/homes/{username}/Code/{spoon}/{branch}(persistent). Old per-job dirs are orphaned and safe to delete. - Containers: per-thread agent containers (
docker run --rm) and per-job terminal containers (spoon-agent-term-*) are gone; everything runs in onespoon-box-{username}per user. Any lingeringspoon-agent-term-*containers can be removed. - Resources: each active user holds one box (4 GB mem cap,
sleep infinity) until 30m idle. Single-user = one box. - Compose already mounts
/var/run/docker.sockinto the worker (unchanged) — the box is created/exec'd through it.
Quick post-deploy checks
docker exec spoon-agent-worker docker --version # CLI present (29.x)
docker run --rm git.gbrown.org/gib/spoon-agent-job:latest codex --version # 0.142
docker run --rm git.gbrown.org/gib/spoon-agent-job:latest claude --version # 2.1.207
docker run --rm git.gbrown.org/gib/spoon-agent-job:latest opencode --version
docker run --rm git.gbrown.org/gib/spoon-agent-job:latest bash -lc 'eza --version; zoxide --version; oh-my-posh --version'
# then: /machine → box status + terminal; open a thread → Terminal tab;
# Settings → Dotfiles add a .bashrc alias; Settings → Notifications toggles.