#!/usr/bin/env bash # # Deploy the headless `claire agent` peer node to a Linux host (apricot|black). # Runs FROM plum. Idempotent. Code + systemd unit + peer config (injects plum's # sync_secret so the host can sync to plum). # # scripts/deploy-agent.sh apricot # # Requires: `remote-run` on PATH (~/Code/@scripts/session-tools), ssh access, # uv + python3.12+ on the remote, and NTP-synced clocks (HMAC skew window 300s). set -euo pipefail HOST="${1:?usage: deploy-agent.sh }" SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" REMOTE_DIR="Code/@projects/@claire" # relative to remote $HOME PLUM_TOML="${CLAIRE_TOML:-$HOME/.config/claire/claire.toml}" say() { printf '\033[1;35m▸\033[0m %s\n' "$*"; } # Plum's bind + sync_secret — the peer host signs sync requests to plum with it. read -r PLUM_URL PLUM_SECRET <&2; exit 1; } say "plum peer URL = $PLUM_URL (secret ${PLUM_SECRET:0:4}…)" say "[$HOST] reachability + clock" ssh -o ConnectTimeout=8 -o BatchMode=yes "$HOST" 'true' \ || { echo "ERROR: cannot ssh $HOST" >&2; exit 1; } ssh "$HOST" 'timedatectl show -p NTPSynchronized --value 2>/dev/null || echo unknown' say "[$HOST] rsync source" ssh "$HOST" "mkdir -p ~/$REMOTE_DIR" rsync -az --delete \ --exclude='.venv/' --exclude='.git/' --exclude='__pycache__/' \ --exclude='*.pyc' --exclude='.pytest_cache/' --exclude='.ruff_cache/' \ --exclude='claire.toml' \ --exclude='src/claire/web/app/node_modules/' \ --exclude='src/claire/web/app/dist/' \ "$SRC/" "${HOST}:${REMOTE_DIR}/" say "[$HOST] install (uv) + init" remote-run "$HOST" "cd ~/$REMOTE_DIR && { [ -d .venv ] || uv venv; } && uv pip install -e . && .venv/bin/claire init" say "[$HOST] configure peer (idempotent — points this host at plum)" remote-run "$HOST" "cd ~/$REMOTE_DIR && .venv/bin/claire agent add-peer --url '$PLUM_URL' --secret '$PLUM_SECRET'" say "[$HOST] install + enable systemd --user unit" remote-run "$HOST" " mkdir -p ~/.config/systemd/user cp ~/$REMOTE_DIR/deployments/systemd/claire-agent.service ~/.config/systemd/user/ systemctl --user daemon-reload systemctl --user enable --now claire-agent.service loginctl enable-linger \$(whoami) 2>/dev/null || true sleep 2 systemctl --user --no-pager status claire-agent.service | head -5 " say "[$HOST] done."