This repository has been archived on 2026-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
orchestrator/agent-team/scripts/deploy-r720-ws-rollout.sh

127 lines
7.1 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# deploy-r720-ws-rollout.sh — attended UPDATE of the live R720 agent-team
# coordinator to the WS0–WS5 rollout (PRs #43–#46 + the activation wiring).
#
# This is an UPDATE, not a first-time provision: P1 is already deployed per
# agent-team/DEPLOY-R720.md (repo rsynced to ~/orchestrator, venv at
# agent-team/.venv, systemd unit agent-team-coordinator.service running).
# Run this from the MAC, after the WS branches have merged to main. It rsyncs
# the new code, installs the new deps, appends the new secrets if absent, syncs
# the engineering handbook, restarts the coordinator, and smoke-tests.
#
# It is idempotent and FAILS LOUDLY. It changes a live box, so:
# 1) SNAPSHOT FIRST (Hyper-V checkpoint of sh-secrev on the R720 host).
# 2) It prompts before the restart.
#
# What goes LIVE after this (the safe, ungated seams):
# * WS1 in-process multi-model invokers (bind_multi_invoker, already wired)
# * WS5 handbook context_provider injected into the planner prompt
# * WS2 Slack /new-task -> start a task (AUTHZ-01 owner allowlist gated)
# The HTTP API (WS1) + the /delegate hook are OPTIONAL and started separately
# (see step 6). The P3 dispatch/build-verify path stays INERT (gated).
set -euo pipefail
# ── Config (override via env) ────────────────────────────────────────────────
BOX="${BOX:-adam@10.10.60.120}"
SSH_KEY="${SSH_KEY:-$HOME/.ssh/r720_seahaven}"
REPO_LOCAL="${REPO_LOCAL:-$HOME/Documents/repositories/orchestrator}"
HANDBOOK_LOCAL="${HANDBOOK_LOCAL:-$HOME/Documents/repositories/engineering-handbook}"
# Where the handbook lands on the box; must match SEA_HAVEN_HANDBOOK_DIR below.
HANDBOOK_REMOTE="${HANDBOOK_REMOTE:-/home/adam/.sea-haven/engineering-handbook}"
SSH="ssh -i ${SSH_KEY} ${BOX}"
say() { printf '\n\033[1;36m== %s\033[0m\n' "$*"; }
confirm() { read -r -p "$1 [y/N] " a; [ "$a" = "y" ] || [ "$a" = "Y" ]; }
say "Preflight"
[ -f "${SSH_KEY}" ] || { echo "missing SSH key ${SSH_KEY}"; exit 1; }
$SSH true || { echo "cannot reach ${BOX}"; exit 1; }
echo "SNAPSHOT REMINDER: take a Hyper-V checkpoint of sh-secrev on the R720 host now."
confirm "Snapshot taken and ready to update the LIVE coordinator?" || { echo "aborted"; exit 1; }
say "1. rsync repo (Mac -> box; same excludes as the P1 runbook)"
rsync -av --exclude .env --exclude .venv --exclude .git --exclude '__pycache__' \
"${REPO_LOCAL}/" "${BOX}:orchestrator/"
say "2. rsync engineering handbook -> ${HANDBOOK_REMOTE} (WS5 context_provider source)"
if [ -d "${HANDBOOK_LOCAL}" ]; then
$SSH "mkdir -p ${HANDBOOK_REMOTE}"
rsync -av --delete --exclude .git "${HANDBOOK_LOCAL}/" "${BOX}:${HANDBOOK_REMOTE}/"
else
echo "WARN: ${HANDBOOK_LOCAL} not found; context_provider will return '' (fail-safe). Skipping."
fi
say "3. Install venv deps from the pinned requirements.txt"
# Install the FULL pinned set into the agent-team venv. This includes the
# non-Claude model stack (langchain-anthropic/-openai/-google-genai/-community)
# that the in-process invokers (WS1: GPT-4.1 review, Gemini scan, DeepSeek build)
# import via models.py — WITHOUT these, models.py fails to import and the review
# loop silently fail-closes to REQUEST_CHANGES (the non-Claude models never run).
# Also brings fastapi/uvicorn (WS1 HTTP API). Leaves the venv-only deps that are
# NOT in requirements.txt (claude-agent-sdk, slack_sdk, slack_bolt) untouched.
$SSH 'cd ~/orchestrator/agent-team && . .venv/bin/activate && pip install --upgrade -r ~/orchestrator/requirements.txt'
say "4. Append new secrets to ~/secrev.env if absent (mode 600, never committed)"
# AGENT_TEAM_API_TOKEN: required only if you run the HTTP API / /delegate hook.
# SEA_HAVEN_HANDBOOK_DIR: where load_handbook_conventions() reads from.
$SSH "bash -s" <<REMOTE
set -euo pipefail
touch ~/secrev.env && chmod 600 ~/secrev.env
grep -q '^SEA_HAVEN_HANDBOOK_DIR=' ~/secrev.env || \
echo 'SEA_HAVEN_HANDBOOK_DIR=${HANDBOOK_REMOTE}' >> ~/secrev.env
if grep -q '^AGENT_TEAM_API_TOKEN=' ~/secrev.env; then
echo 'AGENT_TEAM_API_TOKEN already set; leaving as-is.'
else
echo 'AGENT_TEAM_API_TOKEN NOT set. Add it now (generated on the Mac):'
echo ' echo "AGENT_TEAM_API_TOKEN=<token>" >> ~/secrev.env && chmod 600 ~/secrev.env'
echo '(only needed for the HTTP API / auto-delegate hook; the coordinator runs without it.)'
fi
REMOTE
say "5. Restart the coordinator daemon"
confirm "Restart agent-team-coordinator.service now?" || { echo "skipped restart"; exit 0; }
$SSH 'sudo systemctl restart agent-team-coordinator.service && sleep 2 && systemctl is-active agent-team-coordinator.service'
$SSH 'journalctl -u agent-team-coordinator.service -n 30 --no-pager'
say "6. (OPTIONAL) HTTP API + /delegate hook — start only if you want them"
cat <<'NOTE'
The coordinator now serves WS5 context + WS2 /new-task. The WS1 HTTP API is a
SEPARATE process (api.serve(), 127.0.0.1:8765, bearer auth). To run it:
- ensure AGENT_TEAM_API_TOKEN is set in ~/secrev.env
- run: cd ~/orchestrator/agent-team && . .venv/bin/activate && \
python3 -c "from agent_team.api import serve; serve()"
- (for persistence, add a second systemd unit; not auto-installed here.)
Then set AGENT_TEAM_API_TOKEN + AGENT_TEAM_API_URL in the Mac Claude Code env
to enable the /delegate hook (sea-haven-claude-plugin).
NOTE
say "6b. (OPTIONAL) READ-ONLY status dashboard — LAN/VPN-only"
cat <<'NOTE'
agent_team/status_page.py serves a self-refreshing HTML view of the queue
(tasks/phases, who is waiting on the human gate, active/parked counts, recent
budget spend). It opens the ledger READ-ONLY (mode=ro), has no mutating
endpoints and NO auth. Separate, optional process from the coordinator.
- install the unit (mirrors the coordinator hardening; reads only, no RW carve-out):
sudo cp ~/orchestrator/agent-team/systemd/agent-team-status.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now agent-team-status.service
- or run ad hoc:
cd ~/orchestrator/agent-team && . .venv/bin/activate && \
python3 -c "from agent_team.status_page import serve; serve()"
- then browse http://10.10.60.120:8770/ from the LAN/VPN.
POSTURE: binds AGENT_TEAM_STATUS_HOST (default 0.0.0.0) on AGENT_TEAM_STATUS_PORT
(default 8770). The sh-secrev VM has no public NIC + sits behind the UniFi
firewall -> LAN/VPN only. Task descriptions may be sensitive; never expose public.
NOTE
say "7. SMOKE TESTS (manual)"
cat <<'SMOKE'
a) Coordinator up: systemctl is-active agent-team-coordinator.service -> active
b) Handbook visible: cd ~/orchestrator/agent-team && . .venv/bin/activate && \
python3 -c "from agent_team.nodes.handbook import load_handbook_conventions as h; print(bool(h()))" -> True
c) Slack /new-task: post "/new-task add a smoke-test file" in #agent-team as an
allowlisted owner -> the bot replies with a clarifying question.
d) (if API running) auth: curl -s -o /dev/null -w '%{http_code}' \
-H "Authorization: Bearer $AGENT_TEAM_API_TOKEN" http://127.0.0.1:8765/tasks -> 405 (GET not allowed = API up + authed)
ROLLBACK: restore the pre-update Hyper-V checkpoint (one-command revert).
SMOKE
say "Done."