Spaces:
Sleeping
Sleeping
File size: 4,119 Bytes
4136906 287d491 4136906 9cb5fe7 4136906 9cb5fe7 287d491 9cb5fe7 287d491 9cb5fe7 287d491 4136906 6fd41e0 9cb5fe7 287d491 9cb5fe7 4136906 9cb5fe7 4136906 287d491 4136906 287d491 4136906 287d491 4136906 287d491 9cb5fe7 4136906 287d491 4136906 9cb5fe7 4136906 287d491 3cb49fd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | #!/usr/bin/env bash
set -eo pipefail
export HOME="${HOME:-/root}"
DATA="/data"
# --- 0. Persistent data dir: ~/.hermes -> /data ---------------------------------
# Hermes (baked into the image) defaults to $HOME/.hermes. We swap that for the
# mounted /data bucket so config, skills, memory, sessions and cron survive
# restarts. /root is ephemeral, so the symlink itself is recreated every boot.
mkdir -p "${DATA}"
rm -rf "${HOME}/.hermes"
ln -sfn "${DATA}" "${HOME}/.hermes"
# Heal mount permissions/ownership (bucket mounts can reset them between boots).
if [ ! -w "${DATA}" ] && [ "$(id -u)" = "0" ]; then
echo "[boot] repairing ownership on ${DATA}..." >&2
chown root:root "${DATA}" 2>/dev/null || true
chmod u+rwx "${DATA}" 2>/dev/null || true
fi
# --- 1. Seed the volume from the image on first boot ---------------------------------------
if [ ! -f "${DATA}/config.yaml" ]; then
echo "[boot] first boot — seeding Hermes data (node, uv, bundled skills) into ${DATA}..." >&2
if [ -d /hermes-seed ]; then
cp -a /hermes-seed/. "${DATA}/" 2>/dev/null || true
fi
fi
# Storage Buckets are S3-like and may drop the executable bit on remount. Re-assert +x
# on every boot for the binaries Hermes relies on (node, uv, skills scripts) so the
# volume stays self-healing across restarts.
if [ -d "${DATA}/node/bin" ]; then
chmod +x "${DATA}/node/bin/"* 2>/dev/null || true
fi
find "${DATA}" -maxdepth 3 -type f \( -name "uv" -o -name "node" -o -name "npm" -o -name "npx" \) -exec chmod +x {} + 2>/dev/null || true
# node/npm (managed by the installer under ~/.hermes/node) + uv on PATH.
export PATH="${DATA}/node/bin:${HOME}/.local/bin:${PATH}"
# Make sure `hermes` is reachable (it's baked at /usr/local/bin, fallback to venv).
if ! command -v hermes >/dev/null 2>&1; then
ln -sfn /usr/local/lib/hermes-agent/venv/bin/hermes /usr/local/bin/hermes 2>/dev/null || true
fi
# --- 2. Persist secrets (Space env secrets) into ~/.hermes/.env every boot ----
# (config.yaml lives in the .env directory too, so this file IS the volume)
env_file="${DATA}/.env"
touch "${env_file}"
set_key() {
local key="$1" value="${2:-}"
if [ -n "${value}" ]; then
if grep -qE "^${key}=" "${env_file}" 2>/dev/null; then
sed -i "/^${key}=/d" "${env_file}"
fi
printf '%s=%s\n' "${key}" "${value}" >> "${env_file}"
fi
}
set_key OPENROUTER_API_KEY "${OPENROUTER_API_KEY:-}"
set_key HERMES_OPENROUTER_CACHE 1
# Dashboard basic auth (a non-loopback bind requires an auth provider).
set_key HERMES_DASHBOARD_BASIC_AUTH_USERNAME "${HERMES_DASHBOARD_BASIC_AUTH_USERNAME:-admin}"
set_key HERMES_DASHBOARD_BASIC_AUTH_PASSWORD "${HERMES_DASHBOARD_BASIC_AUTH_PASSWORD:-}"
set_key HERMES_DASHBOARD_BASIC_AUTH_SECRET "${HERMES_DASHBOARD_BASIC_AUTH_SECRET:-}"
# OpenAI-compatible API server (loopback only).
set_key API_SERVER_ENABLED "${API_SERVER_ENABLED:-true}"
set_key API_SERVER_PORT "${API_SERVER_PORT:-8642}"
set_key API_SERVER_KEY "${API_SERVER_KEY:-}"
set_key API_SERVER_HOST "127.0.0.1"
# --- 3. Default config.yaml (OpenRouter + delegation/spawn), only if missing ----
if [ ! -f "${DATA}/config.yaml" ]; then
cat > "${DATA}/config.yaml" <<'YAML'
# Hermes Agent — persistent setup via OpenRouter with subagent spawning.
model:
provider: openrouter
default: "~anthropic/claude-sonnet-latest"
# Spawn subagents through OpenRouter (parallel + nested orchestration).
delegation:
provider: openrouter
max_concurrent_children: 3
max_spawn_depth: 2
orchestrator_enabled: true
max_iterations: 50
terminal:
backend: local
openrouter:
response_cache: true
YAML
fi
# --- 4. Start the Hermes web dashboard on the Hugging Face PORT ----------------
PORT="${PORT:-7860}"
echo "[boot] Hermes dashboard → http://0.0.0.0:${PORT}/" >&2
# Use prebuilt web UI if present (baked at Docker build); otherwise build at runtime.
DASH_FLAGS="--host 0.0.0.0 --port ${PORT}"
if [ -d /usr/local/lib/hermes-agent/hermes_cli/web_dist ]; then
DASH_FLAGS="${DASH_FLAGS} --skip-build"
fi
exec hermes dashboard ${DASH_FLAGS} |