Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 26 additions & 24 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ Guidelines for AI agents working on this codebase.

## Project Overview

This is a Cloudflare Worker that runs [Moltbot](https://molt.bot/) in a Cloudflare Sandbox container. It provides:
- Proxying to the Moltbot gateway (web UI + WebSocket)
This is a Cloudflare Worker that runs [OpenClaw](https://openclaw.ai/) in a Cloudflare Sandbox container. It provides:
- Proxying to the OpenClaw gateway (web UI + WebSocket)
- Admin UI at `/_admin/` for device management
- API endpoints at `/api/*` for device pairing
- Debug endpoints at `/debug/*` for troubleshooting

**Note:** The CLI tool is still named `clawdbot` (upstream hasn't renamed yet), so CLI commands and internal config paths still use that name.

## Project Structure

```
Expand All @@ -23,7 +21,7 @@ src/
│ ├── jwt.ts # JWT verification
│ ├── jwks.ts # JWKS fetching and caching
│ └── middleware.ts # Hono middleware for auth
├── gateway/ # Moltbot gateway management
├── gateway/ # OpenClaw gateway management
│ ├── process.ts # Process lifecycle (find, start)
│ ├── env.ts # Environment variable building
│ ├── r2.ts # R2 bucket mounting
Expand All @@ -43,16 +41,15 @@ src/

### Environment Variables

- `DEV_MODE` - Skips CF Access auth AND bypasses device pairing (maps to `CLAWDBOT_DEV_MODE` for container)
- `DEV_MODE` - Skips CF Access auth AND bypasses device pairing (maps to `OPENCLAW_DEV_MODE` for container)
- `DEBUG_ROUTES` - Enables `/debug/*` routes (disabled by default)
- See `src/types.ts` for full `MoltbotEnv` interface

### CLI Commands

When calling the moltbot CLI from the worker, always include `--url ws://localhost:18789`.
Note: The CLI is still named `clawdbot` until upstream renames it:
When calling the openclaw CLI from the worker, always include `--url ws://localhost:18789`.
```typescript
sandbox.startProcess('clawdbot devices list --json --url ws://localhost:18789')
sandbox.startProcess('openclaw devices list --json --url ws://localhost:18789')
```

CLI commands take 10-15 seconds due to WebSocket connection overhead. Use `waitForProcess()` helper in `src/routes/api.ts`.
Expand Down Expand Up @@ -114,7 +111,7 @@ Browser
┌─────────────────────────────────────┐
│ Cloudflare Worker (index.ts) │
│ - Starts Moltbot in sandbox
│ - Starts OpenClaw in sandbox │
│ - Proxies HTTP/WebSocket requests │
│ - Passes secrets as env vars │
└──────────────┬──────────────────────┘
Expand All @@ -123,7 +120,7 @@ Browser
┌─────────────────────────────────────┐
│ Cloudflare Sandbox Container │
│ ┌───────────────────────────────┐ │
│ │ Moltbot Gateway │ │
│ │ OpenClaw Gateway │ │
│ │ - Control UI on port 18789 │ │
│ │ - WebSocket RPC protocol │ │
│ │ - Agent runtime │ │
Expand All @@ -136,9 +133,9 @@ Browser
| File | Purpose |
|------|---------|
| `src/index.ts` | Worker that manages sandbox lifecycle and proxies requests |
| `Dockerfile` | Container image based on `cloudflare/sandbox` with Node 22 + Moltbot |
| `start-moltbot.sh` | Startup script that configures moltbot from env vars and launches gateway |
| `moltbot.json.template` | Default Moltbot configuration template |
| `Dockerfile` | Container image based on `cloudflare/sandbox` with Node 22 + OpenClaw |
| `start-moltbot.sh` | Startup script that configures openclaw from env vars and launches gateway |
| `moltbot.json.template` | Default OpenClaw configuration template |
| `wrangler.jsonc` | Cloudflare Worker + Container configuration |

## Local Development
Expand Down Expand Up @@ -169,14 +166,14 @@ Local development with `wrangler dev` has issues proxying WebSocket connections
The Dockerfile includes a cache bust comment. When changing `moltbot.json.template` or `start-moltbot.sh`, bump the version:

```dockerfile
# Build cache bust: 2026-01-26-v10
# Build cache bust: 2026-02-05-v28-workspace-persistence
```

## Gateway Configuration

Moltbot configuration is built at container startup:
OpenClaw configuration is built at container startup:

1. `moltbot.json.template` is copied to `~/.clawdbot/clawdbot.json` (internal path unchanged)
1. `moltbot.json.template` is copied to `~/.openclaw/openclaw.json`
2. `start-moltbot.sh` updates the config with values from environment variables
3. Gateway starts with `--allow-unconfigured` flag (skips onboarding wizard)

Expand All @@ -186,24 +183,24 @@ These are the env vars passed TO the container (internal names):

| Variable | Config Path | Notes |
|----------|-------------|-------|
| `ANTHROPIC_API_KEY` | (env var) | Moltbot reads directly from env |
| `CLAWDBOT_GATEWAY_TOKEN` | `--token` flag | Mapped from `MOLTBOT_GATEWAY_TOKEN` |
| `CLAWDBOT_DEV_MODE` | `controlUi.allowInsecureAuth` | Mapped from `DEV_MODE` |
| `ANTHROPIC_API_KEY` | (env var) | OpenClaw reads directly from env |
| `OPENCLAW_GATEWAY_TOKEN` | `--token` flag | Mapped from `MOLTBOT_GATEWAY_TOKEN` |
| `OPENCLAW_DEV_MODE` | `controlUi.allowInsecureAuth` | Mapped from `DEV_MODE` |
| `TELEGRAM_BOT_TOKEN` | `channels.telegram.botToken` | |
| `DISCORD_BOT_TOKEN` | `channels.discord.token` | |
| `SLACK_BOT_TOKEN` | `channels.slack.botToken` | |
| `SLACK_APP_TOKEN` | `channels.slack.appToken` | |

## Moltbot Config Schema
## OpenClaw Config Schema

Moltbot has strict config validation. Common gotchas:
OpenClaw has strict config validation. Common gotchas:

- `agents.defaults.model` must be `{ "primary": "model/name" }` not a string
- `gateway.mode` must be `"local"` for headless operation
- No `webchat` channel - the Control UI is served automatically
- `gateway.bind` is not a config option - use `--bind` CLI flag

See [Moltbot docs](https://docs.molt.bot/gateway/configuration) for full schema.
See [OpenClaw docs](https://docs.openclaw.ai/gateway/configuration) for full schema.

## Common Tasks

Expand Down Expand Up @@ -235,7 +232,12 @@ Enable debug routes with `DEBUG_ROUTES=true` and check `/debug/processes`.

## R2 Storage Notes

R2 is mounted via s3fs at `/data/moltbot`. Important gotchas:
R2 is mounted via s3fs at `/data/moltbot`. The following directories are synced to R2:
- `/root/.openclaw/` → `openclaw/` (config, sessions, paired devices)
- `/root/clawd/skills/` → `skills/` (custom skills)
- `/root/clawd/` → `workspace/` (MEMORY.md, IDENTITY.md, memory/, user files)

Important gotchas:

- **rsync compatibility**: Use `rsync -r --no-times` instead of `rsync -a`. s3fs doesn't support setting timestamps, which causes rsync to fail with "Input/output error".

Expand Down
29 changes: 18 additions & 11 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM docker.io/cloudflare/sandbox:0.7.0

# Install Node.js 22 (required by clawdbot) and rsync (for R2 backup sync)
# Install Node.js 22 (required by openclaw) and rsync (for R2 backup sync)
# The base image has Node 20, we need to replace it with Node 22
# Using direct binary download for reliability
ENV NODE_VERSION=22.13.1
Expand All @@ -20,25 +20,32 @@ RUN ARCH="$(dpkg --print-architecture)" \
# Install pnpm globally
RUN npm install -g pnpm

# Install moltbot (CLI is still named clawdbot until upstream renames)
# Install openclaw
# Pin to specific version for reproducible builds
RUN npm install -g clawdbot@2026.1.24-3 \
&& clawdbot --version

# Create moltbot directories (paths still use clawdbot until upstream renames)
# Templates are stored in /root/.clawdbot-templates for initialization
RUN mkdir -p /root/.clawdbot \
&& mkdir -p /root/.clawdbot-templates \
# Skip optional deps (like Puppeteer/Chromium) to reduce size
# Clean up caches to reduce layer size
ENV PUPPETEER_SKIP_DOWNLOAD=true
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=true
RUN npm install -g openclaw@2026.2.1 --omit=optional \
&& openclaw --version \
&& npm cache clean --force \
&& rm -rf /root/.npm /tmp/* /var/cache/apt/archives/* \
&& apt-get clean

# Create openclaw directories
# Templates are stored in /root/.openclaw-templates for initialization
RUN mkdir -p /root/.openclaw \
&& mkdir -p /root/.openclaw-templates \
&& mkdir -p /root/clawd \
&& mkdir -p /root/clawd/skills

# Copy startup script
# Build cache bust: 2026-01-28-v26-browser-skill
# Build cache bust: 2026-02-05-v28-workspace-persistence
COPY start-moltbot.sh /usr/local/bin/start-moltbot.sh
RUN chmod +x /usr/local/bin/start-moltbot.sh

# Copy default configuration template
COPY moltbot.json.template /root/.clawdbot-templates/moltbot.json.template
COPY moltbot.json.template /root/.openclaw-templates/moltbot.json.template

# Copy custom skills
COPY skills/ /root/clawd/skills/
Expand Down
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ To use the admin UI at `/_admin/` for device management, you need to:
The easiest way to protect your worker is using the built-in Cloudflare Access integration for workers.dev:

1. Go to the [Workers & Pages dashboard](https://dash.cloudflare.com/?to=/:account/workers-and-pages)
2. Select your Worker (e.g., `moltbot-sandbox`)
2. Select your Worker (e.g., `openclaw-sandbox`)
3. In **Settings**, under **Domains & Routes**, in the `workers.dev` row, click the meatballs menu (`...`)
4. Click **Enable Cloudflare Access**
5. Click **Manage Cloudflare Access** to configure who can access:
Expand Down Expand Up @@ -124,7 +124,7 @@ If you prefer more control, you can manually create an Access application:
1. Go to [Cloudflare Zero Trust Dashboard](https://one.dash.cloudflare.com/)
2. Navigate to **Access** > **Applications**
3. Create a new **Self-hosted** application
4. Set the application domain to your Worker URL (e.g., `moltbot-sandbox.your-subdomain.workers.dev`)
4. Set the application domain to your Worker URL (e.g., `openclaw-sandbox.your-subdomain.workers.dev`)
5. Add paths to protect: `/_admin/*`, `/api/*`, `/debug/*`
6. Configure your desired identity providers (e.g., email OTP, Google, GitHub)
7. Copy the **Application Audience (AUD)** tag and set the secrets as shown above
Expand All @@ -140,7 +140,7 @@ DEBUG_ROUTES=true # Enable /debug/* routes (optional)

## Authentication

By default, moltbot uses **device pairing** for authentication. When a new device (browser, CLI, etc.) connects, it must be approved via the admin UI at `/_admin/`.
By default, OpenClaw uses **device pairing** for authentication. When a new device (browser, CLI, etc.) connects, it must be approved via the admin UI at `/_admin/`.

### Device Pairing

Expand All @@ -166,7 +166,7 @@ For local development only, set `DEV_MODE=true` in `.dev.vars` to skip Cloudflar

## Persistent Storage (R2)

By default, moltbot data (configs, paired devices, conversation history) is lost when the container restarts. To enable persistent storage across sessions, configure R2:
By default, OpenClaw data (configs, paired devices, conversation history) is lost when the container restarts. To enable persistent storage across sessions, configure R2:

### 1. Create R2 API Token

Expand Down Expand Up @@ -196,18 +196,18 @@ To find your Account ID: Go to the [Cloudflare Dashboard](https://dash.cloudflar
R2 storage uses a backup/restore approach for simplicity:

**On container startup:**
- If R2 is mounted and contains backup data, it's restored to the moltbot config directory
- If R2 is mounted and contains backup data, it's restored to the OpenClaw config directory
- OpenClaw uses its default paths (no special configuration needed)

**During operation:**
- A cron job runs every 5 minutes to sync the moltbot config to R2
- A cron job runs every 5 minutes to sync the OpenClaw config to R2
- You can also trigger a manual backup from the admin UI at `/_admin/`

**In the admin UI:**
- When R2 is configured, you'll see "Last backup: [timestamp]"
- Click "Backup Now" to trigger an immediate sync

Without R2 credentials, moltbot still works but uses ephemeral storage (data lost on container restart).
Without R2 credentials, OpenClaw still works but uses ephemeral storage (data lost on container restart).

## Container Lifecycle

Expand All @@ -228,7 +228,7 @@ When the container sleeps, the next request will trigger a cold start. If you ha

Access the admin UI at `/_admin/` to:
- **R2 Storage Status** - Shows if R2 is configured, last backup time, and a "Backup Now" button
- **Restart Gateway** - Kill and restart the moltbot gateway process
- **Restart Gateway** - Kill and restart the OpenClaw gateway process
- **Device Pairing** - View pending requests, approve devices individually or all at once, view paired devices

The admin UI requires Cloudflare Access authentication (or `DEV_MODE=true` for local development).
Expand All @@ -239,7 +239,7 @@ Debug endpoints are available at `/debug/*` when enabled (requires `DEBUG_ROUTES

- `GET /debug/processes` - List all container processes
- `GET /debug/logs?id=<process_id>` - Get logs for a specific process
- `GET /debug/version` - Get container and moltbot version info
- `GET /debug/version` - Get container and OpenClaw version info

## Optional: Chat Channels

Expand Down
Loading