Files
quinceagent/deploy/entrypoint.sh
T
Quince ec780b2e73 Add prod deployment for the agent fleet (docker-compose.prod.yml)
- docker-compose.prod.yml + .env.prod.example: one container per agent, Quince
  first; deployed under /opt/gu_agents and wired into the server's start/stop.sh.
- Route API + git via host-gateway (containers can't hairpin the host's public IP).
- Dockerfile: drop the base image's uid-1000 user before creating quince.
- entrypoint: pip install --break-system-packages (Debian bookworm PEP 668).

Verified on prod: image builds, API reachable (200), PyPI egress ok, gutask
installs and runs, git clone from ramanujan works via host-gateway.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 10:42:46 +02:00

74 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# Quince entrypoint: bootstrap the persistent self, then sleep-and-wake forever.
set -euo pipefail
HOME_DIR="/home/quince"
GUTASK_DIR="$HOME_DIR/gutasktool"
GUTASK_REPO="ssh://git@ramanujan.glitch.university:2222/glitch-university/gutasktool.git"
WAKE_TIME="${WAKE_TIME:-09:00}"
log() { echo "[entrypoint $(date '+%Y-%m-%d %H:%M:%S %Z')] $*"; }
# --- 0. Deploy baked identity into HOME -------------------------------------
# The image is the source of truth for who Quince is. Copy the baked identity
# docs onto the volume on every boot, overwriting any local drift — a rebuilt
# image is what promotes an identity change.
IDENTITY_SRC="/opt/quince/identity"
mkdir -p "$HOME_DIR/.claude"
if [ -d "$IDENTITY_SRC" ]; then
cp -f "$IDENTITY_SRC/CLAUDE.md" "$HOME_DIR/CLAUDE.md"
cp -f "$IDENTITY_SRC/GOALS.md" "$HOME_DIR/GOALS.md"
cp -f "$IDENTITY_SRC/claude-settings.json" "$HOME_DIR/.claude/settings.json"
log "Identity deployed from image ($IDENTITY_SRC) → $HOME_DIR."
else
log "WARNING: no baked identity at $IDENTITY_SRC."
fi
# --- 1. SSH: lock down perms and trust ramanujan ----------------------------
mkdir -p "$HOME_DIR/.ssh" "$HOME_DIR/workspace" "$HOME_DIR/notes" "$HOME_DIR/logs"
chmod 700 "$HOME_DIR/.ssh" || true
if [ -f "$HOME_DIR/.ssh/id_ed25519" ]; then
chmod 600 "$HOME_DIR/.ssh/id_ed25519" || true
ssh-keyscan -p 2222 ramanujan.glitch.university >> "$HOME_DIR/.ssh/known_hosts" 2>/dev/null || true
sort -u "$HOME_DIR/.ssh/known_hosts" -o "$HOME_DIR/.ssh/known_hosts" 2>/dev/null || true
else
log "WARNING: no SSH key at ~/.ssh/id_ed25519 — repo clone/push to ramanujan will fail."
fi
# --- 2. gutasktool: clone if missing, then editable-install -----------------
if [ ! -d "$GUTASK_DIR/.git" ]; then
log "gutasktool not on volume — cloning from ramanujan…"
GIT_SSH_COMMAND="ssh -i $HOME_DIR/.ssh/id_ed25519 -o IdentitiesOnly=yes" \
git clone "$GUTASK_REPO" "$GUTASK_DIR" || log "WARNING: clone failed (check SSH key)."
fi
if [ -d "$GUTASK_DIR" ]; then
log "Installing gutasktool (editable)…"
# --break-system-packages: the Debian base marks its Python externally-managed
# (PEP 668); this is an isolated container, so installing to --user is fine.
python3 -m pip install --user --break-system-packages -e "$GUTASK_DIR" -q || \
log "WARNING: gutasktool install failed."
fi
# --- 3. Sanity: identity present? -------------------------------------------
: "${AGENT_ID:?AGENT_ID not set — check .env / env_file}"
: "${CONTENT_API_KEY:?CONTENT_API_KEY not set — check .env / env_file}"
: "${ANTHROPIC_API_KEY:?ANTHROPIC_API_KEY not set — Claude Code cannot authenticate}"
log "Quince online. Identity AGENT_ID=$AGENT_ID, wake time $WAKE_TIME ($TZ)."
# --- 4. Optional immediate run (first deploy / testing) ---------------------
if [ "${RUN_ON_START:-0}" = "1" ]; then
log "RUN_ON_START=1 — triggering one awakening now."
/usr/local/bin/wake.sh || log "wake.sh exited non-zero."
fi
# --- 5. Sleep until the next WAKE_TIME, wake, repeat ------------------------
while true; do
now=$(date +%s)
target=$(date -d "today $WAKE_TIME" +%s)
[ "$target" -le "$now" ] && target=$(date -d "tomorrow $WAKE_TIME" +%s)
secs=$(( target - now ))
log "Sleeping ${secs}s until next awakening at $(date -d "@$target" '+%Y-%m-%d %H:%M:%S %Z')."
sleep "$secs"
/usr/local/bin/wake.sh || log "wake.sh exited non-zero; will try again next cycle."
done