close-claw / start.sh
underrate's picture
Upload start.sh
15e4e19 verified
Raw
History Blame Contribute Delete
8.59 kB
#!/bin/bash
# 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