Spaces:
Runtime error
Runtime error
| # Hugging Face Spaces startup script for OpenClaw | |
| echo "๐ฆ Starting OpenClaw on Hugging Face Spaces..." | |
| # Create config directory | |
| mkdir -p /root/.openclaw/workspace | |
| # Check required env vars | |
| if [ -z "$API_KEY" ] || [ -z "$BASE_URL" ]; then | |
| echo "โ ๏ธ Warning: API_KEY or BASE_URL not set. AI features won't work." | |
| fi | |
| # ========================================== | |
| # GITHUB STATE SYNC (STARTUP PULL) | |
| # ========================================== | |
| OPENCLAW_DIR="/root/.openclaw" | |
| if [ -n "$MEMORY_REPO_URL" ] && [ -n "$MEMORY_REPO_TOKEN" ]; then | |
| echo "๐ Memory Sync Enabled! Attempting to restore state from GitHub..." | |
| # Extract domain and path from repo URL to format it with the token | |
| # Supports formats like: https://github.com/user/repo or github.com/user/repo | |
| REPO_CLEAN=$(echo "$MEMORY_REPO_URL" | sed -e 's|^[^/]*//||' -e 's|^.*@||') | |
| AUTH_REPO_URL="https://${MEMORY_REPO_TOKEN}@${REPO_CLEAN}" | |
| # Use a temporary directory for cloning to avoid conflict with existing config | |
| SYNC_TMP="/tmp/openclaw_sync" | |
| rm -rf "$SYNC_TMP" | |
| # Try cloning the repository | |
| if git clone "$AUTH_REPO_URL" "$SYNC_TMP" 2>/dev/null; then | |
| echo "โ Successfully downloaded state from GitHub repository." | |
| # Copy over the state, ensuring the destination directory exists | |
| mkdir -p "$OPENCLAW_DIR" | |
| # We use rsync or standard cp to move contents (excluding .git from remote) | |
| # Note: copying everything EXCEPT the remote's .git to our local working dir. | |
| if [ "$(ls -A $SYNC_TMP)" ]; then | |
| cp -r "$SYNC_TMP/." "$OPENCLAW_DIR/" | |
| rm -rf "$OPENCLAW_DIR/.git" | |
| fi | |
| # Initialize Git in the actual OpenClaw directory so we can push back later | |
| cd "$OPENCLAW_DIR" | |
| git init | |
| git config user.email "openclaw-bot@huggingface.co" | |
| git config user.name "OpenClaw Auto-Sync" | |
| git remote add origin "$AUTH_REPO_URL" | |
| # Force the branch name if needed (assumes main) | |
| git checkout -B main | |
| # Reset local to match remote exactly | |
| git fetch origin main 2>/dev/null || true | |
| git reset --soft origin/main 2>/dev/null || true | |
| echo "โ State restoration complete!" | |
| else | |
| echo "โ Failed to clone repository. Is the token valid and URL format correct? Starting fresh..." | |
| fi | |
| else | |
| echo "โน๏ธ MEMORY_REPO_URL or MEMORY_REPO_TOKEN not provided. State will NOT be persisted across restarts." | |
| fi | |
| # ========================================== | |
| # CLEAN STALE SESSION LOCKS | |
| # ========================================== | |
| # When Hugging Face spaces restart unexpectedly, lock files might be left behind. | |
| # Because Docker PIDs start at 1 again, OpenClaw might think the old lock is still active | |
| # and time out trying to access the session. We wipe them cleanly on boot. | |
| if [ -d "/root/.openclaw/agents" ]; then | |
| echo "๐งน Cleaning up any stale session lock files on boot..." | |
| find /root/.openclaw/agents -type f -name "*.jsonl.lock" -exec rm -f {} + | |
| fi | |
| # Set defaults | |
| BASE_URL=${BASE_URL:-"http://127.0.0.1:20128/v1"} | |
| MODEL_ID=${MODEL_ID:-"Multiple-models"} | |
| PROVIDER_NAME=${PROVIDER_NAME:-"custom"} | |
| # Create necessary OpenClaw memory files to prevent ENOENT errors | |
| mkdir -p /root/.openclaw/workspace/memory | |
| touch /root/.openclaw/workspace/MEMORY.md | |
| touch "/root/.openclaw/workspace/memory/$(date -u +%Y-%m-%d).md" | |
| touch "/root/.openclaw/workspace/memory/$(date -u -d "yesterday" +%Y-%m-%d 2>/dev/null || date -u -v -1d +%Y-%m-%d 2>/dev/null || echo "").md" 2>/dev/null || true | |
| # Create OpenClaw config | |
| cat > /root/.openclaw/openclaw.json << EOF | |
| { | |
| "meta": { | |
| "lastTouchedVersion": "2026.2.19-2" | |
| }, | |
| "models": { | |
| "providers": { | |
| "${PROVIDER_NAME}": { | |
| "baseUrl": "${BASE_URL}", | |
| "apiKey": "${API_KEY}", | |
| "api": "openai-completions", | |
| "models": [ | |
| { "id": "${MODEL_ID}", "name": "${MODEL_ID}" } | |
| ] | |
| } | |
| } | |
| }, | |
| "agents": { | |
| "defaults": { | |
| "model": { "primary": "${PROVIDER_NAME}/${MODEL_ID}" }, | |
| "workspace": "/root/.openclaw/workspace", | |
| "timeoutSeconds": 300, | |
| "lockTimeoutMs": 120000 | |
| } | |
| }, | |
| "commands": { "native": "auto", "nativeSkills": "auto", "restart": false }, | |
| "hooks": { | |
| "internal": { | |
| "enabled": true, | |
| "entries": { | |
| "boot-md": { "enabled": true }, | |
| "command-logger": { "enabled": true }, | |
| "session-memory": { "enabled": true } | |
| } | |
| } | |
| }, | |
| "session": { "dmScope": "per-channel-peer" }, | |
| "gateway": { | |
| "port": 7860, | |
| "mode": "local", | |
| "bind": "lan", | |
| "controlUi": { | |
| "dangerouslyDisableDeviceAuth": true | |
| }, | |
| "trustedProxies": ["0.0.0.0/0"], | |
| "tailscale": { "mode": "off" } | |
| }, | |
| "skills": { "install": { "nodeManager": "npm" } }, | |
| "plugins": { "entries": {} } | |
| } | |
| EOF | |
| echo "โ Config created" | |
| echo "๐ก API: ${BASE_URL}" | |
| echo "๐ค Model: ${MODEL_ID}" | |
| echo "" | |
| echo "๐ Starting OpenClaw Gateway..." | |
| echo "๐ฑ Open your Space URL to access the dashboard" | |
| echo "๐ Note: OpenClaw will natively generate a Gateway Token on its first run. Check these initialization logs below to find it!" | |
| echo "" | |
| # Start OpenClaw gateway directly in the background | |
| openclaw gateway & | |
| GATEWAY_PID=$! | |
| sleep 4 | |
| # Run a background task to display the token right after initialization | |
| ( | |
| echo "" | |
| echo "==========================================================================" | |
| # Try to grab the token from the updated config file | |
| TOKEN=$(grep -E '"token"\s*:' /root/.openclaw/openclaw.json | head -1 | awk -F '"' '{print $4}') | |
| if [ -z "$TOKEN" ] || [ "$TOKEN" == "null" ]; then | |
| # Fallback to CLI command | |
| TOKEN=$(openclaw config get gateway.auth.token 2>/dev/null) | |
| fi | |
| echo "๐ GENERATED GATEWAY TOKEN: $TOKEN" | |
| echo "๐ Use this token in the OpenClaw pairing screen!" | |
| echo "==========================================================================" | |
| echo "" | |
| ) | |
| # ========================================== | |
| # GITHUB STATE SYNC (CONTINUOUS PUSH) | |
| # ========================================== | |
| if [ -n "$MEMORY_REPO_URL" ] && [ -n "$MEMORY_REPO_TOKEN" ]; then | |
| echo "๐ Starting background memory synchronization..." | |
| # Extract domain and path again just in case for the fallback initialization | |
| REPO_CLEAN=$(echo "$MEMORY_REPO_URL" | sed -e 's|^[^/]*//||' -e 's|^.*@||') | |
| AUTH_REPO_URL="https://${MEMORY_REPO_TOKEN}@${REPO_CLEAN}" | |
| ( | |
| # Ensure working directory exists before jumping in | |
| mkdir -p "$OPENCLAW_DIR" | |
| cd "$OPENCLAW_DIR" || exit | |
| # If for some reason git wasn't initialized during the startup step (e.g., clone failed because repo was empty), | |
| # we initialize it here as a fallback before entering the infinite loop. | |
| if [ ! -d ".git" ]; then | |
| echo "โ ๏ธ Git not initialized in $OPENCLAW_DIR. Initializing fallback..." | |
| git init | |
| git config user.email "openclaw-bot@huggingface.co" | |
| git config user.name "OpenClaw Auto-Sync" | |
| git remote add origin "$AUTH_REPO_URL" | |
| git checkout -B main | |
| fi | |
| # Ensure .gitignore prevents pushing bad/heavy files | |
| cat > .gitignore << 'IGNORE' | |
| node_modules/ | |
| .env | |
| *.jsonl.lock | |
| IGNORE | |
| # Untrack any lock files that may have accidentally been added previously | |
| find "$OPENCLAW_DIR" -type f -name "*.jsonl.lock" -exec git rm --cached {} + 2>/dev/null || true | |
| while true; do | |
| # Sync every 30 seconds | |
| sleep 30 | |
| # Remove any nested .git directories that confuse our top-level git repo | |
| # This prevents "error: 'workspace/' does not have a commit checked out" | |
| find "$OPENCLAW_DIR" -mindepth 2 -type d -name ".git" -exec rm -rf {} + | |
| # Add all changes | |
| git add . | |
| # Commit will fail cleanly if there are no changes, acting as our checker | |
| if git commit -m "Auto-sync OpenClaw state [$(date -u)]" >/dev/null 2>&1; then | |
| echo "[$(date -u)] ๐ Syncing OpenClaw memory state to GitHub..." | |
| # Try to pull in case of external changes to avoid conflicts, then push | |
| git pull --rebase origin main || echo "โ ๏ธ Git pull failed" | |
| git push -u origin main || echo "โ Git push failed! Please check token permissions." | |
| # echo "[$(date -u)] โ Memory state saved." | |
| fi | |
| done | |
| ) & | |
| fi | |
| # Wait for the main gateway process | |
| wait $GATEWAY_PID | |