Sprite setup scripts for Claude Code and OpenClaw

- OAuth authentication flow with OpenRouter to mint API keys
- Automatic sprite creation and environment configuration
- Claude Code setup with bypassed onboarding and dark theme
- OpenClaw setup with gateway and TUI launch
- Shell environment setup (bun PATH, zsh switch)
This commit is contained in:
lab 2026-02-04 14:34:38 -06:00
parent 3eaf6321a1
commit 57bf0ca2fc
No known key found for this signature in database
4 changed files with 547 additions and 72 deletions

View file

@ -1,9 +1,17 @@
# Spawn
Automated sprite provisioning scripts for various tools and configurations.
Conjure your agents!
## Usage
### Claude Code Setup
Setup a sprite with Claude Code pre-configured (via OpenRouter):
```bash
curl https://openrouter.ai/lab/spawn/sprite/claude.sh | bash
```
### OpenClaw Setup
Setup a sprite with openclaw pre-configured:
@ -11,25 +19,3 @@ Setup a sprite with openclaw pre-configured:
```bash
curl https://openrouter.ai/lab/spawn/sprite/openclaw.sh | bash
```
This will:
1. Install sprite CLI if not present
2. Login to sprite to get credentials
3. Provision a new sprite with the specified name
4. Add `bun` to PATH
5. Install openclaw using bun
6. Open openrouter.ai/settings/keys to grab an API key
7. Inject API keys (OPENROUTER_API_KEY, ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL)
8. Configure openclaw to bypass initial settings
## Development
To test locally:
```bash
bash sprite/openclaw.sh
```
## Deployment
These scripts are served from `openrouter.ai/lab/spawn/*` via Next.js rewrites configured in `openrouter-web/projects/web/next.config.mjs`.

View file

@ -0,0 +1,79 @@
---
globs: sprite/**
---
# Sprite CLI Rules
When building bash scripts that use the Sprite CLI, always follow these guidelines.
## Documentation Reference
Always consult the latest [Sprite CLI documentation](https://docs.sprites.dev/cli/commands/) before writing commands.
## Key Commands
| Command | Purpose |
|---------|---------|
| `sprite login` | Authenticate with Sprites |
| `sprite create <name>` | Create a new sprite |
| `sprite list` / `sprite ls` | List available sprites |
| `sprite exec -s <name> -- <cmd>` | Execute command on sprite (non-interactive) |
| `sprite console -s <name>` | Connect to sprite interactively |
| `sprite destroy <name>` | Delete a sprite |
| `sprite checkpoint create` | Create a checkpoint |
| `sprite restore <version>` | Restore from checkpoint |
| `sprite proxy <port>` | Forward ports from sprite |
## Rules
1. **Use `sprite exec` for non-interactive commands**
- Run installation/setup commands with `sprite exec -s <sprite> -- bash -c "<command>"`
- Do NOT use `sprite console` for running automated commands
2. **Use `sprite console` only for interactive sessions**
- Reserve `sprite console` for when user interaction is needed
- Place `sprite console` at the very end of setup scripts
3. **Always specify sprite with `-s` flag**
- Use `-s <sprite-name>` to target a specific sprite explicitly
- Example: `sprite exec -s my-sprite -- ls -la`
4. **Check sprite existence before creating**
- Use `sprite list | grep -q "<name>"` to check if a sprite exists
- Only create if it doesn't exist
5. **Handle login state properly**
- Check `sprite list &> /dev/null` to verify authentication
- Use `sprite login || true` to prevent script exit on login issues
6. **Global flags**
- `--debug[=<file>]` - Enable debug logging
- `-o, --org <name>` - Specify organization
- `-s, --sprite <name>` - Specify sprite
- `-h, --help` - Show help
## Script Pattern
```bash
# 1. Check if sprite CLI is installed
if ! command -v sprite &> /dev/null; then
curl -fsSL https://sprites.dev/install.sh | bash
export PATH="$HOME/.local/bin:$PATH"
fi
# 2. Ensure logged in
if ! sprite list &> /dev/null; then
sprite login || true
fi
# 3. Create sprite if needed
if ! sprite list | grep -q "$SPRITE_NAME"; then
sprite create "$SPRITE_NAME"
fi
# 4. Run setup commands via exec
sprite exec -s "$SPRITE_NAME" -- bash -c "echo 'Setting up...'"
# 5. Connect interactively at the very end
sprite console "$SPRITE_NAME"
```

271
sprite/claude.sh Executable file
View file

@ -0,0 +1,271 @@
#!/bin/bash
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}Claude Code on Sprite${NC}"
echo ""
# Check if sprite is installed, install if not
if ! command -v sprite &> /dev/null; then
echo -e "${YELLOW}Installing sprite CLI...${NC}"
curl -fsSL https://sprites.dev/install.sh | bash
export PATH="$HOME/.local/bin:$PATH"
fi
# Check if already authenticated
if ! sprite org list &> /dev/null; then
echo -e "${YELLOW}Logging in to sprite...${NC}"
sprite login || true
fi
# Ensure user provides a sprite name
read -p "Enter sprite name: " SPRITE_NAME < /dev/tty
# Check if sprite exists, create if not
if sprite list 2>/dev/null | grep -q "^${SPRITE_NAME}$\|^${SPRITE_NAME} "; then
echo -e "${GREEN}Sprite '$SPRITE_NAME' already exists${NC}"
else
echo -e "${YELLOW}Creating sprite '$SPRITE_NAME'...${NC}"
sprite create -skip-console "$SPRITE_NAME" || true
echo -e "${YELLOW}Waiting for sprite to be ready...${NC}"
sleep 5
fi
# Verify sprite is accessible
echo -e "${YELLOW}Verifying sprite connectivity...${NC}"
if ! sprite exec -s "$SPRITE_NAME" -- echo "ok" >/dev/null 2>&1; then
echo -e "${YELLOW}Sprite not ready, waiting longer...${NC}"
sleep 5
fi
echo -e "${YELLOW}Setting up sprite environment...${NC}"
# Helper function to run commands on sprite
run_sprite() {
sprite exec -s "$SPRITE_NAME" -- bash -c "$1"
}
# 1. Add bun to PATH in .zshrc and .zprofile
echo -e "${YELLOW}Configuring shell environment...${NC}"
# Create temp file with path config
PATH_TEMP=$(mktemp)
cat > "$PATH_TEMP" << 'EOF'
# [spawn:path]
export PATH="$HOME/.bun/bin:/.sprite/languages/bun/bin:$PATH"
EOF
# Upload and append to shell configs
sprite exec -s "$SPRITE_NAME" -file "$PATH_TEMP:/tmp/path_config" -- bash -c "cat /tmp/path_config >> ~/.zprofile && cat /tmp/path_config >> ~/.zshrc && rm /tmp/path_config"
rm "$PATH_TEMP"
# Switch bash to zsh
BASH_TEMP=$(mktemp)
cat > "$BASH_TEMP" << 'EOF'
# [spawn:bash]
exec /usr/bin/zsh -l
EOF
sprite exec -s "$SPRITE_NAME" -file "$BASH_TEMP:/tmp/bash_config" -- bash -c "cat /tmp/bash_config > ~/.bash_profile && cat /tmp/bash_config > ~/.bashrc && rm /tmp/bash_config"
rm "$BASH_TEMP"
# 2. Install Claude Code using claude install (reinitializes properly)
echo -e "${YELLOW}Installing Claude Code...${NC}"
run_sprite "claude install > /dev/null 2>&1"
# 3. Get OpenRouter API key via OAuth
echo ""
echo -e "${YELLOW}Authenticating with OpenRouter via OAuth...${NC}"
CALLBACK_PORT=5180
CALLBACK_URL="http://localhost:${CALLBACK_PORT}/callback"
AUTH_URL="https://openrouter.ai/auth?callback_url=${CALLBACK_URL}"
# Create a temporary directory for the OAuth flow
OAUTH_DIR=$(mktemp -d)
CODE_FILE="$OAUTH_DIR/code"
# Create an inline script that handles the OAuth callback
OAUTH_SCRIPT="$OAUTH_DIR/server.sh"
cat > "$OAUTH_SCRIPT" << 'SERVEREOF'
#!/bin/bash
PORT=$1
CODE_FILE=$2
SUCCESS_HTML='HTTP/1.1 200 OK
Content-Type: text/html
Connection: close
<html><body style="font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #1a1a2e;"><div style="text-align: center; color: #fff;"><h1 style="color: #00d4aa;">Authentication Successful!</h1><p>You can close this window and return to your terminal.</p></div></body></html>'
# Listen for the callback and respond
while true; do
# Create a temp file for this request
REQ_FILE=$(mktemp)
# Use bash's /dev/tcp to handle the connection (works on macOS and Linux)
exec 3<>/dev/tcp/localhost/$PORT 2>/dev/null || {
# /dev/tcp not available, fall back to nc with response
{ echo "$SUCCESS_HTML"; cat; } | nc -l $PORT > "$REQ_FILE" 2>/dev/null
REQUEST=$(head -1 "$REQ_FILE")
rm -f "$REQ_FILE"
if [[ "$REQUEST" == *"/callback?code="* ]]; then
CODE=$(echo "$REQUEST" | sed -n 's/.*code=\([^ &]*\).*/\1/p')
echo "$CODE" > "$CODE_FILE"
exit 0
fi
continue
}
done
SERVEREOF
chmod +x "$OAUTH_SCRIPT"
echo -e "${YELLOW}Starting local OAuth server on port ${CALLBACK_PORT}...${NC}"
# Use a simpler nc approach - pipe response while capturing request
(
SUCCESS_RESPONSE='HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<html><body style="font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #1a1a2e;"><div style="text-align: center; color: #fff;"><h1 style="color: #00d4aa;">Authentication Successful!</h1><p>You can close this window and return to your terminal.</p></div></body></html>'
while true; do
# Listen and capture just the first line of the request, then respond
RESPONSE_FILE=$(mktemp)
echo -e "$SUCCESS_RESPONSE" > "$RESPONSE_FILE"
REQUEST=$(nc -l "$CALLBACK_PORT" < "$RESPONSE_FILE" 2>/dev/null | head -1)
rm -f "$RESPONSE_FILE"
if [[ "$REQUEST" == *"/callback?code="* ]]; then
CODE=$(echo "$REQUEST" | sed -n 's/.*code=\([^ &]*\).*/\1/p')
echo "$CODE" > "$CODE_FILE"
break
fi
done
) </dev/null &
SERVER_PID=$!
# Give the server a moment to start
sleep 1
# Open browser
echo -e "${YELLOW}Opening browser to authenticate with OpenRouter...${NC}"
if command -v open &> /dev/null; then
open "$AUTH_URL" </dev/null
elif command -v xdg-open &> /dev/null; then
xdg-open "$AUTH_URL" </dev/null
else
echo -e "${YELLOW}Please open: ${AUTH_URL}${NC}"
fi
# Wait for the code file to be created (timeout after 2 minutes)
TIMEOUT=120
ELAPSED=0
while [[ ! -f "$CODE_FILE" ]] && [[ $ELAPSED -lt $TIMEOUT ]]; do
sleep 1
((ELAPSED++))
done
# Kill the background server process
kill $SERVER_PID 2>/dev/null || true
wait $SERVER_PID 2>/dev/null || true
if [[ ! -f "$CODE_FILE" ]]; then
echo -e "${RED}Timed out waiting for OAuth callback${NC}"
rm -rf "$OAUTH_DIR"
exit 1
fi
OAUTH_CODE=$(cat "$CODE_FILE")
rm -rf "$OAUTH_DIR"
# Exchange the code for an API key
echo -e "${YELLOW}Exchanging OAuth code for API key...${NC}"
KEY_RESPONSE=$(curl -s -X POST "https://openrouter.ai/api/v1/auth/keys" \
-H "Content-Type: application/json" \
-d "{\"code\": \"$OAUTH_CODE\"}")
OPENROUTER_API_KEY=$(echo "$KEY_RESPONSE" | grep -o '"key":"[^"]*"' | sed 's/"key":"//;s/"$//')
if [[ -z "$OPENROUTER_API_KEY" ]]; then
echo -e "${RED}Failed to obtain API key: ${KEY_RESPONSE}${NC}"
exit 1
fi
echo -e "${GREEN}Successfully obtained OpenRouter API key!${NC}"
# 4. Inject environment variables
echo -e "${YELLOW}Setting up environment variables...${NC}"
# Create temp file with env config
ENV_TEMP=$(mktemp)
cat > "$ENV_TEMP" << EOF
# [spawn:env]
export OPENROUTER_API_KEY="${OPENROUTER_API_KEY}"
export ANTHROPIC_BASE_URL="https://openrouter.ai/api"
export ANTHROPIC_AUTH_TOKEN="${OPENROUTER_API_KEY}"
export ANTHROPIC_API_KEY=""
export CLAUDE_CODE_SKIP_ONBOARDING="1"
export CLAUDE_CODE_ENABLE_TELEMETRY="0"
EOF
# Upload and append to zshrc
sprite exec -s "$SPRITE_NAME" -file "$ENV_TEMP:/tmp/env_config" -- bash -c "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
rm "$ENV_TEMP"
# 5. Setup Claude Code settings to bypass initial setup
echo -e "${YELLOW}Configuring Claude Code...${NC}"
run_sprite "mkdir -p ~/.claude"
# Create Claude settings.json via file upload
SETTINGS_TEMP=$(mktemp)
cat > "$SETTINGS_TEMP" << EOF
{
"theme": "dark",
"editor": "vim",
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "0",
"ANTHROPIC_BASE_URL": "https://openrouter.ai/api",
"ANTHROPIC_AUTH_TOKEN": "${OPENROUTER_API_KEY}"
},
"permissions": {
"defaultMode": "bypassPermissions",
"dangerouslySkipPermissions": true
}
}
EOF
sprite exec -s "$SPRITE_NAME" -file "$SETTINGS_TEMP:/tmp/claude_settings" -- bash -c "mv /tmp/claude_settings ~/.claude/settings.json"
rm "$SETTINGS_TEMP"
# Create ~/.claude.json global state to skip onboarding and trust dialogs
GLOBAL_STATE_TEMP=$(mktemp)
cat > "$GLOBAL_STATE_TEMP" << EOF
{
"hasCompletedOnboarding": true,
"bypassPermissionsModeAccepted": true
}
EOF
sprite exec -s "$SPRITE_NAME" -file "$GLOBAL_STATE_TEMP:/tmp/claude_global" -- bash -c "mv /tmp/claude_global ~/.claude.json"
rm "$GLOBAL_STATE_TEMP"
# Create empty CLAUDE.md to prevent first-run prompts
run_sprite "touch ~/.claude/CLAUDE.md"
echo ""
echo -e "${GREEN}✅ Sprite setup completed successfully!${NC}"
echo ""
# Start Claude Code immediately
echo -e "${YELLOW}Starting Claude Code...${NC}"
sleep 1
clear
sprite exec -s "$SPRITE_NAME" -tty -- zsh -c "source ~/.zshrc && claude"

237
sprite/openclaw.sh Normal file → Executable file
View file

@ -7,112 +7,251 @@ GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}🚀 Spawnor - OpenClaw Sprite Setup${NC}"
echo -e "${GREEN}🚀 Spawn an OpenClaw agent on Sprite${NC}"
echo ""
# Check if sprite is installed
# Check if sprite is installed, install if not
if ! command -v sprite &> /dev/null; then
echo -e "${YELLOW}Installing sprite CLI...${NC}"
curl -fsSL https://fly.io/install.sh | sh
export PATH="$HOME/.fly/bin:$PATH"
curl -fsSL https://sprites.dev/install.sh | bash
export PATH="$HOME/.local/bin:$PATH"
fi
# Login to sprite if not already logged in
if ! sprite auth whoami &> /dev/null; then
echo -e "${YELLOW}Please login to sprite:${NC}"
sprite auth login
# Check if already authenticated
if ! sprite org list &> /dev/null; then
echo -e "${YELLOW}Logging in to sprite...${NC}"
sprite login || true
fi
# Get sprite name from user
read -p "Enter sprite name: " SPRITE_NAME
# Ensure user provides a sprite name
read -p "Enter sprite name: " SPRITE_NAME < /dev/tty
# Check if sprite exists, create if not
if sprite list | grep -q "$SPRITE_NAME"; then
if sprite list | grep -qx "$SPRITE_NAME"; then
echo -e "${GREEN}Sprite '$SPRITE_NAME' already exists${NC}"
else
echo -e "${YELLOW}Creating sprite '$SPRITE_NAME'...${NC}"
sprite create "$SPRITE_NAME"
sprite create -skip-console "$SPRITE_NAME" || true
echo -e "${YELLOW}Waiting for sprite to be ready...${NC}"
sleep 3
fi
echo -e "${YELLOW}Setting up sprite environment...${NC}"
# Helper function to run commands on sprite
run_sprite() {
sprite exec "$SPRITE_NAME" -- bash -c "$1"
sprite exec -s "$SPRITE_NAME" -- bash -c "$1"
}
# 1. Add bun to PATH in .zshrc and .zprofile
echo -e "${YELLOW}Configuring shell environment...${NC}"
PATH_CONFIG='
# [spawnor:path]
# Create temp file with path config
PATH_TEMP=$(mktemp)
cat > "$PATH_TEMP" << 'EOF'
# [spawn:path]
export PATH="$HOME/.bun/bin:/.sprite/languages/bun/bin:$PATH"
'
EOF
# Add to .zprofile for login shells
run_sprite "grep -q '\[spawnor:path\]' ~/.zprofile 2>/dev/null || echo '$PATH_CONFIG' >> ~/.zprofile"
# Add to .zshrc for interactive shells
run_sprite "grep -q '\[spawnor:path\]' ~/.zshrc 2>/dev/null || echo '$PATH_CONFIG' >> ~/.zshrc"
# Upload and append to shell configs
sprite exec -s "$SPRITE_NAME" -file "$PATH_TEMP:/tmp/path_config" -- bash -c "cat /tmp/path_config >> ~/.zprofile && cat /tmp/path_config >> ~/.zshrc && rm /tmp/path_config"
rm "$PATH_TEMP"
# Switch bash to zsh
BASH_CONFIG='
# [spawnor:bash]
BASH_TEMP=$(mktemp)
cat > "$BASH_TEMP" << 'EOF'
# [spawn:bash]
exec /usr/bin/zsh -l
'
EOF
run_sprite "grep -q '\[spawnor:bash\]' ~/.bash_profile 2>/dev/null || echo '$BASH_CONFIG' > ~/.bash_profile"
run_sprite "grep -q '\[spawnor:bash\]' ~/.bashrc 2>/dev/null || echo '$BASH_CONFIG' > ~/.bashrc"
sprite exec -s "$SPRITE_NAME" -file "$BASH_TEMP:/tmp/bash_config" -- bash -c "cat /tmp/bash_config > ~/.bash_profile && cat /tmp/bash_config > ~/.bashrc && rm /tmp/bash_config"
rm "$BASH_TEMP"
# 2. Install openclaw using bun
echo -e "${YELLOW}Installing openclaw...${NC}"
run_sprite "/.sprite/languages/bun/bin/bun install -g openclaw"
# 3. Get OpenRouter API key
# 3. Get OpenRouter API key via OAuth
echo ""
echo -e "${YELLOW}Opening openrouter.ai/settings/keys to grab API key...${NC}"
echo -e "${YELLOW}Please copy your API key and paste it below${NC}"
echo -e "${YELLOW}Authenticating with OpenRouter via OAuth...${NC}"
# Try to open the browser
CALLBACK_PORT=5180
CALLBACK_URL="http://localhost:${CALLBACK_PORT}/callback"
AUTH_URL="https://openrouter.ai/auth?callback_url=${CALLBACK_URL}"
# Create a temporary directory for the OAuth flow
OAUTH_DIR=$(mktemp -d)
CODE_FILE="$OAUTH_DIR/code"
# Create an inline script that handles the OAuth callback
OAUTH_SCRIPT="$OAUTH_DIR/server.sh"
cat > "$OAUTH_SCRIPT" << 'SERVEREOF'
#!/bin/bash
PORT=$1
CODE_FILE=$2
SUCCESS_HTML='HTTP/1.1 200 OK
Content-Type: text/html
Connection: close
<html><body style="font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #1a1a2e;"><div style="text-align: center; color: #fff;"><h1 style="color: #00d4aa;">Authentication Successful!</h1><p>You can close this window and return to your terminal.</p></div></body></html>'
# Listen for the callback and respond
while true; do
# Create a temp file for this request
REQ_FILE=$(mktemp)
# Use bash's /dev/tcp to handle the connection (works on macOS and Linux)
exec 3<>/dev/tcp/localhost/$PORT 2>/dev/null || {
# /dev/tcp not available, fall back to nc with response
{ echo "$SUCCESS_HTML"; cat; } | nc -l $PORT > "$REQ_FILE" 2>/dev/null
REQUEST=$(head -1 "$REQ_FILE")
rm -f "$REQ_FILE"
if [[ "$REQUEST" == *"/callback?code="* ]]; then
CODE=$(echo "$REQUEST" | sed -n 's/.*code=\([^ &]*\).*/\1/p')
echo "$CODE" > "$CODE_FILE"
exit 0
fi
continue
}
done
SERVEREOF
chmod +x "$OAUTH_SCRIPT"
echo -e "${YELLOW}Starting local OAuth server on port ${CALLBACK_PORT}...${NC}"
# Use a simpler nc approach - pipe response while capturing request
(
SUCCESS_RESPONSE='HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<html><body style="font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #1a1a2e;"><div style="text-align: center; color: #fff;"><h1 style="color: #00d4aa;">Authentication Successful!</h1><p>You can close this window and return to your terminal.</p></div></body></html>'
while true; do
# Listen and capture just the first line of the request, then respond
RESPONSE_FILE=$(mktemp)
echo -e "$SUCCESS_RESPONSE" > "$RESPONSE_FILE"
REQUEST=$(nc -l "$CALLBACK_PORT" < "$RESPONSE_FILE" 2>/dev/null | head -1)
rm -f "$RESPONSE_FILE"
if [[ "$REQUEST" == *"/callback?code="* ]]; then
CODE=$(echo "$REQUEST" | sed -n 's/.*code=\([^ &]*\).*/\1/p')
echo "$CODE" > "$CODE_FILE"
break
fi
done
) </dev/null &
SERVER_PID=$!
# Give the server a moment to start
sleep 1
# Open browser
echo -e "${YELLOW}Opening browser to authenticate with OpenRouter...${NC}"
if command -v open &> /dev/null; then
open "https://openrouter.ai/settings/keys"
open "$AUTH_URL" </dev/null
elif command -v xdg-open &> /dev/null; then
xdg-open "https://openrouter.ai/settings/keys"
xdg-open "$AUTH_URL" </dev/null
else
echo "Please open: https://openrouter.ai/settings/keys"
echo -e "${YELLOW}Please open: ${AUTH_URL}${NC}"
fi
read -sp "Enter your OpenRouter API Key: " OPENROUTER_API_KEY
# Wait for the code file to be created (timeout after 2 minutes)
TIMEOUT=120
ELAPSED=0
while [[ ! -f "$CODE_FILE" ]] && [[ $ELAPSED -lt $TIMEOUT ]]; do
sleep 1
((ELAPSED++))
done
# Kill the background server process
kill $SERVER_PID 2>/dev/null || true
wait $SERVER_PID 2>/dev/null || true
if [[ ! -f "$CODE_FILE" ]]; then
echo -e "${RED}Timed out waiting for OAuth callback${NC}"
rm -rf "$OAUTH_DIR"
exit 1
fi
OAUTH_CODE=$(cat "$CODE_FILE")
rm -rf "$OAUTH_DIR"
# Exchange the code for an API key
echo -e "${YELLOW}Exchanging OAuth code for API key...${NC}"
KEY_RESPONSE=$(curl -s -X POST "https://openrouter.ai/api/v1/auth/keys" \
-H "Content-Type: application/json" \
-d "{\"code\": \"$OAUTH_CODE\"}")
OPENROUTER_API_KEY=$(echo "$KEY_RESPONSE" | grep -o '"key":"[^"]*"' | sed 's/"key":"//;s/"$//')
if [[ -z "$OPENROUTER_API_KEY" ]]; then
echo -e "${RED}Failed to obtain API key: ${KEY_RESPONSE}${NC}"
exit 1
fi
echo -e "${GREEN}Successfully obtained OpenRouter API key!${NC}"
# Get model preference
echo ""
echo -e "${YELLOW}Browse models at: https://openrouter.ai/models${NC}"
echo -e "${YELLOW}Which model would you like to use?${NC}"
read -p "Enter model ID [openrouter/auto]: " MODEL_ID < /dev/tty
MODEL_ID="${MODEL_ID:-openrouter/auto}"
# 4. Inject environment variables
echo -e "${YELLOW}Setting up environment variables...${NC}"
ENV_CONFIG="
# [spawnor:env]
export OPENROUTER_API_KEY=\"$OPENROUTER_API_KEY\"
export ANTHROPIC_API_KEY=\"$OPENROUTER_API_KEY\"
export ANTHROPIC_BASE_URL=\"https://openrouter.ai/api\"
"
# Create temp file with env config
ENV_TEMP=$(mktemp)
cat > "$ENV_TEMP" << EOF
run_sprite "grep -q '\[spawnor:env\]' ~/.zshrc 2>/dev/null || echo '$ENV_CONFIG' >> ~/.zshrc"
# [spawn:env]
export OPENROUTER_API_KEY="${OPENROUTER_API_KEY}"
export ANTHROPIC_API_KEY="${OPENROUTER_API_KEY}"
export ANTHROPIC_BASE_URL="https://openrouter.ai/api"
EOF
# Upload and append to zshrc
sprite exec -s "$SPRITE_NAME" -file "$ENV_TEMP:/tmp/env_config" -- bash -c "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
rm "$ENV_TEMP"
# 5. Setup openclaw to bypass initial settings
echo -e "${YELLOW}Configuring openclaw...${NC}"
run_sprite "mkdir -p ~/.config/openclaw"
# Remove old config and create fresh
run_sprite "rm -rf ~/.openclaw && mkdir -p ~/.openclaw"
# Generate a random gateway token
GATEWAY_TOKEN=$(openssl rand -hex 16)
OPENCLAW_CONFIG='{
"hasCompletedOnboarding": true,
"defaultProvider": "openrouter",
"apiKey": "'"$OPENROUTER_API_KEY"'",
"baseUrl": "https://openrouter.ai/api"
"env": {
"OPENROUTER_API_KEY": "'"$OPENROUTER_API_KEY"'"
},
"gateway": {
"mode": "local",
"auth": {
"token": "'"$GATEWAY_TOKEN"'"
}
},
"agents": {
"defaults": {
"model": {
"primary": "openrouter/'"$MODEL_ID"'"
}
}
}
}'
run_sprite "echo '$OPENCLAW_CONFIG' > ~/.config/openclaw/config.json"
run_sprite "echo '$OPENCLAW_CONFIG' > ~/.openclaw/openclaw.json"
echo ""
echo -e "${GREEN}✅ Sprite setup completed successfully!${NC}"
echo ""
echo -e "Connect to your sprite with: ${YELLOW}sprite console $SPRITE_NAME${NC}"
echo ""
# Start openclaw gateway in background and run openclaw tui
echo -e "${YELLOW}Starting openclaw...${NC}"
sprite exec -s "$SPRITE_NAME" -- zsh -c "source ~/.zshrc && nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &"
sleep 2
sprite exec -s "$SPRITE_NAME" -tty -- zsh -c "source ~/.zshrc && openclaw tui"