#!/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