Download entrypoint.sh from amangs/hermes: direct link, hf CLI and curl.
- Browser
- Download file 8.3 kB
-
https://huggingface.co/spaces/amangs/hermes/resolve/main/entrypoint.sh
- Command line
-
hf download hf://spaces/amangs/hermes/entrypoint.sh
-
curl -L -o entrypoint.sh https://huggingface.co/spaces/amangs/hermes/resolve/main/entrypoint.sh
8.3 kB
| # Entrypoint script for Hermes Agent on Hugging Face Spaces | |
| # | |
| # Startup Architecture: | |
| # entrypoint.sh | |
| # βββ data_sync daemon (Background, Data persistence) | |
| # βββ hermes gateway run (Background, API Server :8642 + Gateway) | |
| # βββ node /opt/hermes-web-ui/dist/server/index.js (Foreground, BFF :7860) | |
| set -e | |
| echo "π Hermes Agent v0.10.0 - Hugging Face Spaces" | |
| echo "==============================================" | |
| # ==================== Initialize Directories ==================== | |
| echo "π Initializing directory structure..." | |
| mkdir -p /data/.hermes/{cron,sessions,logs,memories,skills,pairing,hooks,image_cache,audio_cache,whatsapp/session,script} | |
| mkdir -p /data/.hermes-web-ui | |
| mkdir -p /app/logs | |
| # ==================== Data Restoration ==================== | |
| export SKIP_CONFIG_RESTORE=true | |
| if [ -n "$HF_DATASET_REPO" ]; then | |
| echo "π₯ Restoring data from Dataset..." | |
| python -m src.data_sync restore || { | |
| echo "β οΈ Data restore failed, starting with clean configuration" | |
| } | |
| fi | |
| # ==================== Setup config.yaml with Env Expansion ==================== | |
| CONFIG_FILE="/data/.hermes/config.yaml" | |
| # Expand ${TELEGRAM_BOT_APIBASE} and other environment variables from template into runtime config | |
| python3 -c " | |
| import os, re | |
| src = '/app/config/config.yaml' | |
| dst = '/data/.hermes/config.yaml' | |
| content = open(src).read() | |
| # Expand \${VAR} and \$VAR patterns from current environment | |
| def expand(match): | |
| var = match.group(1) or match.group(2) | |
| return os.environ.get(var, '') | |
| expanded = re.sub(r'\\\$\\{([A-Za-z0-9_]+)\\}|\\\$(\\w+)', expand, content) | |
| open(dst, 'w').write(expanded) | |
| " 2>/dev/null || cp /app/config/config.yaml "$CONFIG_FILE" | |
| # Merge restored user config if present | |
| RESTORED_CONFIG="/data/.hermes/config.yaml.restored" | |
| if [ -f "$RESTORED_CONFIG" ]; then | |
| echo "π Merging user configuration..." | |
| python3 << 'MERGE_SCRIPT' | |
| import yaml | |
| GENERATED = '/data/.hermes/config.yaml' | |
| RESTORED = '/data/.hermes/config.yaml.restored' | |
| ENTRYPOINT_PRIORITY = {'api_server'} | |
| try: | |
| with open(GENERATED) as f: generated = yaml.safe_load(f) or {} | |
| with open(RESTORED) as f: restored = yaml.safe_load(f) or {} | |
| merged = {} | |
| for k in set(list(generated.keys()) + list(restored.keys())): | |
| merged[k] = generated.get(k, restored.get(k)) if k in ENTRYPOINT_PRIORITY else restored.get(k, generated.get(k)) | |
| with open(GENERATED, 'w') as f: | |
| yaml.dump(merged, f, default_flow_style=False, allow_unicode=True, sort_keys=False) | |
| print(" β Configuration successfully merged") | |
| except Exception as e: | |
| print(f" β οΈ Merge failed: {e}") | |
| MERGE_SCRIPT | |
| rm -f "$RESTORED_CONFIG" | |
| fi | |
| # ==================== REA MCP Registration ==================== | |
| # Idempotent; after config generation so the entry survives, before gateway loads config | |
| echo "π Registering REA MCP with Hermes..." | |
| rea setup --client hermes --yes || echo " β οΈ REA setup skipped (non-fatal)" | |
| rea setup --client opencode --yes || true | |
| # optional | |
| # ==================== Base URLs & Runtime Environment ==================== | |
| export NVIDIA_BASE_URL="${NVIDIA_BASE_URL:-https://integrate.api.nvidia.com/v1}" | |
| export API_SERVER_ENABLED=true | |
| export API_SERVER_PORT=8642 | |
| export API_SERVER_HOST=127.0.0.1 | |
| export GATEWAY_ALLOW_ALL_USERS="${GATEWAY_ALLOW_ALL_USERS:-true}" | |
| export HERMES_MODEL="${MODEL_NAME:-deepseek-ai/deepseek-v4-flash}" | |
| # API Server Secret Key | |
| export API_SERVER_KEY="${API_SERVER_KEY:-$(python3 -c "import secrets; print(secrets.token_hex(32))")}" | |
| # ==================== Write Environment Variables (.env) ==================== | |
| echo "βοΈ Syncing environment variables to .env..." | |
| ENV_FILE="/data/.hermes/.env" | |
| PERSISTENT_VARS=( | |
| "MODEL_PROVIDER" "MODEL_NAME" "HERMES_MODEL" | |
| "NVIDIA_API_KEY" "NVIDIA_BASE_URL" | |
| "API_SERVER_KEY" "API_SERVER_ENABLED" "API_SERVER_PORT" "API_SERVER_HOST" | |
| "TELEGRAM_BOT_TOKEN" "TELEGRAM_ALLOWED_USERS" "TELEGRAM_BOT_APIBASE" "TELEGRAM_PROXY" | |
| "GATEWAY_ALLOW_ALL_USERS" | |
| "AUTH_TOKEN" "TZ" | |
| ) | |
| declare -A env_entries=() | |
| if [ -f "$ENV_FILE" ]; then | |
| while IFS= read -r line; do | |
| [[ "$line" =~ ^[[:space:]]*# ]] && continue | |
| [[ -z "${line// }" ]] && continue | |
| eq_idx="${line%%=*}" | |
| if [ -n "$eq_idx" ] && [ "$eq_idx" != "$line" ]; then | |
| env_entries["$eq_idx"]="$line" | |
| fi | |
| done < "$ENV_FILE" | |
| fi | |
| for var in "${PERSISTENT_VARS[@]}"; do | |
| if [ -n "${!var}" ]; then | |
| env_entries["$var"]="${var}=${!var}" | |
| fi | |
| done | |
| { | |
| for key in "${!env_entries[@]}"; do | |
| echo "${env_entries[$key]}" | |
| done | |
| } | sort > "$ENV_FILE" | |
| echo " β .env synchronized" | |
| # ==================== Start Data Sync Daemon ==================== | |
| SYNC_INTERVAL=${SYNC_INTERVAL:-60} | |
| python -m src.data_sync daemon & | |
| SYNC_PID=$! | |
| echo "π Data sync daemon started (PID: $SYNC_PID, Interval: ${SYNC_INTERVAL}s)" | |
| # ==================== Start Gateway & API Server ==================== | |
| echo "π‘ Starting Hermes Gateway + API Server..." | |
| ( | |
| while true; do | |
| hermes gateway run --replace 2>&1 | |
| EXIT_CODE=$? | |
| if [ "$EXIT_CODE" -ne 0 ]; then | |
| echo " β οΈ Gateway exited (code=$EXIT_CODE), restarting in 15s..." | |
| sleep 15 | |
| else | |
| echo " π Gateway exited normally" | |
| break | |
| fi | |
| done | |
| ) & | |
| GATEWAY_PID=$! | |
| echo " β³ Waiting for API Server (:8642)..." | |
| for i in $(seq 1 30); do | |
| if curl -sf http://127.0.0.1:8642/health > /dev/null 2>&1; then | |
| echo " β API Server is ready (http://127.0.0.1:8642)" | |
| break | |
| fi | |
| sleep 1 | |
| done | |
| # ==================== Web UI Auth ==================== | |
| export AUTH_TOKEN="${AUTH_TOKEN:-123456}" | |
| export PASSWORD="$AUTH_TOKEN" | |
| # ==================== Start Zen Proxy (Go) ==================== | |
| if [ -d "/data/.hermes/script/opencode-router" ]; then | |
| echo "π Initializing & Starting OpenCode Router (:8787)..." | |
| chmod +x /data/.hermes/script/opencode-router/opencode-router /data/.hermes/script/opencode-router/*.sh 2>/dev/null || true | |
| if [ -f "/data/.hermes/script/opencode-router/start.sh" ]; then | |
| bash /data/.hermes/script/opencode-router/start.sh 8787 | |
| fi | |
| fi | |
| # ==================== Start Persistent Services (script/init.d) ==================== | |
| [ -f /data/.hermes/script/init.d.sh ] && bash /data/.hermes/script/init.d.sh | |
| # ==================== Start Web UI (BFF Server) ==================== | |
| echo "π Starting Hermes Web UI on internal port 7861..." | |
| export PORT=7861 | |
| export UPSTREAM=http://127.0.0.1:8642 | |
| export HERMES_BIN=/usr/local/bin/hermes | |
| export HERMES_HOME=/data/.hermes | |
| export HERMES_WEB_UI_HOME=/data/.hermes-web-ui | |
| cleanup() { | |
| echo "π Cleaning up..." | |
| if [ -n "$HF_DATASET_REPO" ]; then | |
| python -m src.data_sync backup --force 2>/dev/null || true | |
| fi | |
| kill $CADDY_PID $BFF_PID $GATEWAY_PID $SYNC_PID 2>/dev/null || true | |
| pkill -f "dufs -c /data/.hermes/script/dufs/dufs.yaml" 2>/dev/null || true | |
| pkill -f "code-server --port 8443" 2>/dev/null || true | |
| pkill -f "opencode-router 8787" 2>/dev/null || true | |
| exit 0 | |
| } | |
| trap cleanup SIGTERM SIGINT | |
| node /opt/hermes-web-ui/dist/server/index.js & | |
| BFF_PID=$! | |
| echo " β³ Waiting for Web UI (:7861)..." | |
| for i in $(seq 1 20); do | |
| if curl -sf http://localhost:7861/health > /dev/null 2>&1; then | |
| echo " β Web UI is ready β http://localhost:7861" | |
| break | |
| fi | |
| sleep 1 | |
| done | |
| # ==================== Start Caddy Reverse Proxy (:7860) ==================== | |
| CADDYFILE="/data/.hermes/script/Caddyfile" | |
| if [ ! -f "$CADDYFILE" ]; then | |
| mkdir -p /data/.hermes/script | |
| cat << 'EOF' > "$CADDYFILE" | |
| :7860 { | |
| handle_path /code* { | |
| reverse_proxy 127.0.0.1:8443 | |
| } | |
| handle_path /opencode* { | |
| reverse_proxy 127.0.0.1:8787 | |
| } | |
| handle /v1/* { | |
| reverse_proxy 127.0.0.1:8642 | |
| } | |
| handle { | |
| reverse_proxy 127.0.0.1:7861 | |
| } | |
| } | |
| EOF | |
| fi | |
| echo "π Starting Caddy on public port 7860..." | |
| caddy run --config "$CADDYFILE" --adapter caddyfile & | |
| CADDY_PID=$! | |
| echo " β³ Waiting for Caddy (:7860)..." | |
| for i in $(seq 1 20); do | |
| if curl -sf http://localhost:7860/health > /dev/null 2>&1; then | |
| echo " β Caddy is ready β http://localhost:7860" | |
| break | |
| fi | |
| sleep 1 | |
| done | |
| wait $CADDY_PID | |