Add ez-assistant and kerberos service folders
This commit is contained in:
141
docker-compose/ez-assistant/docs/platforms/android.md
Normal file
141
docker-compose/ez-assistant/docs/platforms/android.md
Normal file
@@ -0,0 +1,141 @@
|
||||
---
|
||||
summary: "Android app (node): connection runbook + Canvas/Chat/Camera"
|
||||
read_when:
|
||||
- Pairing or reconnecting the Android node
|
||||
- Debugging Android gateway discovery or auth
|
||||
- Verifying chat history parity across clients
|
||||
---
|
||||
|
||||
# Android App (Node)
|
||||
|
||||
## Support snapshot
|
||||
- Role: companion node app (Android does not host the Gateway).
|
||||
- Gateway required: yes (run it on macOS, Linux, or Windows via WSL2).
|
||||
- Install: [Getting Started](/start/getting-started) + [Pairing](/gateway/pairing).
|
||||
- Gateway: [Runbook](/gateway) + [Configuration](/gateway/configuration).
|
||||
- Protocols: [Gateway protocol](/gateway/protocol) (nodes + control plane).
|
||||
|
||||
## System control
|
||||
System control (launchd/systemd) lives on the Gateway host. See [Gateway](/gateway).
|
||||
|
||||
## Connection Runbook
|
||||
|
||||
Android node app ⇄ (mDNS/NSD + WebSocket) ⇄ **Gateway**
|
||||
|
||||
Android connects directly to the Gateway WebSocket (default `ws://<host>:18789`) and uses Gateway-owned pairing.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- You can run the Gateway on the “master” machine.
|
||||
- Android device/emulator can reach the gateway WebSocket:
|
||||
- Same LAN with mDNS/NSD, **or**
|
||||
- Same Tailscale tailnet using Wide-Area Bonjour / unicast DNS-SD (see below), **or**
|
||||
- Manual gateway host/port (fallback)
|
||||
- You can run the CLI (`moltbot`) on the gateway machine (or via SSH).
|
||||
|
||||
### 1) Start the Gateway
|
||||
|
||||
```bash
|
||||
moltbot gateway --port 18789 --verbose
|
||||
```
|
||||
|
||||
Confirm in logs you see something like:
|
||||
- `listening on ws://0.0.0.0:18789`
|
||||
|
||||
For tailnet-only setups (recommended for Vienna ⇄ London), bind the gateway to the tailnet IP:
|
||||
|
||||
- Set `gateway.bind: "tailnet"` in `~/.clawdbot/moltbot.json` on the gateway host.
|
||||
- Restart the Gateway / macOS menubar app.
|
||||
|
||||
### 2) Verify discovery (optional)
|
||||
|
||||
From the gateway machine:
|
||||
|
||||
```bash
|
||||
dns-sd -B _moltbot-gw._tcp local.
|
||||
```
|
||||
|
||||
More debugging notes: [Bonjour](/gateway/bonjour).
|
||||
|
||||
#### Tailnet (Vienna ⇄ London) discovery via unicast DNS-SD
|
||||
|
||||
Android NSD/mDNS discovery won’t cross networks. If your Android node and the gateway are on different networks but connected via Tailscale, use Wide-Area Bonjour / unicast DNS-SD instead:
|
||||
|
||||
1) Set up a DNS-SD zone (example `moltbot.internal.`) on the gateway host and publish `_moltbot-gw._tcp` records.
|
||||
2) Configure Tailscale split DNS for `moltbot.internal` pointing at that DNS server.
|
||||
|
||||
Details and example CoreDNS config: [Bonjour](/gateway/bonjour).
|
||||
|
||||
### 3) Connect from Android
|
||||
|
||||
In the Android app:
|
||||
|
||||
- The app keeps its gateway connection alive via a **foreground service** (persistent notification).
|
||||
- Open **Settings**.
|
||||
- Under **Discovered Gateways**, select your gateway and hit **Connect**.
|
||||
- If mDNS is blocked, use **Advanced → Manual Gateway** (host + port) and **Connect (Manual)**.
|
||||
|
||||
After the first successful pairing, Android auto-reconnects on launch:
|
||||
- Manual endpoint (if enabled), otherwise
|
||||
- The last discovered gateway (best-effort).
|
||||
|
||||
### 4) Approve pairing (CLI)
|
||||
|
||||
On the gateway machine:
|
||||
|
||||
```bash
|
||||
moltbot nodes pending
|
||||
moltbot nodes approve <requestId>
|
||||
```
|
||||
|
||||
Pairing details: [Gateway pairing](/gateway/pairing).
|
||||
|
||||
### 5) Verify the node is connected
|
||||
|
||||
- Via nodes status:
|
||||
```bash
|
||||
moltbot nodes status
|
||||
```
|
||||
- Via Gateway:
|
||||
```bash
|
||||
moltbot gateway call node.list --params "{}"
|
||||
```
|
||||
|
||||
### 6) Chat + history
|
||||
|
||||
The Android node’s Chat sheet uses the gateway’s **primary session key** (`main`), so history and replies are shared with WebChat and other clients:
|
||||
|
||||
- History: `chat.history`
|
||||
- Send: `chat.send`
|
||||
- Push updates (best-effort): `chat.subscribe` → `event:"chat"`
|
||||
|
||||
### 7) Canvas + camera
|
||||
|
||||
#### Gateway Canvas Host (recommended for web content)
|
||||
|
||||
If you want the node to show real HTML/CSS/JS that the agent can edit on disk, point the node at the Gateway canvas host.
|
||||
|
||||
Note: nodes use the standalone canvas host on `canvasHost.port` (default `18793`).
|
||||
|
||||
1) Create `~/clawd/canvas/index.html` on the gateway host.
|
||||
|
||||
2) Navigate the node to it (LAN):
|
||||
|
||||
```bash
|
||||
moltbot nodes invoke --node "<Android Node>" --command canvas.navigate --params '{"url":"http://<gateway-hostname>.local:18793/__moltbot__/canvas/"}'
|
||||
```
|
||||
|
||||
Tailnet (optional): if both devices are on Tailscale, use a MagicDNS name or tailnet IP instead of `.local`, e.g. `http://<gateway-magicdns>:18793/__moltbot__/canvas/`.
|
||||
|
||||
This server injects a live-reload client into HTML and reloads on file changes.
|
||||
The A2UI host lives at `http://<gateway-host>:18793/__moltbot__/a2ui/`.
|
||||
|
||||
Canvas commands (foreground only):
|
||||
- `canvas.eval`, `canvas.snapshot`, `canvas.navigate` (use `{"url":""}` or `{"url":"/"}` to return to the default scaffold). `canvas.snapshot` returns `{ format, base64 }` (default `format="jpeg"`).
|
||||
- A2UI: `canvas.a2ui.push`, `canvas.a2ui.reset` (`canvas.a2ui.pushJSONL` legacy alias)
|
||||
|
||||
Camera commands (foreground only; permission-gated):
|
||||
- `camera.snap` (jpg)
|
||||
- `camera.clip` (mp4)
|
||||
|
||||
See [Camera node](/nodes/camera) for parameters and CLI helpers.
|
||||
243
docker-compose/ez-assistant/docs/platforms/digitalocean.md
Normal file
243
docker-compose/ez-assistant/docs/platforms/digitalocean.md
Normal file
@@ -0,0 +1,243 @@
|
||||
---
|
||||
summary: "Moltbot on DigitalOcean (simple paid VPS option)"
|
||||
read_when:
|
||||
- Setting up Moltbot on DigitalOcean
|
||||
- Looking for cheap VPS hosting for Moltbot
|
||||
---
|
||||
|
||||
# Moltbot on DigitalOcean
|
||||
|
||||
## Goal
|
||||
|
||||
Run a persistent Moltbot Gateway on DigitalOcean for **$6/month** (or $4/mo with reserved pricing).
|
||||
|
||||
If you want a $0/month option and don’t mind ARM + provider-specific setup, see the [Oracle Cloud guide](/platforms/oracle).
|
||||
|
||||
## Cost Comparison (2026)
|
||||
|
||||
| Provider | Plan | Specs | Price/mo | Notes |
|
||||
|----------|------|-------|----------|-------|
|
||||
| Oracle Cloud | Always Free ARM | up to 4 OCPU, 24GB RAM | $0 | ARM, limited capacity / signup quirks |
|
||||
| Hetzner | CX22 | 2 vCPU, 4GB RAM | €3.79 (~$4) | Cheapest paid option |
|
||||
| DigitalOcean | Basic | 1 vCPU, 1GB RAM | $6 | Easy UI, good docs |
|
||||
| Vultr | Cloud Compute | 1 vCPU, 1GB RAM | $6 | Many locations |
|
||||
| Linode | Nanode | 1 vCPU, 1GB RAM | $5 | Now part of Akamai |
|
||||
|
||||
**Picking a provider:**
|
||||
- DigitalOcean: simplest UX + predictable setup (this guide)
|
||||
- Hetzner: good price/perf (see [Hetzner guide](/platforms/hetzner))
|
||||
- Oracle Cloud: can be $0/month, but is more finicky and ARM-only (see [Oracle guide](/platforms/oracle))
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- DigitalOcean account ([signup with $200 free credit](https://m.do.co/c/signup))
|
||||
- SSH key pair (or willingness to use password auth)
|
||||
- ~20 minutes
|
||||
|
||||
## 1) Create a Droplet
|
||||
|
||||
1. Log into [DigitalOcean](https://cloud.digitalocean.com/)
|
||||
2. Click **Create → Droplets**
|
||||
3. Choose:
|
||||
- **Region:** Closest to you (or your users)
|
||||
- **Image:** Ubuntu 24.04 LTS
|
||||
- **Size:** Basic → Regular → **$6/mo** (1 vCPU, 1GB RAM, 25GB SSD)
|
||||
- **Authentication:** SSH key (recommended) or password
|
||||
4. Click **Create Droplet**
|
||||
5. Note the IP address
|
||||
|
||||
## 2) Connect via SSH
|
||||
|
||||
```bash
|
||||
ssh root@YOUR_DROPLET_IP
|
||||
```
|
||||
|
||||
## 3) Install Moltbot
|
||||
|
||||
```bash
|
||||
# Update system
|
||||
apt update && apt upgrade -y
|
||||
|
||||
# Install Node.js 22
|
||||
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
||||
apt install -y nodejs
|
||||
|
||||
# Install Moltbot
|
||||
curl -fsSL https://molt.bot/install.sh | bash
|
||||
|
||||
# Verify
|
||||
moltbot --version
|
||||
```
|
||||
|
||||
## 4) Run Onboarding
|
||||
|
||||
```bash
|
||||
moltbot onboard --install-daemon
|
||||
```
|
||||
|
||||
The wizard will walk you through:
|
||||
- Model auth (API keys or OAuth)
|
||||
- Channel setup (Telegram, WhatsApp, Discord, etc.)
|
||||
- Gateway token (auto-generated)
|
||||
- Daemon installation (systemd)
|
||||
|
||||
## 5) Verify the Gateway
|
||||
|
||||
```bash
|
||||
# Check status
|
||||
moltbot status
|
||||
|
||||
# Check service
|
||||
systemctl --user status moltbot-gateway.service
|
||||
|
||||
# View logs
|
||||
journalctl --user -u moltbot-gateway.service -f
|
||||
```
|
||||
|
||||
## 6) Access the Dashboard
|
||||
|
||||
The gateway binds to loopback by default. To access the Control UI:
|
||||
|
||||
**Option A: SSH Tunnel (recommended)**
|
||||
```bash
|
||||
# From your local machine
|
||||
ssh -L 18789:localhost:18789 root@YOUR_DROPLET_IP
|
||||
|
||||
# Then open: http://localhost:18789
|
||||
```
|
||||
|
||||
**Option B: Tailscale Serve (HTTPS, loopback-only)**
|
||||
```bash
|
||||
# On the droplet
|
||||
curl -fsSL https://tailscale.com/install.sh | sh
|
||||
tailscale up
|
||||
|
||||
# Configure Gateway to use Tailscale Serve
|
||||
moltbot config set gateway.tailscale.mode serve
|
||||
moltbot gateway restart
|
||||
```
|
||||
|
||||
Open: `https://<magicdns>/`
|
||||
|
||||
Notes:
|
||||
- Serve keeps the Gateway loopback-only and authenticates via Tailscale identity headers.
|
||||
- To require token/password instead, set `gateway.auth.allowTailscale: false` or use `gateway.auth.mode: "password"`.
|
||||
|
||||
**Option C: Tailnet bind (no Serve)**
|
||||
```bash
|
||||
moltbot config set gateway.bind tailnet
|
||||
moltbot gateway restart
|
||||
```
|
||||
|
||||
Open: `http://<tailscale-ip>:18789` (token required).
|
||||
|
||||
## 7) Connect Your Channels
|
||||
|
||||
### Telegram
|
||||
```bash
|
||||
moltbot pairing list telegram
|
||||
moltbot pairing approve telegram <CODE>
|
||||
```
|
||||
|
||||
### WhatsApp
|
||||
```bash
|
||||
moltbot channels login whatsapp
|
||||
# Scan QR code
|
||||
```
|
||||
|
||||
See [Channels](/channels) for other providers.
|
||||
|
||||
---
|
||||
|
||||
## Optimizations for 1GB RAM
|
||||
|
||||
The $6 droplet only has 1GB RAM. To keep things running smoothly:
|
||||
|
||||
### Add swap (recommended)
|
||||
```bash
|
||||
fallocate -l 2G /swapfile
|
||||
chmod 600 /swapfile
|
||||
mkswap /swapfile
|
||||
swapon /swapfile
|
||||
echo '/swapfile none swap sw 0 0' >> /etc/fstab
|
||||
```
|
||||
|
||||
### Use a lighter model
|
||||
If you're hitting OOMs, consider:
|
||||
- Using API-based models (Claude, GPT) instead of local models
|
||||
- Setting `agents.defaults.model.primary` to a smaller model
|
||||
|
||||
### Monitor memory
|
||||
```bash
|
||||
free -h
|
||||
htop
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Persistence
|
||||
|
||||
All state lives in:
|
||||
- `~/.clawdbot/` — config, credentials, session data
|
||||
- `~/clawd/` — workspace (SOUL.md, memory, etc.)
|
||||
|
||||
These survive reboots. Back them up periodically:
|
||||
```bash
|
||||
tar -czvf moltbot-backup.tar.gz ~/.clawdbot ~/clawd
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Oracle Cloud Free Alternative
|
||||
|
||||
Oracle Cloud offers **Always Free** ARM instances that are significantly more powerful than any paid option here — for $0/month.
|
||||
|
||||
| What you get | Specs |
|
||||
|--------------|-------|
|
||||
| **4 OCPUs** | ARM Ampere A1 |
|
||||
| **24GB RAM** | More than enough |
|
||||
| **200GB storage** | Block volume |
|
||||
| **Forever free** | No credit card charges |
|
||||
|
||||
**Caveats:**
|
||||
- Signup can be finicky (retry if it fails)
|
||||
- ARM architecture — most things work, but some binaries need ARM builds
|
||||
|
||||
For the full setup guide, see [Oracle Cloud](/platforms/oracle). For signup tips and troubleshooting the enrollment process, see this [community guide](https://gist.github.com/rssnyder/51e3cfedd730e7dd5f4a816143b25dbd).
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Gateway won't start
|
||||
```bash
|
||||
moltbot gateway status
|
||||
moltbot doctor --non-interactive
|
||||
journalctl -u moltbot --no-pager -n 50
|
||||
```
|
||||
|
||||
### Port already in use
|
||||
```bash
|
||||
lsof -i :18789
|
||||
kill <PID>
|
||||
```
|
||||
|
||||
### Out of memory
|
||||
```bash
|
||||
# Check memory
|
||||
free -h
|
||||
|
||||
# Add more swap
|
||||
# Or upgrade to $12/mo droplet (2GB RAM)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Hetzner guide](/platforms/hetzner) — cheaper, more powerful
|
||||
- [Docker install](/install/docker) — containerized setup
|
||||
- [Tailscale](/gateway/tailscale) — secure remote access
|
||||
- [Configuration](/gateway/configuration) — full config reference
|
||||
187
docker-compose/ez-assistant/docs/platforms/exe-dev.md
Normal file
187
docker-compose/ez-assistant/docs/platforms/exe-dev.md
Normal file
@@ -0,0 +1,187 @@
|
||||
---
|
||||
summary: "Run Moltbot Gateway on exe.dev (VM + HTTPS proxy) for remote access"
|
||||
read_when:
|
||||
- You want a cheap always-on Linux host for the Gateway
|
||||
- You want remote Control UI access without running your own VPS
|
||||
---
|
||||
|
||||
# exe.dev
|
||||
|
||||
Goal: Moltbot Gateway running on an exe.dev VM, reachable from your laptop via:
|
||||
- **exe.dev HTTPS proxy** (easy, no tunnel) or
|
||||
- **SSH tunnel** (most secure; loopback-only Gateway)
|
||||
|
||||
This page assumes **Ubuntu/Debian**. If you picked a different distro, map packages accordingly.
|
||||
|
||||
If you’re on any other Linux VPS, the same steps apply — you just won’t use the exe.dev proxy commands.
|
||||
|
||||
## Beginner quick path
|
||||
|
||||
1) Create VM → install Node 22 → install Moltbot
|
||||
2) Run `moltbot onboard --install-daemon`
|
||||
3) Tunnel from laptop (`ssh -N -L 18789:127.0.0.1:18789 …`)
|
||||
4) Open `http://127.0.0.1:18789/` and paste your token
|
||||
|
||||
## What you need
|
||||
|
||||
- exe.dev account + `ssh exe.dev` working on your laptop
|
||||
- SSH keys set up (your laptop → exe.dev)
|
||||
- Model auth (OAuth or API key) you want to use
|
||||
- Provider credentials (optional): WhatsApp QR scan, Telegram bot token, Discord bot token, …
|
||||
|
||||
## 1) Create the VM
|
||||
|
||||
From your laptop:
|
||||
|
||||
```bash
|
||||
ssh exe.dev new --name=moltbot
|
||||
```
|
||||
|
||||
Then connect:
|
||||
|
||||
```bash
|
||||
ssh moltbot.exe.xyz
|
||||
```
|
||||
|
||||
Tip: keep this VM **stateful**. Moltbot stores state under `~/.clawdbot/` and `~/clawd/`.
|
||||
|
||||
## 2) Install prerequisites (on the VM)
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y git curl jq ca-certificates openssl
|
||||
```
|
||||
|
||||
### Node 22
|
||||
|
||||
Install Node **>= 22.12** (any method is fine). Quick check:
|
||||
|
||||
```bash
|
||||
node -v
|
||||
```
|
||||
|
||||
If you don’t already have Node 22 on the VM, use your preferred Node manager (nvm/mise/asdf) or a distro package source that provides Node 22+.
|
||||
|
||||
Common Ubuntu/Debian option (NodeSource):
|
||||
|
||||
```bash
|
||||
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
```
|
||||
|
||||
## 3) Install Moltbot
|
||||
|
||||
Recommended on servers: npm global install.
|
||||
|
||||
```bash
|
||||
npm i -g moltbot@latest
|
||||
moltbot --version
|
||||
```
|
||||
|
||||
If native deps fail to install (rare; usually `sharp`), add build tools:
|
||||
|
||||
```bash
|
||||
sudo apt-get install -y build-essential python3
|
||||
```
|
||||
|
||||
## 4) First-time setup (wizard)
|
||||
|
||||
Run the onboarding wizard on the VM:
|
||||
|
||||
```bash
|
||||
moltbot onboard --install-daemon
|
||||
```
|
||||
|
||||
It can set up:
|
||||
- `~/clawd` workspace bootstrap
|
||||
- `~/.clawdbot/moltbot.json` config
|
||||
- model auth profiles
|
||||
- model provider config/login
|
||||
- Linux systemd **user** service (service)
|
||||
|
||||
If you’re doing OAuth on a headless VM: do OAuth on a normal machine first, then copy the auth profile to the VM (see [Help](/help)).
|
||||
|
||||
## 5) Remote access options
|
||||
|
||||
### Option A (recommended): SSH tunnel (loopback-only)
|
||||
|
||||
Keep Gateway on loopback (default) and tunnel it from your laptop:
|
||||
|
||||
```bash
|
||||
ssh -N -L 18789:127.0.0.1:18789 moltbot.exe.xyz
|
||||
```
|
||||
|
||||
Open locally:
|
||||
- `http://127.0.0.1:18789/` (Control UI)
|
||||
|
||||
Runbook: [Remote access](/gateway/remote)
|
||||
|
||||
### Option B: exe.dev HTTPS proxy (no tunnel)
|
||||
|
||||
To let exe.dev proxy traffic to the VM, bind the Gateway to the LAN interface and set a token:
|
||||
|
||||
```bash
|
||||
export CLAWDBOT_GATEWAY_TOKEN="$(openssl rand -hex 32)"
|
||||
moltbot gateway --bind lan --port 8080 --token "$CLAWDBOT_GATEWAY_TOKEN"
|
||||
```
|
||||
|
||||
For service runs, persist it in `~/.clawdbot/moltbot.json`:
|
||||
|
||||
```json5
|
||||
{
|
||||
gateway: {
|
||||
mode: "local",
|
||||
port: 8080,
|
||||
bind: "lan",
|
||||
auth: { mode: "token", token: "YOUR_TOKEN" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
- Non-loopback binds require `gateway.auth.token` (or `CLAWDBOT_GATEWAY_TOKEN`).
|
||||
- `gateway.remote.token` is only for remote CLI calls; it does not enable local auth.
|
||||
|
||||
Then point exe.dev’s proxy at `8080` (or whatever port you chose) and open your VM’s HTTPS URL:
|
||||
|
||||
```bash
|
||||
ssh exe.dev share port moltbot 8080
|
||||
```
|
||||
|
||||
Open:
|
||||
- `https://moltbot.exe.xyz/`
|
||||
|
||||
In the Control UI, paste the token (UI → Settings → token). The UI sends it as `connect.params.auth.token`.
|
||||
|
||||
Notes:
|
||||
- Prefer a **non-default** port (like `8080`) if your proxy expects an app port.
|
||||
- Treat the token like a password.
|
||||
|
||||
Control UI details: [Control UI](/web/control-ui)
|
||||
|
||||
## 6) Keep it running (service)
|
||||
|
||||
On Linux, Moltbot uses a systemd **user** service. After `--install-daemon`, verify:
|
||||
|
||||
```bash
|
||||
systemctl --user status moltbot-gateway[-<profile>].service
|
||||
```
|
||||
|
||||
If the service dies after logout, enable lingering:
|
||||
|
||||
```bash
|
||||
sudo loginctl enable-linger "$USER"
|
||||
```
|
||||
|
||||
More: [Linux](/platforms/linux)
|
||||
|
||||
## 7) Updates
|
||||
|
||||
```bash
|
||||
npm i -g moltbot@latest
|
||||
moltbot doctor
|
||||
moltbot gateway restart
|
||||
moltbot health
|
||||
```
|
||||
|
||||
Guide: [Updating](/install/updating)
|
||||
465
docker-compose/ez-assistant/docs/platforms/fly.md
Normal file
465
docker-compose/ez-assistant/docs/platforms/fly.md
Normal file
@@ -0,0 +1,465 @@
|
||||
---
|
||||
title: Fly.io
|
||||
description: Deploy Moltbot on Fly.io
|
||||
---
|
||||
|
||||
# Fly.io Deployment
|
||||
|
||||
**Goal:** Moltbot Gateway running on a [Fly.io](https://fly.io) machine with persistent storage, automatic HTTPS, and Discord/channel access.
|
||||
|
||||
## What you need
|
||||
|
||||
- [flyctl CLI](https://fly.io/docs/hands-on/install-flyctl/) installed
|
||||
- Fly.io account (free tier works)
|
||||
- Model auth: Anthropic API key (or other provider keys)
|
||||
- Channel credentials: Discord bot token, Telegram token, etc.
|
||||
|
||||
## Beginner quick path
|
||||
|
||||
1. Clone repo → customize `fly.toml`
|
||||
2. Create app + volume → set secrets
|
||||
3. Deploy with `fly deploy`
|
||||
4. SSH in to create config or use Control UI
|
||||
|
||||
## 1) Create the Fly app
|
||||
|
||||
```bash
|
||||
# Clone the repo
|
||||
git clone https://github.com/moltbot/moltbot.git
|
||||
cd moltbot
|
||||
|
||||
# Create a new Fly app (pick your own name)
|
||||
fly apps create my-moltbot
|
||||
|
||||
# Create a persistent volume (1GB is usually enough)
|
||||
fly volumes create moltbot_data --size 1 --region iad
|
||||
```
|
||||
|
||||
**Tip:** Choose a region close to you. Common options: `lhr` (London), `iad` (Virginia), `sjc` (San Jose).
|
||||
|
||||
## 2) Configure fly.toml
|
||||
|
||||
Edit `fly.toml` to match your app name and requirements.
|
||||
|
||||
**Security note:** The default config exposes a public URL. For a hardened deployment with no public IP, see [Private Deployment](#private-deployment-hardened) or use `fly.private.toml`.
|
||||
|
||||
```toml
|
||||
app = "my-moltbot" # Your app name
|
||||
primary_region = "iad"
|
||||
|
||||
[build]
|
||||
dockerfile = "Dockerfile"
|
||||
|
||||
[env]
|
||||
NODE_ENV = "production"
|
||||
CLAWDBOT_PREFER_PNPM = "1"
|
||||
CLAWDBOT_STATE_DIR = "/data"
|
||||
NODE_OPTIONS = "--max-old-space-size=1536"
|
||||
|
||||
[processes]
|
||||
app = "node dist/index.js gateway --allow-unconfigured --port 3000 --bind lan"
|
||||
|
||||
[http_service]
|
||||
internal_port = 3000
|
||||
force_https = true
|
||||
auto_stop_machines = false
|
||||
auto_start_machines = true
|
||||
min_machines_running = 1
|
||||
processes = ["app"]
|
||||
|
||||
[[vm]]
|
||||
size = "shared-cpu-2x"
|
||||
memory = "2048mb"
|
||||
|
||||
[mounts]
|
||||
source = "moltbot_data"
|
||||
destination = "/data"
|
||||
```
|
||||
|
||||
**Key settings:**
|
||||
|
||||
| Setting | Why |
|
||||
|---------|-----|
|
||||
| `--bind lan` | Binds to `0.0.0.0` so Fly's proxy can reach the gateway |
|
||||
| `--allow-unconfigured` | Starts without a config file (you'll create one after) |
|
||||
| `internal_port = 3000` | Must match `--port 3000` (or `CLAWDBOT_GATEWAY_PORT`) for Fly health checks |
|
||||
| `memory = "2048mb"` | 512MB is too small; 2GB recommended |
|
||||
| `CLAWDBOT_STATE_DIR = "/data"` | Persists state on the volume |
|
||||
|
||||
## 3) Set secrets
|
||||
|
||||
```bash
|
||||
# Required: Gateway token (for non-loopback binding)
|
||||
fly secrets set CLAWDBOT_GATEWAY_TOKEN=$(openssl rand -hex 32)
|
||||
|
||||
# Model provider API keys
|
||||
fly secrets set ANTHROPIC_API_KEY=sk-ant-...
|
||||
|
||||
# Optional: Other providers
|
||||
fly secrets set OPENAI_API_KEY=sk-...
|
||||
fly secrets set GOOGLE_API_KEY=...
|
||||
|
||||
# Channel tokens
|
||||
fly secrets set DISCORD_BOT_TOKEN=MTQ...
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- Non-loopback binds (`--bind lan`) require `CLAWDBOT_GATEWAY_TOKEN` for security.
|
||||
- Treat these tokens like passwords.
|
||||
- **Prefer env vars over config file** for all API keys and tokens. This keeps secrets out of `moltbot.json` where they could be accidentally exposed or logged.
|
||||
|
||||
## 4) Deploy
|
||||
|
||||
```bash
|
||||
fly deploy
|
||||
```
|
||||
|
||||
First deploy builds the Docker image (~2-3 minutes). Subsequent deploys are faster.
|
||||
|
||||
After deployment, verify:
|
||||
```bash
|
||||
fly status
|
||||
fly logs
|
||||
```
|
||||
|
||||
You should see:
|
||||
```
|
||||
[gateway] listening on ws://0.0.0.0:3000 (PID xxx)
|
||||
[discord] logged in to discord as xxx
|
||||
```
|
||||
|
||||
## 5) Create config file
|
||||
|
||||
SSH into the machine to create a proper config:
|
||||
|
||||
```bash
|
||||
fly ssh console
|
||||
```
|
||||
|
||||
Create the config directory and file:
|
||||
```bash
|
||||
mkdir -p /data
|
||||
cat > /data/moltbot.json << 'EOF'
|
||||
{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"model": {
|
||||
"primary": "anthropic/claude-opus-4-5",
|
||||
"fallbacks": ["anthropic/claude-sonnet-4-5", "openai/gpt-4o"]
|
||||
},
|
||||
"maxConcurrent": 4
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"id": "main",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"auth": {
|
||||
"profiles": {
|
||||
"anthropic:default": { "mode": "token", "provider": "anthropic" },
|
||||
"openai:default": { "mode": "token", "provider": "openai" }
|
||||
}
|
||||
},
|
||||
"bindings": [
|
||||
{
|
||||
"agentId": "main",
|
||||
"match": { "channel": "discord" }
|
||||
}
|
||||
],
|
||||
"channels": {
|
||||
"discord": {
|
||||
"enabled": true,
|
||||
"groupPolicy": "allowlist",
|
||||
"guilds": {
|
||||
"YOUR_GUILD_ID": {
|
||||
"channels": { "general": { "allow": true } },
|
||||
"requireMention": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gateway": {
|
||||
"mode": "local",
|
||||
"bind": "auto"
|
||||
},
|
||||
"meta": {
|
||||
"lastTouchedVersion": "2026.1.26"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
**Note:** With `CLAWDBOT_STATE_DIR=/data`, the config path is `/data/moltbot.json`.
|
||||
|
||||
**Note:** The Discord token can come from either:
|
||||
- Environment variable: `DISCORD_BOT_TOKEN` (recommended for secrets)
|
||||
- Config file: `channels.discord.token`
|
||||
|
||||
If using env var, no need to add token to config. The gateway reads `DISCORD_BOT_TOKEN` automatically.
|
||||
|
||||
Restart to apply:
|
||||
```bash
|
||||
exit
|
||||
fly machine restart <machine-id>
|
||||
```
|
||||
|
||||
## 6) Access the Gateway
|
||||
|
||||
### Control UI
|
||||
|
||||
Open in browser:
|
||||
```bash
|
||||
fly open
|
||||
```
|
||||
|
||||
Or visit `https://my-moltbot.fly.dev/`
|
||||
|
||||
Paste your gateway token (the one from `CLAWDBOT_GATEWAY_TOKEN`) to authenticate.
|
||||
|
||||
### Logs
|
||||
|
||||
```bash
|
||||
fly logs # Live logs
|
||||
fly logs --no-tail # Recent logs
|
||||
```
|
||||
|
||||
### SSH Console
|
||||
|
||||
```bash
|
||||
fly ssh console
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "App is not listening on expected address"
|
||||
|
||||
The gateway is binding to `127.0.0.1` instead of `0.0.0.0`.
|
||||
|
||||
**Fix:** Add `--bind lan` to your process command in `fly.toml`.
|
||||
|
||||
### Health checks failing / connection refused
|
||||
|
||||
Fly can't reach the gateway on the configured port.
|
||||
|
||||
**Fix:** Ensure `internal_port` matches the gateway port (set `--port 3000` or `CLAWDBOT_GATEWAY_PORT=3000`).
|
||||
|
||||
### OOM / Memory Issues
|
||||
|
||||
Container keeps restarting or getting killed. Signs: `SIGABRT`, `v8::internal::Runtime_AllocateInYoungGeneration`, or silent restarts.
|
||||
|
||||
**Fix:** Increase memory in `fly.toml`:
|
||||
```toml
|
||||
[[vm]]
|
||||
memory = "2048mb"
|
||||
```
|
||||
|
||||
Or update an existing machine:
|
||||
```bash
|
||||
fly machine update <machine-id> --vm-memory 2048 -y
|
||||
```
|
||||
|
||||
**Note:** 512MB is too small. 1GB may work but can OOM under load or with verbose logging. **2GB is recommended.**
|
||||
|
||||
### Gateway Lock Issues
|
||||
|
||||
Gateway refuses to start with "already running" errors.
|
||||
|
||||
This happens when the container restarts but the PID lock file persists on the volume.
|
||||
|
||||
**Fix:** Delete the lock file:
|
||||
```bash
|
||||
fly ssh console --command "rm -f /data/gateway.*.lock"
|
||||
fly machine restart <machine-id>
|
||||
```
|
||||
|
||||
The lock file is at `/data/gateway.*.lock` (not in a subdirectory).
|
||||
|
||||
### Config Not Being Read
|
||||
|
||||
If using `--allow-unconfigured`, the gateway creates a minimal config. Your custom config at `/data/moltbot.json` should be read on restart.
|
||||
|
||||
Verify the config exists:
|
||||
```bash
|
||||
fly ssh console --command "cat /data/moltbot.json"
|
||||
```
|
||||
|
||||
### Writing Config via SSH
|
||||
|
||||
The `fly ssh console -C` command doesn't support shell redirection. To write a config file:
|
||||
|
||||
```bash
|
||||
# Use echo + tee (pipe from local to remote)
|
||||
echo '{"your":"config"}' | fly ssh console -C "tee /data/moltbot.json"
|
||||
|
||||
# Or use sftp
|
||||
fly sftp shell
|
||||
> put /local/path/config.json /data/moltbot.json
|
||||
```
|
||||
|
||||
**Note:** `fly sftp` may fail if the file already exists. Delete first:
|
||||
```bash
|
||||
fly ssh console --command "rm /data/moltbot.json"
|
||||
```
|
||||
|
||||
### State Not Persisting
|
||||
|
||||
If you lose credentials or sessions after a restart, the state dir is writing to the container filesystem.
|
||||
|
||||
**Fix:** Ensure `CLAWDBOT_STATE_DIR=/data` is set in `fly.toml` and redeploy.
|
||||
|
||||
## Updates
|
||||
|
||||
```bash
|
||||
# Pull latest changes
|
||||
git pull
|
||||
|
||||
# Redeploy
|
||||
fly deploy
|
||||
|
||||
# Check health
|
||||
fly status
|
||||
fly logs
|
||||
```
|
||||
|
||||
### Updating Machine Command
|
||||
|
||||
If you need to change the startup command without a full redeploy:
|
||||
|
||||
```bash
|
||||
# Get machine ID
|
||||
fly machines list
|
||||
|
||||
# Update command
|
||||
fly machine update <machine-id> --command "node dist/index.js gateway --port 3000 --bind lan" -y
|
||||
|
||||
# Or with memory increase
|
||||
fly machine update <machine-id> --vm-memory 2048 --command "node dist/index.js gateway --port 3000 --bind lan" -y
|
||||
```
|
||||
|
||||
**Note:** After `fly deploy`, the machine command may reset to what's in `fly.toml`. If you made manual changes, re-apply them after deploy.
|
||||
|
||||
## Private Deployment (Hardened)
|
||||
|
||||
By default, Fly allocates public IPs, making your gateway accessible at `https://your-app.fly.dev`. This is convenient but means your deployment is discoverable by internet scanners (Shodan, Censys, etc.).
|
||||
|
||||
For a hardened deployment with **no public exposure**, use the private template.
|
||||
|
||||
### When to use private deployment
|
||||
|
||||
- You only make **outbound** calls/messages (no inbound webhooks)
|
||||
- You use **ngrok or Tailscale** tunnels for any webhook callbacks
|
||||
- You access the gateway via **SSH, proxy, or WireGuard** instead of browser
|
||||
- You want the deployment **hidden from internet scanners**
|
||||
|
||||
### Setup
|
||||
|
||||
Use `fly.private.toml` instead of the standard config:
|
||||
|
||||
```bash
|
||||
# Deploy with private config
|
||||
fly deploy -c fly.private.toml
|
||||
```
|
||||
|
||||
Or convert an existing deployment:
|
||||
|
||||
```bash
|
||||
# List current IPs
|
||||
fly ips list -a my-moltbot
|
||||
|
||||
# Release public IPs
|
||||
fly ips release <public-ipv4> -a my-moltbot
|
||||
fly ips release <public-ipv6> -a my-moltbot
|
||||
|
||||
# Switch to private config so future deploys don't re-allocate public IPs
|
||||
# (remove [http_service] or deploy with the private template)
|
||||
fly deploy -c fly.private.toml
|
||||
|
||||
# Allocate private-only IPv6
|
||||
fly ips allocate-v6 --private -a my-moltbot
|
||||
```
|
||||
|
||||
After this, `fly ips list` should show only a `private` type IP:
|
||||
```
|
||||
VERSION IP TYPE REGION
|
||||
v6 fdaa:x:x:x:x::x private global
|
||||
```
|
||||
|
||||
### Accessing a private deployment
|
||||
|
||||
Since there's no public URL, use one of these methods:
|
||||
|
||||
**Option 1: Local proxy (simplest)**
|
||||
```bash
|
||||
# Forward local port 3000 to the app
|
||||
fly proxy 3000:3000 -a my-moltbot
|
||||
|
||||
# Then open http://localhost:3000 in browser
|
||||
```
|
||||
|
||||
**Option 2: WireGuard VPN**
|
||||
```bash
|
||||
# Create WireGuard config (one-time)
|
||||
fly wireguard create
|
||||
|
||||
# Import to WireGuard client, then access via internal IPv6
|
||||
# Example: http://[fdaa:x:x:x:x::x]:3000
|
||||
```
|
||||
|
||||
**Option 3: SSH only**
|
||||
```bash
|
||||
fly ssh console -a my-moltbot
|
||||
```
|
||||
|
||||
### Webhooks with private deployment
|
||||
|
||||
If you need webhook callbacks (Twilio, Telnyx, etc.) without public exposure:
|
||||
|
||||
1. **ngrok tunnel** - Run ngrok inside the container or as a sidecar
|
||||
2. **Tailscale Funnel** - Expose specific paths via Tailscale
|
||||
3. **Outbound-only** - Some providers (Twilio) work fine for outbound calls without webhooks
|
||||
|
||||
Example voice-call config with ngrok:
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"voice-call": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"provider": "twilio",
|
||||
"tunnel": { "provider": "ngrok" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The ngrok tunnel runs inside the container and provides a public webhook URL without exposing the Fly app itself.
|
||||
|
||||
### Security benefits
|
||||
|
||||
| Aspect | Public | Private |
|
||||
|--------|--------|---------|
|
||||
| Internet scanners | Discoverable | Hidden |
|
||||
| Direct attacks | Possible | Blocked |
|
||||
| Control UI access | Browser | Proxy/VPN |
|
||||
| Webhook delivery | Direct | Via tunnel |
|
||||
|
||||
## Notes
|
||||
|
||||
- Fly.io uses **x86 architecture** (not ARM)
|
||||
- The Dockerfile is compatible with both architectures
|
||||
- For WhatsApp/Telegram onboarding, use `fly ssh console`
|
||||
- Persistent data lives on the volume at `/data`
|
||||
- Signal requires Java + signal-cli; use a custom image and keep memory at 2GB+.
|
||||
|
||||
## Cost
|
||||
|
||||
With the recommended config (`shared-cpu-2x`, 2GB RAM):
|
||||
- ~$10-15/month depending on usage
|
||||
- Free tier includes some allowance
|
||||
|
||||
See [Fly.io pricing](https://fly.io/docs/about/pricing/) for details.
|
||||
498
docker-compose/ez-assistant/docs/platforms/gcp.md
Normal file
498
docker-compose/ez-assistant/docs/platforms/gcp.md
Normal file
@@ -0,0 +1,498 @@
|
||||
---
|
||||
summary: "Run Moltbot Gateway 24/7 on a GCP Compute Engine VM (Docker) with durable state"
|
||||
read_when:
|
||||
- You want Moltbot running 24/7 on GCP
|
||||
- You want a production-grade, always-on Gateway on your own VM
|
||||
- You want full control over persistence, binaries, and restart behavior
|
||||
---
|
||||
|
||||
# Moltbot on GCP Compute Engine (Docker, Production VPS Guide)
|
||||
|
||||
## Goal
|
||||
|
||||
Run a persistent Moltbot Gateway on a GCP Compute Engine VM using Docker, with durable state, baked-in binaries, and safe restart behavior.
|
||||
|
||||
If you want "Moltbot 24/7 for ~$5-12/mo", this is a reliable setup on Google Cloud.
|
||||
Pricing varies by machine type and region; pick the smallest VM that fits your workload and scale up if you hit OOMs.
|
||||
|
||||
## What are we doing (simple terms)?
|
||||
|
||||
- Create a GCP project and enable billing
|
||||
- Create a Compute Engine VM
|
||||
- Install Docker (isolated app runtime)
|
||||
- Start the Moltbot Gateway in Docker
|
||||
- Persist `~/.clawdbot` + `~/clawd` on the host (survives restarts/rebuilds)
|
||||
- Access the Control UI from your laptop via an SSH tunnel
|
||||
|
||||
The Gateway can be accessed via:
|
||||
- SSH port forwarding from your laptop
|
||||
- Direct port exposure if you manage firewalling and tokens yourself
|
||||
|
||||
This guide uses Debian on GCP Compute Engine.
|
||||
Ubuntu also works; map packages accordingly.
|
||||
For the generic Docker flow, see [Docker](/install/docker).
|
||||
|
||||
---
|
||||
|
||||
## Quick path (experienced operators)
|
||||
|
||||
1) Create GCP project + enable Compute Engine API
|
||||
2) Create Compute Engine VM (e2-small, Debian 12, 20GB)
|
||||
3) SSH into the VM
|
||||
4) Install Docker
|
||||
5) Clone Moltbot repository
|
||||
6) Create persistent host directories
|
||||
7) Configure `.env` and `docker-compose.yml`
|
||||
8) Bake required binaries, build, and launch
|
||||
|
||||
---
|
||||
|
||||
## What you need
|
||||
|
||||
- GCP account (free tier eligible for e2-micro)
|
||||
- gcloud CLI installed (or use Cloud Console)
|
||||
- SSH access from your laptop
|
||||
- Basic comfort with SSH + copy/paste
|
||||
- ~20-30 minutes
|
||||
- Docker and Docker Compose
|
||||
- Model auth credentials
|
||||
- Optional provider credentials
|
||||
- WhatsApp QR
|
||||
- Telegram bot token
|
||||
- Gmail OAuth
|
||||
|
||||
---
|
||||
|
||||
## 1) Install gcloud CLI (or use Console)
|
||||
|
||||
**Option A: gcloud CLI** (recommended for automation)
|
||||
|
||||
Install from https://cloud.google.com/sdk/docs/install
|
||||
|
||||
Initialize and authenticate:
|
||||
|
||||
```bash
|
||||
gcloud init
|
||||
gcloud auth login
|
||||
```
|
||||
|
||||
**Option B: Cloud Console**
|
||||
|
||||
All steps can be done via the web UI at https://console.cloud.google.com
|
||||
|
||||
---
|
||||
|
||||
## 2) Create a GCP project
|
||||
|
||||
**CLI:**
|
||||
|
||||
```bash
|
||||
gcloud projects create my-moltbot-project --name="Moltbot Gateway"
|
||||
gcloud config set project my-moltbot-project
|
||||
```
|
||||
|
||||
Enable billing at https://console.cloud.google.com/billing (required for Compute Engine).
|
||||
|
||||
Enable the Compute Engine API:
|
||||
|
||||
```bash
|
||||
gcloud services enable compute.googleapis.com
|
||||
```
|
||||
|
||||
**Console:**
|
||||
|
||||
1. Go to IAM & Admin > Create Project
|
||||
2. Name it and create
|
||||
3. Enable billing for the project
|
||||
4. Navigate to APIs & Services > Enable APIs > search "Compute Engine API" > Enable
|
||||
|
||||
---
|
||||
|
||||
## 3) Create the VM
|
||||
|
||||
**Machine types:**
|
||||
|
||||
| Type | Specs | Cost | Notes |
|
||||
|------|-------|------|-------|
|
||||
| e2-small | 2 vCPU, 2GB RAM | ~$12/mo | Recommended |
|
||||
| e2-micro | 2 vCPU (shared), 1GB RAM | Free tier eligible | May OOM under load |
|
||||
|
||||
**CLI:**
|
||||
|
||||
```bash
|
||||
gcloud compute instances create moltbot-gateway \
|
||||
--zone=us-central1-a \
|
||||
--machine-type=e2-small \
|
||||
--boot-disk-size=20GB \
|
||||
--image-family=debian-12 \
|
||||
--image-project=debian-cloud
|
||||
```
|
||||
|
||||
**Console:**
|
||||
|
||||
1. Go to Compute Engine > VM instances > Create instance
|
||||
2. Name: `moltbot-gateway`
|
||||
3. Region: `us-central1`, Zone: `us-central1-a`
|
||||
4. Machine type: `e2-small`
|
||||
5. Boot disk: Debian 12, 20GB
|
||||
6. Create
|
||||
|
||||
---
|
||||
|
||||
## 4) SSH into the VM
|
||||
|
||||
**CLI:**
|
||||
|
||||
```bash
|
||||
gcloud compute ssh moltbot-gateway --zone=us-central1-a
|
||||
```
|
||||
|
||||
**Console:**
|
||||
|
||||
Click the "SSH" button next to your VM in the Compute Engine dashboard.
|
||||
|
||||
Note: SSH key propagation can take 1-2 minutes after VM creation. If connection is refused, wait and retry.
|
||||
|
||||
---
|
||||
|
||||
## 5) Install Docker (on the VM)
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y git curl ca-certificates
|
||||
curl -fsSL https://get.docker.com | sudo sh
|
||||
sudo usermod -aG docker $USER
|
||||
```
|
||||
|
||||
Log out and back in for the group change to take effect:
|
||||
|
||||
```bash
|
||||
exit
|
||||
```
|
||||
|
||||
Then SSH back in:
|
||||
|
||||
```bash
|
||||
gcloud compute ssh moltbot-gateway --zone=us-central1-a
|
||||
```
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
docker --version
|
||||
docker compose version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6) Clone the Moltbot repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/moltbot/moltbot.git
|
||||
cd moltbot
|
||||
```
|
||||
|
||||
This guide assumes you will build a custom image to guarantee binary persistence.
|
||||
|
||||
---
|
||||
|
||||
## 7) Create persistent host directories
|
||||
|
||||
Docker containers are ephemeral.
|
||||
All long-lived state must live on the host.
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.clawdbot
|
||||
mkdir -p ~/clawd
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8) Configure environment variables
|
||||
|
||||
Create `.env` in the repository root.
|
||||
|
||||
```bash
|
||||
CLAWDBOT_IMAGE=moltbot:latest
|
||||
CLAWDBOT_GATEWAY_TOKEN=change-me-now
|
||||
CLAWDBOT_GATEWAY_BIND=lan
|
||||
CLAWDBOT_GATEWAY_PORT=18789
|
||||
|
||||
CLAWDBOT_CONFIG_DIR=/home/$USER/.clawdbot
|
||||
CLAWDBOT_WORKSPACE_DIR=/home/$USER/clawd
|
||||
|
||||
GOG_KEYRING_PASSWORD=change-me-now
|
||||
XDG_CONFIG_HOME=/home/node/.clawdbot
|
||||
```
|
||||
|
||||
Generate strong secrets:
|
||||
|
||||
```bash
|
||||
openssl rand -hex 32
|
||||
```
|
||||
|
||||
**Do not commit this file.**
|
||||
|
||||
---
|
||||
|
||||
## 9) Docker Compose configuration
|
||||
|
||||
Create or update `docker-compose.yml`.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
moltbot-gateway:
|
||||
image: ${CLAWDBOT_IMAGE}
|
||||
build: .
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- HOME=/home/node
|
||||
- NODE_ENV=production
|
||||
- TERM=xterm-256color
|
||||
- CLAWDBOT_GATEWAY_BIND=${CLAWDBOT_GATEWAY_BIND}
|
||||
- CLAWDBOT_GATEWAY_PORT=${CLAWDBOT_GATEWAY_PORT}
|
||||
- CLAWDBOT_GATEWAY_TOKEN=${CLAWDBOT_GATEWAY_TOKEN}
|
||||
- GOG_KEYRING_PASSWORD=${GOG_KEYRING_PASSWORD}
|
||||
- XDG_CONFIG_HOME=${XDG_CONFIG_HOME}
|
||||
- PATH=/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
volumes:
|
||||
- ${CLAWDBOT_CONFIG_DIR}:/home/node/.clawdbot
|
||||
- ${CLAWDBOT_WORKSPACE_DIR}:/home/node/clawd
|
||||
ports:
|
||||
# Recommended: keep the Gateway loopback-only on the VM; access via SSH tunnel.
|
||||
# To expose it publicly, remove the `127.0.0.1:` prefix and firewall accordingly.
|
||||
- "127.0.0.1:${CLAWDBOT_GATEWAY_PORT}:18789"
|
||||
|
||||
# Optional: only if you run iOS/Android nodes against this VM and need Canvas host.
|
||||
# If you expose this publicly, read /gateway/security and firewall accordingly.
|
||||
# - "18793:18793"
|
||||
command:
|
||||
[
|
||||
"node",
|
||||
"dist/index.js",
|
||||
"gateway",
|
||||
"--bind",
|
||||
"${CLAWDBOT_GATEWAY_BIND}",
|
||||
"--port",
|
||||
"${CLAWDBOT_GATEWAY_PORT}"
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10) Bake required binaries into the image (critical)
|
||||
|
||||
Installing binaries inside a running container is a trap.
|
||||
Anything installed at runtime will be lost on restart.
|
||||
|
||||
All external binaries required by skills must be installed at image build time.
|
||||
|
||||
The examples below show three common binaries only:
|
||||
- `gog` for Gmail access
|
||||
- `goplaces` for Google Places
|
||||
- `wacli` for WhatsApp
|
||||
|
||||
These are examples, not a complete list.
|
||||
You may install as many binaries as needed using the same pattern.
|
||||
|
||||
If you add new skills later that depend on additional binaries, you must:
|
||||
1. Update the Dockerfile
|
||||
2. Rebuild the image
|
||||
3. Restart the containers
|
||||
|
||||
**Example Dockerfile**
|
||||
|
||||
```dockerfile
|
||||
FROM node:22-bookworm
|
||||
|
||||
RUN apt-get update && apt-get install -y socat && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Example binary 1: Gmail CLI
|
||||
RUN curl -L https://github.com/steipete/gog/releases/latest/download/gog_Linux_x86_64.tar.gz \
|
||||
| tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/gog
|
||||
|
||||
# Example binary 2: Google Places CLI
|
||||
RUN curl -L https://github.com/steipete/goplaces/releases/latest/download/goplaces_Linux_x86_64.tar.gz \
|
||||
| tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/goplaces
|
||||
|
||||
# Example binary 3: WhatsApp CLI
|
||||
RUN curl -L https://github.com/steipete/wacli/releases/latest/download/wacli_Linux_x86_64.tar.gz \
|
||||
| tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/wacli
|
||||
|
||||
# Add more binaries below using the same pattern
|
||||
|
||||
WORKDIR /app
|
||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
|
||||
COPY ui/package.json ./ui/package.json
|
||||
COPY scripts ./scripts
|
||||
|
||||
RUN corepack enable
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
RUN pnpm build
|
||||
RUN pnpm ui:install
|
||||
RUN pnpm ui:build
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
CMD ["node","dist/index.js"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11) Build and launch
|
||||
|
||||
```bash
|
||||
docker compose build
|
||||
docker compose up -d moltbot-gateway
|
||||
```
|
||||
|
||||
Verify binaries:
|
||||
|
||||
```bash
|
||||
docker compose exec moltbot-gateway which gog
|
||||
docker compose exec moltbot-gateway which goplaces
|
||||
docker compose exec moltbot-gateway which wacli
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```
|
||||
/usr/local/bin/gog
|
||||
/usr/local/bin/goplaces
|
||||
/usr/local/bin/wacli
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12) Verify Gateway
|
||||
|
||||
```bash
|
||||
docker compose logs -f moltbot-gateway
|
||||
```
|
||||
|
||||
Success:
|
||||
|
||||
```
|
||||
[gateway] listening on ws://0.0.0.0:18789
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13) Access from your laptop
|
||||
|
||||
Create an SSH tunnel to forward the Gateway port:
|
||||
|
||||
```bash
|
||||
gcloud compute ssh moltbot-gateway --zone=us-central1-a -- -L 18789:127.0.0.1:18789
|
||||
```
|
||||
|
||||
Open in your browser:
|
||||
|
||||
`http://127.0.0.1:18789/`
|
||||
|
||||
Paste your gateway token.
|
||||
|
||||
---
|
||||
|
||||
## What persists where (source of truth)
|
||||
|
||||
Moltbot runs in Docker, but Docker is not the source of truth.
|
||||
All long-lived state must survive restarts, rebuilds, and reboots.
|
||||
|
||||
| Component | Location | Persistence mechanism | Notes |
|
||||
|---|---|---|---|
|
||||
| Gateway config | `/home/node/.clawdbot/` | Host volume mount | Includes `moltbot.json`, tokens |
|
||||
| Model auth profiles | `/home/node/.clawdbot/` | Host volume mount | OAuth tokens, API keys |
|
||||
| Skill configs | `/home/node/.clawdbot/skills/` | Host volume mount | Skill-level state |
|
||||
| Agent workspace | `/home/node/clawd/` | Host volume mount | Code and agent artifacts |
|
||||
| WhatsApp session | `/home/node/.clawdbot/` | Host volume mount | Preserves QR login |
|
||||
| Gmail keyring | `/home/node/.clawdbot/` | Host volume + password | Requires `GOG_KEYRING_PASSWORD` |
|
||||
| External binaries | `/usr/local/bin/` | Docker image | Must be baked at build time |
|
||||
| Node runtime | Container filesystem | Docker image | Rebuilt every image build |
|
||||
| OS packages | Container filesystem | Docker image | Do not install at runtime |
|
||||
| Docker container | Ephemeral | Restartable | Safe to destroy |
|
||||
|
||||
---
|
||||
|
||||
## Updates
|
||||
|
||||
To update Moltbot on the VM:
|
||||
|
||||
```bash
|
||||
cd ~/moltbot
|
||||
git pull
|
||||
docker compose build
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**SSH connection refused**
|
||||
|
||||
SSH key propagation can take 1-2 minutes after VM creation. Wait and retry.
|
||||
|
||||
**OS Login issues**
|
||||
|
||||
Check your OS Login profile:
|
||||
|
||||
```bash
|
||||
gcloud compute os-login describe-profile
|
||||
```
|
||||
|
||||
Ensure your account has the required IAM permissions (Compute OS Login or Compute OS Admin Login).
|
||||
|
||||
**Out of memory (OOM)**
|
||||
|
||||
If using e2-micro and hitting OOM, upgrade to e2-small or e2-medium:
|
||||
|
||||
```bash
|
||||
# Stop the VM first
|
||||
gcloud compute instances stop moltbot-gateway --zone=us-central1-a
|
||||
|
||||
# Change machine type
|
||||
gcloud compute instances set-machine-type moltbot-gateway \
|
||||
--zone=us-central1-a \
|
||||
--machine-type=e2-small
|
||||
|
||||
# Start the VM
|
||||
gcloud compute instances start moltbot-gateway --zone=us-central1-a
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Service accounts (security best practice)
|
||||
|
||||
For personal use, your default user account works fine.
|
||||
|
||||
For automation or CI/CD pipelines, create a dedicated service account with minimal permissions:
|
||||
|
||||
1. Create a service account:
|
||||
```bash
|
||||
gcloud iam service-accounts create moltbot-deploy \
|
||||
--display-name="Moltbot Deployment"
|
||||
```
|
||||
|
||||
2. Grant Compute Instance Admin role (or narrower custom role):
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding my-moltbot-project \
|
||||
--member="serviceAccount:moltbot-deploy@my-moltbot-project.iam.gserviceaccount.com" \
|
||||
--role="roles/compute.instanceAdmin.v1"
|
||||
```
|
||||
|
||||
Avoid using the Owner role for automation. Use the principle of least privilege.
|
||||
|
||||
See https://cloud.google.com/iam/docs/understanding-roles for IAM role details.
|
||||
|
||||
---
|
||||
|
||||
## Next steps
|
||||
|
||||
- Set up messaging channels: [Channels](/channels)
|
||||
- Pair local devices as nodes: [Nodes](/nodes)
|
||||
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
|
||||
325
docker-compose/ez-assistant/docs/platforms/hetzner.md
Normal file
325
docker-compose/ez-assistant/docs/platforms/hetzner.md
Normal file
@@ -0,0 +1,325 @@
|
||||
---
|
||||
summary: "Run Moltbot Gateway 24/7 on a cheap Hetzner VPS (Docker) with durable state and baked-in binaries"
|
||||
read_when:
|
||||
- You want Moltbot running 24/7 on a cloud VPS (not your laptop)
|
||||
- You want a production-grade, always-on Gateway on your own VPS
|
||||
- You want full control over persistence, binaries, and restart behavior
|
||||
- You are running Moltbot in Docker on Hetzner or a similar provider
|
||||
---
|
||||
|
||||
# Moltbot on Hetzner (Docker, Production VPS Guide)
|
||||
|
||||
## Goal
|
||||
Run a persistent Moltbot Gateway on a Hetzner VPS using Docker, with durable state, baked-in binaries, and safe restart behavior.
|
||||
|
||||
If you want “Moltbot 24/7 for ~$5”, this is the simplest reliable setup.
|
||||
Hetzner pricing changes; pick the smallest Debian/Ubuntu VPS and scale up if you hit OOMs.
|
||||
|
||||
## What are we doing (simple terms)?
|
||||
|
||||
- Rent a small Linux server (Hetzner VPS)
|
||||
- Install Docker (isolated app runtime)
|
||||
- Start the Moltbot Gateway in Docker
|
||||
- Persist `~/.clawdbot` + `~/clawd` on the host (survives restarts/rebuilds)
|
||||
- Access the Control UI from your laptop via an SSH tunnel
|
||||
|
||||
The Gateway can be accessed via:
|
||||
- SSH port forwarding from your laptop
|
||||
- Direct port exposure if you manage firewalling and tokens yourself
|
||||
|
||||
This guide assumes Ubuntu or Debian on Hetzner.
|
||||
If you are on another Linux VPS, map packages accordingly.
|
||||
For the generic Docker flow, see [Docker](/install/docker).
|
||||
|
||||
---
|
||||
|
||||
## Quick path (experienced operators)
|
||||
|
||||
1) Provision Hetzner VPS
|
||||
2) Install Docker
|
||||
3) Clone Moltbot repository
|
||||
4) Create persistent host directories
|
||||
5) Configure `.env` and `docker-compose.yml`
|
||||
6) Bake required binaries into the image
|
||||
7) `docker compose up -d`
|
||||
8) Verify persistence and Gateway access
|
||||
|
||||
---
|
||||
|
||||
## What you need
|
||||
|
||||
- Hetzner VPS with root access
|
||||
- SSH access from your laptop
|
||||
- Basic comfort with SSH + copy/paste
|
||||
- ~20 minutes
|
||||
- Docker and Docker Compose
|
||||
- Model auth credentials
|
||||
- Optional provider credentials
|
||||
- WhatsApp QR
|
||||
- Telegram bot token
|
||||
- Gmail OAuth
|
||||
|
||||
---
|
||||
|
||||
## 1) Provision the VPS
|
||||
|
||||
Create an Ubuntu or Debian VPS in Hetzner.
|
||||
|
||||
Connect as root:
|
||||
|
||||
```bash
|
||||
ssh root@YOUR_VPS_IP
|
||||
```
|
||||
|
||||
This guide assumes the VPS is stateful.
|
||||
Do not treat it as disposable infrastructure.
|
||||
|
||||
---
|
||||
|
||||
## 2) Install Docker (on the VPS)
|
||||
|
||||
```bash
|
||||
apt-get update
|
||||
apt-get install -y git curl ca-certificates
|
||||
curl -fsSL https://get.docker.com | sh
|
||||
```
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
docker --version
|
||||
docker compose version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3) Clone the Moltbot repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/moltbot/moltbot.git
|
||||
cd moltbot
|
||||
```
|
||||
|
||||
This guide assumes you will build a custom image to guarantee binary persistence.
|
||||
|
||||
---
|
||||
|
||||
## 4) Create persistent host directories
|
||||
|
||||
Docker containers are ephemeral.
|
||||
All long-lived state must live on the host.
|
||||
|
||||
```bash
|
||||
mkdir -p /root/.clawdbot
|
||||
mkdir -p /root/clawd
|
||||
|
||||
# Set ownership to the container user (uid 1000):
|
||||
chown -R 1000:1000 /root/.clawdbot
|
||||
chown -R 1000:1000 /root/clawd
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5) Configure environment variables
|
||||
|
||||
Create `.env` in the repository root.
|
||||
|
||||
```bash
|
||||
CLAWDBOT_IMAGE=moltbot:latest
|
||||
CLAWDBOT_GATEWAY_TOKEN=change-me-now
|
||||
CLAWDBOT_GATEWAY_BIND=lan
|
||||
CLAWDBOT_GATEWAY_PORT=18789
|
||||
|
||||
CLAWDBOT_CONFIG_DIR=/root/.clawdbot
|
||||
CLAWDBOT_WORKSPACE_DIR=/root/clawd
|
||||
|
||||
GOG_KEYRING_PASSWORD=change-me-now
|
||||
XDG_CONFIG_HOME=/home/node/.clawdbot
|
||||
```
|
||||
|
||||
Generate strong secrets:
|
||||
|
||||
```bash
|
||||
openssl rand -hex 32
|
||||
```
|
||||
|
||||
**Do not commit this file.**
|
||||
|
||||
---
|
||||
|
||||
## 6) Docker Compose configuration
|
||||
|
||||
Create or update `docker-compose.yml`.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
moltbot-gateway:
|
||||
image: ${CLAWDBOT_IMAGE}
|
||||
build: .
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- HOME=/home/node
|
||||
- NODE_ENV=production
|
||||
- TERM=xterm-256color
|
||||
- CLAWDBOT_GATEWAY_BIND=${CLAWDBOT_GATEWAY_BIND}
|
||||
- CLAWDBOT_GATEWAY_PORT=${CLAWDBOT_GATEWAY_PORT}
|
||||
- CLAWDBOT_GATEWAY_TOKEN=${CLAWDBOT_GATEWAY_TOKEN}
|
||||
- GOG_KEYRING_PASSWORD=${GOG_KEYRING_PASSWORD}
|
||||
- XDG_CONFIG_HOME=${XDG_CONFIG_HOME}
|
||||
- PATH=/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
volumes:
|
||||
- ${CLAWDBOT_CONFIG_DIR}:/home/node/.clawdbot
|
||||
- ${CLAWDBOT_WORKSPACE_DIR}:/home/node/clawd
|
||||
ports:
|
||||
# Recommended: keep the Gateway loopback-only on the VPS; access via SSH tunnel.
|
||||
# To expose it publicly, remove the `127.0.0.1:` prefix and firewall accordingly.
|
||||
- "127.0.0.1:${CLAWDBOT_GATEWAY_PORT}:18789"
|
||||
|
||||
# Optional: only if you run iOS/Android nodes against this VPS and need Canvas host.
|
||||
# If you expose this publicly, read /gateway/security and firewall accordingly.
|
||||
# - "18793:18793"
|
||||
command:
|
||||
[
|
||||
"node",
|
||||
"dist/index.js",
|
||||
"gateway",
|
||||
"--bind",
|
||||
"${CLAWDBOT_GATEWAY_BIND}",
|
||||
"--port",
|
||||
"${CLAWDBOT_GATEWAY_PORT}"
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7) Bake required binaries into the image (critical)
|
||||
|
||||
Installing binaries inside a running container is a trap.
|
||||
Anything installed at runtime will be lost on restart.
|
||||
|
||||
All external binaries required by skills must be installed at image build time.
|
||||
|
||||
The examples below show three common binaries only:
|
||||
- `gog` for Gmail access
|
||||
- `goplaces` for Google Places
|
||||
- `wacli` for WhatsApp
|
||||
|
||||
These are examples, not a complete list.
|
||||
You may install as many binaries as needed using the same pattern.
|
||||
|
||||
If you add new skills later that depend on additional binaries, you must:
|
||||
1. Update the Dockerfile
|
||||
2. Rebuild the image
|
||||
3. Restart the containers
|
||||
|
||||
**Example Dockerfile**
|
||||
|
||||
```dockerfile
|
||||
FROM node:22-bookworm
|
||||
|
||||
RUN apt-get update && apt-get install -y socat && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Example binary 1: Gmail CLI
|
||||
RUN curl -L https://github.com/steipete/gog/releases/latest/download/gog_Linux_x86_64.tar.gz \
|
||||
| tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/gog
|
||||
|
||||
# Example binary 2: Google Places CLI
|
||||
RUN curl -L https://github.com/steipete/goplaces/releases/latest/download/goplaces_Linux_x86_64.tar.gz \
|
||||
| tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/goplaces
|
||||
|
||||
# Example binary 3: WhatsApp CLI
|
||||
RUN curl -L https://github.com/steipete/wacli/releases/latest/download/wacli_Linux_x86_64.tar.gz \
|
||||
| tar -xz -C /usr/local/bin && chmod +x /usr/local/bin/wacli
|
||||
|
||||
# Add more binaries below using the same pattern
|
||||
|
||||
WORKDIR /app
|
||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
|
||||
COPY ui/package.json ./ui/package.json
|
||||
COPY scripts ./scripts
|
||||
|
||||
RUN corepack enable
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
RUN pnpm build
|
||||
RUN pnpm ui:install
|
||||
RUN pnpm ui:build
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
CMD ["node","dist/index.js"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8) Build and launch
|
||||
|
||||
```bash
|
||||
docker compose build
|
||||
docker compose up -d moltbot-gateway
|
||||
```
|
||||
|
||||
Verify binaries:
|
||||
|
||||
```bash
|
||||
docker compose exec moltbot-gateway which gog
|
||||
docker compose exec moltbot-gateway which goplaces
|
||||
docker compose exec moltbot-gateway which wacli
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```
|
||||
/usr/local/bin/gog
|
||||
/usr/local/bin/goplaces
|
||||
/usr/local/bin/wacli
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9) Verify Gateway
|
||||
|
||||
```bash
|
||||
docker compose logs -f moltbot-gateway
|
||||
```
|
||||
|
||||
Success:
|
||||
|
||||
```
|
||||
[gateway] listening on ws://0.0.0.0:18789
|
||||
```
|
||||
|
||||
From your laptop:
|
||||
|
||||
```bash
|
||||
ssh -N -L 18789:127.0.0.1:18789 root@YOUR_VPS_IP
|
||||
```
|
||||
|
||||
Open:
|
||||
|
||||
`http://127.0.0.1:18789/`
|
||||
|
||||
Paste your gateway token.
|
||||
|
||||
---
|
||||
|
||||
## What persists where (source of truth)
|
||||
|
||||
Moltbot runs in Docker, but Docker is not the source of truth.
|
||||
All long-lived state must survive restarts, rebuilds, and reboots.
|
||||
|
||||
| Component | Location | Persistence mechanism | Notes |
|
||||
|---|---|---|---|
|
||||
| Gateway config | `/home/node/.clawdbot/` | Host volume mount | Includes `moltbot.json`, tokens |
|
||||
| Model auth profiles | `/home/node/.clawdbot/` | Host volume mount | OAuth tokens, API keys |
|
||||
| Skill configs | `/home/node/.clawdbot/skills/` | Host volume mount | Skill-level state |
|
||||
| Agent workspace | `/home/node/clawd/` | Host volume mount | Code and agent artifacts |
|
||||
| WhatsApp session | `/home/node/.clawdbot/` | Host volume mount | Preserves QR login |
|
||||
| Gmail keyring | `/home/node/.clawdbot/` | Host volume + password | Requires `GOG_KEYRING_PASSWORD` |
|
||||
| External binaries | `/usr/local/bin/` | Docker image | Must be baked at build time |
|
||||
| Node runtime | Container filesystem | Docker image | Rebuilt every image build |
|
||||
| OS packages | Container filesystem | Docker image | Do not install at runtime |
|
||||
| Docker container | Ephemeral | Restartable | Safe to destroy |
|
||||
50
docker-compose/ez-assistant/docs/platforms/index.md
Normal file
50
docker-compose/ez-assistant/docs/platforms/index.md
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
summary: "Platform support overview (Gateway + companion apps)"
|
||||
read_when:
|
||||
- Looking for OS support or install paths
|
||||
- Deciding where to run the Gateway
|
||||
---
|
||||
# Platforms
|
||||
|
||||
Moltbot core is written in TypeScript. **Node is the recommended runtime**.
|
||||
Bun is not recommended for the Gateway (WhatsApp/Telegram bugs).
|
||||
|
||||
Companion apps exist for macOS (menu bar app) and mobile nodes (iOS/Android). Windows and
|
||||
Linux companion apps are planned, but the Gateway is fully supported today.
|
||||
Native companion apps for Windows are also planned; the Gateway is recommended via WSL2.
|
||||
|
||||
## Choose your OS
|
||||
|
||||
- macOS: [macOS](/platforms/macos)
|
||||
- iOS: [iOS](/platforms/ios)
|
||||
- Android: [Android](/platforms/android)
|
||||
- Windows: [Windows](/platforms/windows)
|
||||
- Linux: [Linux](/platforms/linux)
|
||||
|
||||
## VPS & hosting
|
||||
|
||||
- VPS hub: [VPS hosting](/vps)
|
||||
- Fly.io: [Fly.io](/platforms/fly)
|
||||
- Hetzner (Docker): [Hetzner](/platforms/hetzner)
|
||||
- GCP (Compute Engine): [GCP](/platforms/gcp)
|
||||
- exe.dev (VM + HTTPS proxy): [exe.dev](/platforms/exe-dev)
|
||||
|
||||
## Common links
|
||||
|
||||
- Install guide: [Getting Started](/start/getting-started)
|
||||
- Gateway runbook: [Gateway](/gateway)
|
||||
- Gateway configuration: [Configuration](/gateway/configuration)
|
||||
- Service status: `moltbot gateway status`
|
||||
|
||||
## Gateway service install (CLI)
|
||||
|
||||
Use one of these (all supported):
|
||||
|
||||
- Wizard (recommended): `moltbot onboard --install-daemon`
|
||||
- Direct: `moltbot gateway install`
|
||||
- Configure flow: `moltbot configure` → select **Gateway service**
|
||||
- Repair/migrate: `moltbot doctor` (offers to install or fix the service)
|
||||
|
||||
The service target depends on OS:
|
||||
- macOS: LaunchAgent (`bot.molt.gateway` or `bot.molt.<profile>`; legacy `com.clawdbot.*`)
|
||||
- Linux/WSL2: systemd user service (`moltbot-gateway[-<profile>].service`)
|
||||
104
docker-compose/ez-assistant/docs/platforms/ios.md
Normal file
104
docker-compose/ez-assistant/docs/platforms/ios.md
Normal file
@@ -0,0 +1,104 @@
|
||||
---
|
||||
summary: "iOS node app: connect to the Gateway, pairing, canvas, and troubleshooting"
|
||||
read_when:
|
||||
- Pairing or reconnecting the iOS node
|
||||
- Running the iOS app from source
|
||||
- Debugging gateway discovery or canvas commands
|
||||
---
|
||||
# iOS App (Node)
|
||||
|
||||
Availability: internal preview. The iOS app is not publicly distributed yet.
|
||||
|
||||
## What it does
|
||||
|
||||
- Connects to a Gateway over WebSocket (LAN or tailnet).
|
||||
- Exposes node capabilities: Canvas, Screen snapshot, Camera capture, Location, Talk mode, Voice wake.
|
||||
- Receives `node.invoke` commands and reports node status events.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Gateway running on another device (macOS, Linux, or Windows via WSL2).
|
||||
- Network path:
|
||||
- Same LAN via Bonjour, **or**
|
||||
- Tailnet via unicast DNS-SD (`moltbot.internal.`), **or**
|
||||
- Manual host/port (fallback).
|
||||
|
||||
## Quick start (pair + connect)
|
||||
|
||||
1) Start the Gateway:
|
||||
|
||||
```bash
|
||||
moltbot gateway --port 18789
|
||||
```
|
||||
|
||||
2) In the iOS app, open Settings and pick a discovered gateway (or enable Manual Host and enter host/port).
|
||||
|
||||
3) Approve the pairing request on the gateway host:
|
||||
|
||||
```bash
|
||||
moltbot nodes pending
|
||||
moltbot nodes approve <requestId>
|
||||
```
|
||||
|
||||
4) Verify connection:
|
||||
|
||||
```bash
|
||||
moltbot nodes status
|
||||
moltbot gateway call node.list --params "{}"
|
||||
```
|
||||
|
||||
## Discovery paths
|
||||
|
||||
### Bonjour (LAN)
|
||||
|
||||
The Gateway advertises `_moltbot._tcp` on `local.`. The iOS app lists these automatically.
|
||||
|
||||
### Tailnet (cross-network)
|
||||
|
||||
If mDNS is blocked, use a unicast DNS-SD zone (recommended domain: `moltbot.internal.`) and Tailscale split DNS.
|
||||
See [Bonjour](/gateway/bonjour) for the CoreDNS example.
|
||||
|
||||
### Manual host/port
|
||||
|
||||
In Settings, enable **Manual Host** and enter the gateway host + port (default `18789`).
|
||||
|
||||
## Canvas + A2UI
|
||||
|
||||
The iOS node renders a WKWebView canvas. Use `node.invoke` to drive it:
|
||||
|
||||
```bash
|
||||
moltbot nodes invoke --node "iOS Node" --command canvas.navigate --params '{"url":"http://<gateway-host>:18793/__moltbot__/canvas/"}'
|
||||
```
|
||||
|
||||
Notes:
|
||||
- The Gateway canvas host serves `/__moltbot__/canvas/` and `/__moltbot__/a2ui/`.
|
||||
- The iOS node auto-navigates to A2UI on connect when a canvas host URL is advertised.
|
||||
- Return to the built-in scaffold with `canvas.navigate` and `{"url":""}`.
|
||||
|
||||
### Canvas eval / snapshot
|
||||
|
||||
```bash
|
||||
moltbot nodes invoke --node "iOS Node" --command canvas.eval --params '{"javaScript":"(() => { const {ctx} = window.__moltbot; ctx.clearRect(0,0,innerWidth,innerHeight); ctx.lineWidth=6; ctx.strokeStyle=\"#ff2d55\"; ctx.beginPath(); ctx.moveTo(40,40); ctx.lineTo(innerWidth-40, innerHeight-40); ctx.stroke(); return \"ok\"; })()"}'
|
||||
```
|
||||
|
||||
```bash
|
||||
moltbot nodes invoke --node "iOS Node" --command canvas.snapshot --params '{"maxWidth":900,"format":"jpeg"}'
|
||||
```
|
||||
|
||||
## Voice wake + talk mode
|
||||
|
||||
- Voice wake and talk mode are available in Settings.
|
||||
- iOS may suspend background audio; treat voice features as best-effort when the app is not active.
|
||||
|
||||
## Common errors
|
||||
|
||||
- `NODE_BACKGROUND_UNAVAILABLE`: bring the iOS app to the foreground (canvas/camera/screen commands require it).
|
||||
- `A2UI_HOST_NOT_CONFIGURED`: the Gateway did not advertise a canvas host URL; check `canvasHost` in [Gateway configuration](/gateway/configuration).
|
||||
- Pairing prompt never appears: run `moltbot nodes pending` and approve manually.
|
||||
- Reconnect fails after reinstall: the Keychain pairing token was cleared; re-pair the node.
|
||||
|
||||
## Related docs
|
||||
|
||||
- [Pairing](/gateway/pairing)
|
||||
- [Discovery](/gateway/discovery)
|
||||
- [Bonjour](/gateway/bonjour)
|
||||
89
docker-compose/ez-assistant/docs/platforms/linux.md
Normal file
89
docker-compose/ez-assistant/docs/platforms/linux.md
Normal file
@@ -0,0 +1,89 @@
|
||||
---
|
||||
summary: "Linux support + companion app status"
|
||||
read_when:
|
||||
- Looking for Linux companion app status
|
||||
- Planning platform coverage or contributions
|
||||
---
|
||||
# Linux App
|
||||
|
||||
The Gateway is fully supported on Linux. **Node is the recommended runtime**.
|
||||
Bun is not recommended for the Gateway (WhatsApp/Telegram bugs).
|
||||
|
||||
Native Linux companion apps are planned. Contributions are welcome if you want to help build one.
|
||||
|
||||
## Beginner quick path (VPS)
|
||||
|
||||
1) Install Node 22+
|
||||
2) `npm i -g moltbot@latest`
|
||||
3) `moltbot onboard --install-daemon`
|
||||
4) From your laptop: `ssh -N -L 18789:127.0.0.1:18789 <user>@<host>`
|
||||
5) Open `http://127.0.0.1:18789/` and paste your token
|
||||
|
||||
Step-by-step VPS guide: [exe.dev](/platforms/exe-dev)
|
||||
|
||||
## Install
|
||||
- [Getting Started](/start/getting-started)
|
||||
- [Install & updates](/install/updating)
|
||||
- Optional flows: [Bun (experimental)](/install/bun), [Nix](/install/nix), [Docker](/install/docker)
|
||||
|
||||
## Gateway
|
||||
- [Gateway runbook](/gateway)
|
||||
- [Configuration](/gateway/configuration)
|
||||
|
||||
## Gateway service install (CLI)
|
||||
|
||||
Use one of these:
|
||||
|
||||
```
|
||||
moltbot onboard --install-daemon
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```
|
||||
moltbot gateway install
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```
|
||||
moltbot configure
|
||||
```
|
||||
|
||||
Select **Gateway service** when prompted.
|
||||
|
||||
Repair/migrate:
|
||||
|
||||
```
|
||||
moltbot doctor
|
||||
```
|
||||
|
||||
## System control (systemd user unit)
|
||||
Moltbot installs a systemd **user** service by default. Use a **system**
|
||||
service for shared or always-on servers. The full unit example and guidance
|
||||
live in the [Gateway runbook](/gateway).
|
||||
|
||||
Minimal setup:
|
||||
|
||||
Create `~/.config/systemd/user/moltbot-gateway[-<profile>].service`:
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=Moltbot Gateway (profile: <profile>, v<version>)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/moltbot gateway --port 18789
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
Enable it:
|
||||
|
||||
```
|
||||
systemctl --user enable --now moltbot-gateway[-<profile>].service
|
||||
```
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
summary: "Gateway runtime on macOS (external launchd service)"
|
||||
read_when:
|
||||
- Packaging Moltbot.app
|
||||
- Debugging the macOS gateway launchd service
|
||||
- Installing the gateway CLI for macOS
|
||||
---
|
||||
|
||||
# Gateway on macOS (external launchd)
|
||||
|
||||
Moltbot.app no longer bundles Node/Bun or the Gateway runtime. The macOS app
|
||||
expects an **external** `moltbot` CLI install, does not spawn the Gateway as a
|
||||
child process, and manages a per‑user launchd service to keep the Gateway
|
||||
running (or attaches to an existing local Gateway if one is already running).
|
||||
|
||||
## Install the CLI (required for local mode)
|
||||
|
||||
You need Node 22+ on the Mac, then install `moltbot` globally:
|
||||
|
||||
```bash
|
||||
npm install -g moltbot@<version>
|
||||
```
|
||||
|
||||
The macOS app’s **Install CLI** button runs the same flow via npm/pnpm (bun not recommended for Gateway runtime).
|
||||
|
||||
## Launchd (Gateway as LaunchAgent)
|
||||
|
||||
Label:
|
||||
- `bot.molt.gateway` (or `bot.molt.<profile>`; legacy `com.clawdbot.*` may remain)
|
||||
|
||||
Plist location (per‑user):
|
||||
- `~/Library/LaunchAgents/bot.molt.gateway.plist`
|
||||
(or `~/Library/LaunchAgents/bot.molt.<profile>.plist`)
|
||||
|
||||
Manager:
|
||||
- The macOS app owns LaunchAgent install/update in Local mode.
|
||||
- The CLI can also install it: `moltbot gateway install`.
|
||||
|
||||
Behavior:
|
||||
- “Moltbot Active” enables/disables the LaunchAgent.
|
||||
- App quit does **not** stop the gateway (launchd keeps it alive).
|
||||
- If a Gateway is already running on the configured port, the app attaches to
|
||||
it instead of starting a new one.
|
||||
|
||||
Logging:
|
||||
- launchd stdout/err: `/tmp/moltbot/moltbot-gateway.log`
|
||||
|
||||
## Version compatibility
|
||||
|
||||
The macOS app checks the gateway version against its own version. If they’re
|
||||
incompatible, update the global CLI to match the app version.
|
||||
|
||||
## Smoke check
|
||||
|
||||
```bash
|
||||
moltbot --version
|
||||
|
||||
CLAWDBOT_SKIP_CHANNELS=1 \
|
||||
CLAWDBOT_SKIP_CANVAS_HOST=1 \
|
||||
moltbot gateway --port 18999 --bind loopback
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
```bash
|
||||
moltbot gateway call health --url ws://127.0.0.1:18999 --timeout 3000
|
||||
```
|
||||
121
docker-compose/ez-assistant/docs/platforms/mac/canvas.md
Normal file
121
docker-compose/ez-assistant/docs/platforms/mac/canvas.md
Normal file
@@ -0,0 +1,121 @@
|
||||
---
|
||||
summary: "Agent-controlled Canvas panel embedded via WKWebView + custom URL scheme"
|
||||
read_when:
|
||||
- Implementing the macOS Canvas panel
|
||||
- Adding agent controls for visual workspace
|
||||
- Debugging WKWebView canvas loads
|
||||
---
|
||||
# Canvas (macOS app)
|
||||
|
||||
The macOS app embeds an agent‑controlled **Canvas panel** using `WKWebView`. It
|
||||
is a lightweight visual workspace for HTML/CSS/JS, A2UI, and small interactive
|
||||
UI surfaces.
|
||||
|
||||
## Where Canvas lives
|
||||
|
||||
Canvas state is stored under Application Support:
|
||||
|
||||
- `~/Library/Application Support/Moltbot/canvas/<session>/...`
|
||||
|
||||
The Canvas panel serves those files via a **custom URL scheme**:
|
||||
|
||||
- `moltbot-canvas://<session>/<path>`
|
||||
|
||||
Examples:
|
||||
- `moltbot-canvas://main/` → `<canvasRoot>/main/index.html`
|
||||
- `moltbot-canvas://main/assets/app.css` → `<canvasRoot>/main/assets/app.css`
|
||||
- `moltbot-canvas://main/widgets/todo/` → `<canvasRoot>/main/widgets/todo/index.html`
|
||||
|
||||
If no `index.html` exists at the root, the app shows a **built‑in scaffold page**.
|
||||
|
||||
## Panel behavior
|
||||
|
||||
- Borderless, resizable panel anchored near the menu bar (or mouse cursor).
|
||||
- Remembers size/position per session.
|
||||
- Auto‑reloads when local canvas files change.
|
||||
- Only one Canvas panel is visible at a time (session is switched as needed).
|
||||
|
||||
Canvas can be disabled from Settings → **Allow Canvas**. When disabled, canvas
|
||||
node commands return `CANVAS_DISABLED`.
|
||||
|
||||
## Agent API surface
|
||||
|
||||
Canvas is exposed via the **Gateway WebSocket**, so the agent can:
|
||||
|
||||
- show/hide the panel
|
||||
- navigate to a path or URL
|
||||
- evaluate JavaScript
|
||||
- capture a snapshot image
|
||||
|
||||
CLI examples:
|
||||
|
||||
```bash
|
||||
moltbot nodes canvas present --node <id>
|
||||
moltbot nodes canvas navigate --node <id> --url "/"
|
||||
moltbot nodes canvas eval --node <id> --js "document.title"
|
||||
moltbot nodes canvas snapshot --node <id>
|
||||
```
|
||||
|
||||
Notes:
|
||||
- `canvas.navigate` accepts **local canvas paths**, `http(s)` URLs, and `file://` URLs.
|
||||
- If you pass `"/"`, the Canvas shows the local scaffold or `index.html`.
|
||||
|
||||
## A2UI in Canvas
|
||||
|
||||
A2UI is hosted by the Gateway canvas host and rendered inside the Canvas panel.
|
||||
When the Gateway advertises a Canvas host, the macOS app auto‑navigates to the
|
||||
A2UI host page on first open.
|
||||
|
||||
Default A2UI host URL:
|
||||
|
||||
```
|
||||
http://<gateway-host>:18793/__moltbot__/a2ui/
|
||||
```
|
||||
|
||||
### A2UI commands (v0.8)
|
||||
|
||||
Canvas currently accepts **A2UI v0.8** server→client messages:
|
||||
|
||||
- `beginRendering`
|
||||
- `surfaceUpdate`
|
||||
- `dataModelUpdate`
|
||||
- `deleteSurface`
|
||||
|
||||
`createSurface` (v0.9) is not supported.
|
||||
|
||||
CLI example:
|
||||
|
||||
```bash
|
||||
cat > /tmp/a2ui-v0.8.jsonl <<'EOFA2'
|
||||
{"surfaceUpdate":{"surfaceId":"main","components":[{"id":"root","component":{"Column":{"children":{"explicitList":["title","content"]}}}},{"id":"title","component":{"Text":{"text":{"literalString":"Canvas (A2UI v0.8)"},"usageHint":"h1"}}},{"id":"content","component":{"Text":{"text":{"literalString":"If you can read this, A2UI push works."},"usageHint":"body"}}}]}}
|
||||
{"beginRendering":{"surfaceId":"main","root":"root"}}
|
||||
EOFA2
|
||||
|
||||
moltbot nodes canvas a2ui push --jsonl /tmp/a2ui-v0.8.jsonl --node <id>
|
||||
```
|
||||
|
||||
Quick smoke:
|
||||
|
||||
```bash
|
||||
moltbot nodes canvas a2ui push --node <id> --text "Hello from A2UI"
|
||||
```
|
||||
|
||||
## Triggering agent runs from Canvas
|
||||
|
||||
Canvas can trigger new agent runs via deep links:
|
||||
|
||||
- `moltbot://agent?...`
|
||||
|
||||
Example (in JS):
|
||||
|
||||
```js
|
||||
window.location.href = "moltbot://agent?message=Review%20this%20design";
|
||||
```
|
||||
|
||||
The app prompts for confirmation unless a valid key is provided.
|
||||
|
||||
## Security notes
|
||||
|
||||
- Canvas scheme blocks directory traversal; files must live under the session root.
|
||||
- Local Canvas content uses a custom scheme (no loopback server required).
|
||||
- External `http(s)` URLs are allowed only when explicitly navigated.
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
summary: "Gateway lifecycle on macOS (launchd)"
|
||||
read_when:
|
||||
- Integrating the mac app with the gateway lifecycle
|
||||
---
|
||||
# Gateway lifecycle on macOS
|
||||
|
||||
The macOS app **manages the Gateway via launchd** by default and does not spawn
|
||||
the Gateway as a child process. It first tries to attach to an already‑running
|
||||
Gateway on the configured port; if none is reachable, it enables the launchd
|
||||
service via the external `moltbot` CLI (no embedded runtime). This gives you
|
||||
reliable auto‑start at login and restart on crashes.
|
||||
|
||||
Child‑process mode (Gateway spawned directly by the app) is **not in use** today.
|
||||
If you need tighter coupling to the UI, run the Gateway manually in a terminal.
|
||||
|
||||
## Default behavior (launchd)
|
||||
|
||||
- The app installs a per‑user LaunchAgent labeled `bot.molt.gateway`
|
||||
(or `bot.molt.<profile>` when using `--profile`/`CLAWDBOT_PROFILE`; legacy `com.clawdbot.*` is supported).
|
||||
- When Local mode is enabled, the app ensures the LaunchAgent is loaded and
|
||||
starts the Gateway if needed.
|
||||
- Logs are written to the launchd gateway log path (visible in Debug Settings).
|
||||
|
||||
Common commands:
|
||||
|
||||
```bash
|
||||
launchctl kickstart -k gui/$UID/bot.molt.gateway
|
||||
launchctl bootout gui/$UID/bot.molt.gateway
|
||||
```
|
||||
|
||||
Replace the label with `bot.molt.<profile>` when running a named profile.
|
||||
|
||||
## Unsigned dev builds
|
||||
|
||||
`scripts/restart-mac.sh --no-sign` is for fast local builds when you don’t have
|
||||
signing keys. To prevent launchd from pointing at an unsigned relay binary, it:
|
||||
|
||||
- Writes `~/.clawdbot/disable-launchagent`.
|
||||
|
||||
Signed runs of `scripts/restart-mac.sh` clear this override if the marker is
|
||||
present. To reset manually:
|
||||
|
||||
```bash
|
||||
rm ~/.clawdbot/disable-launchagent
|
||||
```
|
||||
|
||||
## Attach-only mode
|
||||
|
||||
To force the macOS app to **never install or manage launchd**, launch it with
|
||||
`--attach-only` (or `--no-launchd`). This sets `~/.clawdbot/disable-launchagent`,
|
||||
so the app only attaches to an already running Gateway. You can toggle the same
|
||||
behavior in Debug Settings.
|
||||
|
||||
## Remote mode
|
||||
|
||||
Remote mode never starts a local Gateway. The app uses an SSH tunnel to the
|
||||
remote host and connects over that tunnel.
|
||||
|
||||
## Why we prefer launchd
|
||||
|
||||
- Auto‑start at login.
|
||||
- Built‑in restart/KeepAlive semantics.
|
||||
- Predictable logs and supervision.
|
||||
|
||||
If a true child‑process mode is ever needed again, it should be documented as a
|
||||
separate, explicit dev‑only mode.
|
||||
91
docker-compose/ez-assistant/docs/platforms/mac/dev-setup.md
Normal file
91
docker-compose/ez-assistant/docs/platforms/mac/dev-setup.md
Normal file
@@ -0,0 +1,91 @@
|
||||
---
|
||||
summary: "Setup guide for developers working on the Moltbot macOS app"
|
||||
read_when:
|
||||
- Setting up the macOS development environment
|
||||
---
|
||||
# macOS Developer Setup
|
||||
|
||||
This guide covers the necessary steps to build and run the Moltbot macOS application from source.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before building the app, ensure you have the following installed:
|
||||
|
||||
1. **Xcode 26.2+**: Required for Swift development.
|
||||
2. **Node.js 22+ & pnpm**: Required for the gateway, CLI, and packaging scripts.
|
||||
|
||||
## 1. Install Dependencies
|
||||
|
||||
Install the project-wide dependencies:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
## 2. Build and Package the App
|
||||
|
||||
To build the macOS app and package it into `dist/Moltbot.app`, run:
|
||||
|
||||
```bash
|
||||
./scripts/package-mac-app.sh
|
||||
```
|
||||
|
||||
If you don't have an Apple Developer ID certificate, the script will automatically use **ad-hoc signing** (`-`).
|
||||
|
||||
For dev run modes, signing flags, and Team ID troubleshooting, see the macOS app README:
|
||||
https://github.com/moltbot/moltbot/blob/main/apps/macos/README.md
|
||||
|
||||
> **Note**: Ad-hoc signed apps may trigger security prompts. If the app crashes immediately with "Abort trap 6", see the [Troubleshooting](#troubleshooting) section.
|
||||
|
||||
## 3. Install the CLI
|
||||
|
||||
The macOS app expects a global `moltbot` CLI install to manage background tasks.
|
||||
|
||||
**To install it (recommended):**
|
||||
1. Open the Moltbot app.
|
||||
2. Go to the **General** settings tab.
|
||||
3. Click **"Install CLI"**.
|
||||
|
||||
Alternatively, install it manually:
|
||||
```bash
|
||||
npm install -g moltbot@<version>
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Build Fails: Toolchain or SDK Mismatch
|
||||
The macOS app build expects the latest macOS SDK and Swift 6.2 toolchain.
|
||||
|
||||
**System dependencies (required):**
|
||||
- **Latest macOS version available in Software Update** (required by Xcode 26.2 SDKs)
|
||||
- **Xcode 26.2** (Swift 6.2 toolchain)
|
||||
|
||||
**Checks:**
|
||||
```bash
|
||||
xcodebuild -version
|
||||
xcrun swift --version
|
||||
```
|
||||
|
||||
If versions don’t match, update macOS/Xcode and re-run the build.
|
||||
|
||||
### App Crashes on Permission Grant
|
||||
If the app crashes when you try to allow **Speech Recognition** or **Microphone** access, it may be due to a corrupted TCC cache or signature mismatch.
|
||||
|
||||
**Fix:**
|
||||
1. Reset the TCC permissions:
|
||||
```bash
|
||||
tccutil reset All bot.molt.mac.debug
|
||||
```
|
||||
2. If that fails, change the `BUNDLE_ID` temporarily in [`scripts/package-mac-app.sh`](https://github.com/moltbot/moltbot/blob/main/scripts/package-mac-app.sh) to force a "clean slate" from macOS.
|
||||
|
||||
### Gateway "Starting..." indefinitely
|
||||
If the gateway status stays on "Starting...", check if a zombie process is holding the port:
|
||||
|
||||
```bash
|
||||
moltbot gateway status
|
||||
moltbot gateway stop
|
||||
|
||||
# If you’re not using a LaunchAgent (dev mode / manual runs), find the listener:
|
||||
lsof -nP -iTCP:18789 -sTCP:LISTEN
|
||||
```
|
||||
If a manual run is holding the port, stop that process (Ctrl+C). As a last resort, kill the PID you found above.
|
||||
28
docker-compose/ez-assistant/docs/platforms/mac/health.md
Normal file
28
docker-compose/ez-assistant/docs/platforms/mac/health.md
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
summary: "How the macOS app reports gateway/Baileys health states"
|
||||
read_when:
|
||||
- Debugging mac app health indicators
|
||||
---
|
||||
# Health Checks on macOS
|
||||
|
||||
How to see whether the linked channel is healthy from the menu bar app.
|
||||
|
||||
## Menu bar
|
||||
- Status dot now reflects Baileys health:
|
||||
- Green: linked + socket opened recently.
|
||||
- Orange: connecting/retrying.
|
||||
- Red: logged out or probe failed.
|
||||
- Secondary line reads "linked · auth 12m" or shows the failure reason.
|
||||
- "Run Health Check" menu item triggers an on-demand probe.
|
||||
|
||||
## Settings
|
||||
- General tab gains a Health card showing: linked auth age, session-store path/count, last check time, last error/status code, and buttons for Run Health Check / Reveal Logs.
|
||||
- Uses a cached snapshot so the UI loads instantly and falls back gracefully when offline.
|
||||
- **Channels tab** surfaces channel status + controls for WhatsApp/Telegram (login QR, logout, probe, last disconnect/error).
|
||||
|
||||
## How the probe works
|
||||
- App runs `moltbot health --json` via `ShellExecutor` every ~60s and on demand. The probe loads creds and reports status without sending messages.
|
||||
- Cache the last good snapshot and the last error separately to avoid flicker; show the timestamp of each.
|
||||
|
||||
## When in doubt
|
||||
- You can still use the CLI flow in [Gateway health](/gateway/health) (`moltbot status`, `moltbot status --deep`, `moltbot health --json`) and tail `/tmp/moltbot/moltbot-*.log` for `web-heartbeat` / `web-reconnect`.
|
||||
26
docker-compose/ez-assistant/docs/platforms/mac/icon.md
Normal file
26
docker-compose/ez-assistant/docs/platforms/mac/icon.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
summary: "Menu bar icon states and animations for Moltbot on macOS"
|
||||
read_when:
|
||||
- Changing menu bar icon behavior
|
||||
---
|
||||
# Menu Bar Icon States
|
||||
|
||||
Author: steipete · Updated: 2025-12-06 · Scope: macOS app (`apps/macos`)
|
||||
|
||||
- **Idle:** Normal icon animation (blink, occasional wiggle).
|
||||
- **Paused:** Status item uses `appearsDisabled`; no motion.
|
||||
- **Voice trigger (big ears):** Voice wake detector calls `AppState.triggerVoiceEars(ttl: nil)` when the wake word is heard, keeping `earBoostActive=true` while the utterance is captured. Ears scale up (1.9x), get circular ear holes for readability, then drop via `stopVoiceEars()` after 1s of silence. Only fired from the in-app voice pipeline.
|
||||
- **Working (agent running):** `AppState.isWorking=true` drives a “tail/leg scurry” micro-motion: faster leg wiggle and slight offset while work is in-flight. Currently toggled around WebChat agent runs; add the same toggle around other long tasks when you wire them.
|
||||
|
||||
Wiring points
|
||||
- Voice wake: runtime/tester call `AppState.triggerVoiceEars(ttl: nil)` on trigger and `stopVoiceEars()` after 1s of silence to match the capture window.
|
||||
- Agent activity: set `AppStateStore.shared.setWorking(true/false)` around work spans (already done in WebChat agent call). Keep spans short and reset in `defer` blocks to avoid stuck animations.
|
||||
|
||||
Shapes & sizes
|
||||
- Base icon drawn in `CritterIconRenderer.makeIcon(blink:legWiggle:earWiggle:earScale:earHoles:)`.
|
||||
- Ear scale defaults to `1.0`; voice boost sets `earScale=1.9` and toggles `earHoles=true` without changing overall frame (18×18 pt template image rendered into a 36×36 px Retina backing store).
|
||||
- Scurry uses leg wiggle up to ~1.0 with a small horizontal jiggle; it’s additive to any existing idle wiggle.
|
||||
|
||||
Behavioral notes
|
||||
- No external CLI/broker toggle for ears/working; keep it internal to the app’s own signals to avoid accidental flapping.
|
||||
- Keep TTLs short (<10s) so the icon returns to baseline quickly if a job hangs.
|
||||
51
docker-compose/ez-assistant/docs/platforms/mac/logging.md
Normal file
51
docker-compose/ez-assistant/docs/platforms/mac/logging.md
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
summary: "Moltbot logging: rolling diagnostics file log + unified log privacy flags"
|
||||
read_when:
|
||||
- Capturing macOS logs or investigating private data logging
|
||||
- Debugging voice wake/session lifecycle issues
|
||||
---
|
||||
# Logging (macOS)
|
||||
|
||||
## Rolling diagnostics file log (Debug pane)
|
||||
Moltbot routes macOS app logs through swift-log (unified logging by default) and can write a local, rotating file log to disk when you need a durable capture.
|
||||
|
||||
- Verbosity: **Debug pane → Logs → App logging → Verbosity**
|
||||
- Enable: **Debug pane → Logs → App logging → “Write rolling diagnostics log (JSONL)”**
|
||||
- Location: `~/Library/Logs/Moltbot/diagnostics.jsonl` (rotates automatically; old files are suffixed with `.1`, `.2`, …)
|
||||
- Clear: **Debug pane → Logs → App logging → “Clear”**
|
||||
|
||||
Notes:
|
||||
- This is **off by default**. Enable only while actively debugging.
|
||||
- Treat the file as sensitive; don’t share it without review.
|
||||
|
||||
## Unified logging private data on macOS
|
||||
|
||||
Unified logging redacts most payloads unless a subsystem opts into `privacy -off`. Per Peter's write-up on macOS [logging privacy shenanigans](https://steipete.me/posts/2025/logging-privacy-shenanigans) (2025) this is controlled by a plist in `/Library/Preferences/Logging/Subsystems/` keyed by the subsystem name. Only new log entries pick up the flag, so enable it before reproducing an issue.
|
||||
|
||||
## Enable for Moltbot (`bot.molt`)
|
||||
- Write the plist to a temp file first, then install it atomically as root:
|
||||
|
||||
```bash
|
||||
cat <<'EOF' >/tmp/bot.molt.plist
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>DEFAULT-OPTIONS</key>
|
||||
<dict>
|
||||
<key>Enable-Private-Data</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
sudo install -m 644 -o root -g wheel /tmp/bot.molt.plist /Library/Preferences/Logging/Subsystems/bot.molt.plist
|
||||
```
|
||||
|
||||
- No reboot is required; logd notices the file quickly, but only new log lines will include private payloads.
|
||||
- View the richer output with the existing helper, e.g. `./scripts/clawlog.sh --category WebChat --last 5m`.
|
||||
|
||||
## Disable after debugging
|
||||
- Remove the override: `sudo rm /Library/Preferences/Logging/Subsystems/bot.molt.plist`.
|
||||
- Optionally run `sudo log config --reload` to force logd to drop the override immediately.
|
||||
- Remember this surface can include phone numbers and message bodies; keep the plist in place only while you actively need the extra detail.
|
||||
70
docker-compose/ez-assistant/docs/platforms/mac/menu-bar.md
Normal file
70
docker-compose/ez-assistant/docs/platforms/mac/menu-bar.md
Normal file
@@ -0,0 +1,70 @@
|
||||
---
|
||||
summary: "Menu bar status logic and what is surfaced to users"
|
||||
read_when:
|
||||
- Tweaking mac menu UI or status logic
|
||||
---
|
||||
# Menu Bar Status Logic
|
||||
|
||||
## What is shown
|
||||
- We surface the current agent work state in the menu bar icon and in the first status row of the menu.
|
||||
- Health status is hidden while work is active; it returns when all sessions are idle.
|
||||
- The “Nodes” block in the menu lists **devices** only (paired nodes via `node.list`), not client/presence entries.
|
||||
- A “Usage” section appears under Context when provider usage snapshots are available.
|
||||
|
||||
## State model
|
||||
- Sessions: events arrive with `runId` (per-run) plus `sessionKey` in the payload. The “main” session is the key `main`; if absent, we fall back to the most recently updated session.
|
||||
- Priority: main always wins. If main is active, its state is shown immediately. If main is idle, the most recently active non‑main session is shown. We do not flip‑flop mid‑activity; we only switch when the current session goes idle or main becomes active.
|
||||
- Activity kinds:
|
||||
- `job`: high‑level command execution (`state: started|streaming|done|error`).
|
||||
- `tool`: `phase: start|result` with `toolName` and `meta/args`.
|
||||
|
||||
## IconState enum (Swift)
|
||||
- `idle`
|
||||
- `workingMain(ActivityKind)`
|
||||
- `workingOther(ActivityKind)`
|
||||
- `overridden(ActivityKind)` (debug override)
|
||||
|
||||
### ActivityKind → glyph
|
||||
- `exec` → 💻
|
||||
- `read` → 📄
|
||||
- `write` → ✍️
|
||||
- `edit` → 📝
|
||||
- `attach` → 📎
|
||||
- default → 🛠️
|
||||
|
||||
### Visual mapping
|
||||
- `idle`: normal critter.
|
||||
- `workingMain`: badge with glyph, full tint, leg “working” animation.
|
||||
- `workingOther`: badge with glyph, muted tint, no scurry.
|
||||
- `overridden`: uses the chosen glyph/tint regardless of activity.
|
||||
|
||||
## Status row text (menu)
|
||||
- While work is active: `<Session role> · <activity label>`
|
||||
- Examples: `Main · exec: pnpm test`, `Other · read: apps/macos/Sources/Moltbot/AppState.swift`.
|
||||
- When idle: falls back to the health summary.
|
||||
|
||||
## Event ingestion
|
||||
- Source: control‑channel `agent` events (`ControlChannel.handleAgentEvent`).
|
||||
- Parsed fields:
|
||||
- `stream: "job"` with `data.state` for start/stop.
|
||||
- `stream: "tool"` with `data.phase`, `name`, optional `meta`/`args`.
|
||||
- Labels:
|
||||
- `exec`: first line of `args.command`.
|
||||
- `read`/`write`: shortened path.
|
||||
- `edit`: path plus inferred change kind from `meta`/diff counts.
|
||||
- fallback: tool name.
|
||||
|
||||
## Debug override
|
||||
- Settings ▸ Debug ▸ “Icon override” picker:
|
||||
- `System (auto)` (default)
|
||||
- `Working: main` (per tool kind)
|
||||
- `Working: other` (per tool kind)
|
||||
- `Idle`
|
||||
- Stored via `@AppStorage("iconOverride")`; mapped to `IconState.overridden`.
|
||||
|
||||
## Testing checklist
|
||||
- Trigger main session job: verify icon switches immediately and status row shows main label.
|
||||
- Trigger non‑main session job while main idle: icon/status shows non‑main; stays stable until it finishes.
|
||||
- Start main while other active: icon flips to main instantly.
|
||||
- Rapid tool bursts: ensure badge does not flicker (TTL grace on tool results).
|
||||
- Health row reappears once all sessions idle.
|
||||
62
docker-compose/ez-assistant/docs/platforms/mac/peekaboo.md
Normal file
62
docker-compose/ez-assistant/docs/platforms/mac/peekaboo.md
Normal file
@@ -0,0 +1,62 @@
|
||||
---
|
||||
summary: "PeekabooBridge integration for macOS UI automation"
|
||||
read_when:
|
||||
- Hosting PeekabooBridge in Moltbot.app
|
||||
- Integrating Peekaboo via Swift Package Manager
|
||||
- Changing PeekabooBridge protocol/paths
|
||||
---
|
||||
# Peekaboo Bridge (macOS UI automation)
|
||||
|
||||
Moltbot can host **PeekabooBridge** as a local, permission‑aware UI automation
|
||||
broker. This lets the `peekaboo` CLI drive UI automation while reusing the
|
||||
macOS app’s TCC permissions.
|
||||
|
||||
## What this is (and isn’t)
|
||||
|
||||
- **Host**: Moltbot.app can act as a PeekabooBridge host.
|
||||
- **Client**: use the `peekaboo` CLI (no separate `moltbot ui ...` surface).
|
||||
- **UI**: visual overlays stay in Peekaboo.app; Moltbot is a thin broker host.
|
||||
|
||||
## Enable the bridge
|
||||
|
||||
In the macOS app:
|
||||
- Settings → **Enable Peekaboo Bridge**
|
||||
|
||||
When enabled, Moltbot starts a local UNIX socket server. If disabled, the host
|
||||
is stopped and `peekaboo` will fall back to other available hosts.
|
||||
|
||||
## Client discovery order
|
||||
|
||||
Peekaboo clients typically try hosts in this order:
|
||||
|
||||
1. Peekaboo.app (full UX)
|
||||
2. Claude.app (if installed)
|
||||
3. Moltbot.app (thin broker)
|
||||
|
||||
Use `peekaboo bridge status --verbose` to see which host is active and which
|
||||
socket path is in use. You can override with:
|
||||
|
||||
```bash
|
||||
export PEEKABOO_BRIDGE_SOCKET=/path/to/bridge.sock
|
||||
```
|
||||
|
||||
## Security & permissions
|
||||
|
||||
- The bridge validates **caller code signatures**; an allowlist of TeamIDs is
|
||||
enforced (Peekaboo host TeamID + Moltbot app TeamID).
|
||||
- Requests time out after ~10 seconds.
|
||||
- If required permissions are missing, the bridge returns a clear error message
|
||||
rather than launching System Settings.
|
||||
|
||||
## Snapshot behavior (automation)
|
||||
|
||||
Snapshots are stored in memory and expire automatically after a short window.
|
||||
If you need longer retention, re‑capture from the client.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- If `peekaboo` reports “bridge client is not authorized”, ensure the client is
|
||||
properly signed or run the host with `PEEKABOO_ALLOW_UNSIGNED_SOCKET_CLIENTS=1`
|
||||
in **debug** mode only.
|
||||
- If no hosts are found, open one of the host apps (Peekaboo.app or Moltbot.app)
|
||||
and confirm permissions are granted.
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
summary: "macOS permission persistence (TCC) and signing requirements"
|
||||
read_when:
|
||||
- Debugging missing or stuck macOS permission prompts
|
||||
- Packaging or signing the macOS app
|
||||
- Changing bundle IDs or app install paths
|
||||
---
|
||||
# macOS permissions (TCC)
|
||||
|
||||
macOS permission grants are fragile. TCC associates a permission grant with the
|
||||
app's code signature, bundle identifier, and on-disk path. If any of those change,
|
||||
macOS treats the app as new and may drop or hide prompts.
|
||||
|
||||
## Requirements for stable permissions
|
||||
- Same path: run the app from a fixed location (for Moltbot, `dist/Moltbot.app`).
|
||||
- Same bundle identifier: changing the bundle ID creates a new permission identity.
|
||||
- Signed app: unsigned or ad-hoc signed builds do not persist permissions.
|
||||
- Consistent signature: use a real Apple Development or Developer ID certificate
|
||||
so the signature stays stable across rebuilds.
|
||||
|
||||
Ad-hoc signatures generate a new identity every build. macOS will forget previous
|
||||
grants, and prompts can disappear entirely until the stale entries are cleared.
|
||||
|
||||
## Recovery checklist when prompts disappear
|
||||
1. Quit the app.
|
||||
2. Remove the app entry in System Settings -> Privacy & Security.
|
||||
3. Relaunch the app from the same path and re-grant permissions.
|
||||
4. If the prompt still does not appear, reset TCC entries with `tccutil` and try again.
|
||||
5. Some permissions only reappear after a full macOS restart.
|
||||
|
||||
Example resets (replace bundle ID as needed):
|
||||
|
||||
```bash
|
||||
sudo tccutil reset Accessibility bot.molt.mac
|
||||
sudo tccutil reset ScreenCapture bot.molt.mac
|
||||
sudo tccutil reset AppleEvents
|
||||
```
|
||||
|
||||
If you are testing permissions, always sign with a real certificate. Ad-hoc
|
||||
builds are only acceptable for quick local runs where permissions do not matter.
|
||||
77
docker-compose/ez-assistant/docs/platforms/mac/release.md
Normal file
77
docker-compose/ez-assistant/docs/platforms/mac/release.md
Normal file
@@ -0,0 +1,77 @@
|
||||
---
|
||||
summary: "Moltbot macOS release checklist (Sparkle feed, packaging, signing)"
|
||||
read_when:
|
||||
- Cutting or validating a Moltbot macOS release
|
||||
- Updating the Sparkle appcast or feed assets
|
||||
---
|
||||
|
||||
# Moltbot macOS release (Sparkle)
|
||||
|
||||
This app now ships Sparkle auto-updates. Release builds must be Developer ID–signed, zipped, and published with a signed appcast entry.
|
||||
|
||||
## Prereqs
|
||||
- Developer ID Application cert installed (example: `Developer ID Application: <Developer Name> (<TEAMID>)`).
|
||||
- Sparkle private key path set in the environment as `SPARKLE_PRIVATE_KEY_FILE` (path to your Sparkle ed25519 private key; public key baked into Info.plist). If it is missing, check `~/.profile`.
|
||||
- Notary credentials (keychain profile or API key) for `xcrun notarytool` if you want Gatekeeper-safe DMG/zip distribution.
|
||||
- We use a Keychain profile named `moltbot-notary`, created from App Store Connect API key env vars in your shell profile:
|
||||
- `APP_STORE_CONNECT_API_KEY_P8`, `APP_STORE_CONNECT_KEY_ID`, `APP_STORE_CONNECT_ISSUER_ID`
|
||||
- `echo "$APP_STORE_CONNECT_API_KEY_P8" | sed 's/\\n/\n/g' > /tmp/moltbot-notary.p8`
|
||||
- `xcrun notarytool store-credentials "moltbot-notary" --key /tmp/moltbot-notary.p8 --key-id "$APP_STORE_CONNECT_KEY_ID" --issuer "$APP_STORE_CONNECT_ISSUER_ID"`
|
||||
- `pnpm` deps installed (`pnpm install --config.node-linker=hoisted`).
|
||||
- Sparkle tools are fetched automatically via SwiftPM at `apps/macos/.build/artifacts/sparkle/Sparkle/bin/` (`sign_update`, `generate_appcast`, etc.).
|
||||
|
||||
## Build & package
|
||||
Notes:
|
||||
- `APP_BUILD` maps to `CFBundleVersion`/`sparkle:version`; keep it numeric + monotonic (no `-beta`), or Sparkle compares it as equal.
|
||||
- Defaults to the current architecture (`$(uname -m)`). For release/universal builds, set `BUILD_ARCHS="arm64 x86_64"` (or `BUILD_ARCHS=all`).
|
||||
- Use `scripts/package-mac-dist.sh` for release artifacts (zip + DMG + notarization). Use `scripts/package-mac-app.sh` for local/dev packaging.
|
||||
|
||||
```bash
|
||||
# From repo root; set release IDs so Sparkle feed is enabled.
|
||||
# APP_BUILD must be numeric + monotonic for Sparkle compare.
|
||||
BUNDLE_ID=bot.molt.mac \
|
||||
APP_VERSION=2026.1.26 \
|
||||
APP_BUILD="$(git rev-list --count HEAD)" \
|
||||
BUILD_CONFIG=release \
|
||||
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
||||
scripts/package-mac-app.sh
|
||||
|
||||
# Zip for distribution (includes resource forks for Sparkle delta support)
|
||||
ditto -c -k --sequesterRsrc --keepParent dist/Moltbot.app dist/Moltbot-2026.1.26.zip
|
||||
|
||||
# Optional: also build a styled DMG for humans (drag to /Applications)
|
||||
scripts/create-dmg.sh dist/Moltbot.app dist/Moltbot-2026.1.26.dmg
|
||||
|
||||
# Recommended: build + notarize/staple zip + DMG
|
||||
# First, create a keychain profile once:
|
||||
# xcrun notarytool store-credentials "moltbot-notary" \
|
||||
# --apple-id "<apple-id>" --team-id "<team-id>" --password "<app-specific-password>"
|
||||
NOTARIZE=1 NOTARYTOOL_PROFILE=moltbot-notary \
|
||||
BUNDLE_ID=bot.molt.mac \
|
||||
APP_VERSION=2026.1.26 \
|
||||
APP_BUILD="$(git rev-list --count HEAD)" \
|
||||
BUILD_CONFIG=release \
|
||||
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
||||
scripts/package-mac-dist.sh
|
||||
|
||||
# Optional: ship dSYM alongside the release
|
||||
ditto -c -k --keepParent apps/macos/.build/release/Moltbot.app.dSYM dist/Moltbot-2026.1.26.dSYM.zip
|
||||
```
|
||||
|
||||
## Appcast entry
|
||||
Use the release note generator so Sparkle renders formatted HTML notes:
|
||||
```bash
|
||||
SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/Moltbot-2026.1.26.zip https://raw.githubusercontent.com/moltbot/moltbot/main/appcast.xml
|
||||
```
|
||||
Generates HTML release notes from `CHANGELOG.md` (via [`scripts/changelog-to-html.sh`](https://github.com/moltbot/moltbot/blob/main/scripts/changelog-to-html.sh)) and embeds them in the appcast entry.
|
||||
Commit the updated `appcast.xml` alongside the release assets (zip + dSYM) when publishing.
|
||||
|
||||
## Publish & verify
|
||||
- Upload `Moltbot-2026.1.26.zip` (and `Moltbot-2026.1.26.dSYM.zip`) to the GitHub release for tag `v2026.1.26`.
|
||||
- Ensure the raw appcast URL matches the baked feed: `https://raw.githubusercontent.com/moltbot/moltbot/main/appcast.xml`.
|
||||
- Sanity checks:
|
||||
- `curl -I https://raw.githubusercontent.com/moltbot/moltbot/main/appcast.xml` returns 200.
|
||||
- `curl -I <enclosure url>` returns 200 after assets upload.
|
||||
- On a previous public build, run “Check for Updates…” from the About tab and verify Sparkle installs the new build cleanly.
|
||||
|
||||
Definition of done: signed app + appcast are published, update flow works from an older installed version, and release assets are attached to the GitHub release.
|
||||
71
docker-compose/ez-assistant/docs/platforms/mac/remote.md
Normal file
71
docker-compose/ez-assistant/docs/platforms/mac/remote.md
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
summary: "macOS app flow for controlling a remote Moltbot gateway over SSH"
|
||||
read_when:
|
||||
- Setting up or debugging remote mac control
|
||||
---
|
||||
# Remote Moltbot (macOS ⇄ remote host)
|
||||
|
||||
|
||||
This flow lets the macOS app act as a full remote control for a Moltbot gateway running on another host (desktop/server). It’s the app’s **Remote over SSH** (remote run) feature. All features—health checks, Voice Wake forwarding, and Web Chat—reuse the same remote SSH configuration from *Settings → General*.
|
||||
|
||||
## Modes
|
||||
- **Local (this Mac)**: Everything runs on the laptop. No SSH involved.
|
||||
- **Remote over SSH (default)**: Moltbot commands are executed on the remote host. The mac app opens an SSH connection with `-o BatchMode` plus your chosen identity/key and a local port-forward.
|
||||
- **Remote direct (ws/wss)**: No SSH tunnel. The mac app connects to the gateway URL directly (for example, via Tailscale Serve or a public HTTPS reverse proxy).
|
||||
|
||||
## Remote transports
|
||||
Remote mode supports two transports:
|
||||
- **SSH tunnel** (default): Uses `ssh -N -L ...` to forward the gateway port to localhost. The gateway will see the node’s IP as `127.0.0.1` because the tunnel is loopback.
|
||||
- **Direct (ws/wss)**: Connects straight to the gateway URL. The gateway sees the real client IP.
|
||||
|
||||
## Prereqs on the remote host
|
||||
1) Install Node + pnpm and build/install the Moltbot CLI (`pnpm install && pnpm build && pnpm link --global`).
|
||||
2) Ensure `moltbot` is on PATH for non-interactive shells (symlink into `/usr/local/bin` or `/opt/homebrew/bin` if needed).
|
||||
3) Open SSH with key auth. We recommend **Tailscale** IPs for stable reachability off-LAN.
|
||||
|
||||
## macOS app setup
|
||||
1) Open *Settings → General*.
|
||||
2) Under **Moltbot runs**, pick **Remote over SSH** and set:
|
||||
- **Transport**: **SSH tunnel** or **Direct (ws/wss)**.
|
||||
- **SSH target**: `user@host` (optional `:port`).
|
||||
- If the gateway is on the same LAN and advertises Bonjour, pick it from the discovered list to auto-fill this field.
|
||||
- **Gateway URL** (Direct only): `wss://gateway.example.ts.net` (or `ws://...` for local/LAN).
|
||||
- **Identity file** (advanced): path to your key.
|
||||
- **Project root** (advanced): remote checkout path used for commands.
|
||||
- **CLI path** (advanced): optional path to a runnable `moltbot` entrypoint/binary (auto-filled when advertised).
|
||||
3) Hit **Test remote**. Success indicates the remote `moltbot status --json` runs correctly. Failures usually mean PATH/CLI issues; exit 127 means the CLI isn’t found remotely.
|
||||
4) Health checks and Web Chat will now run through this SSH tunnel automatically.
|
||||
|
||||
## Web Chat
|
||||
- **SSH tunnel**: Web Chat connects to the gateway over the forwarded WebSocket control port (default 18789).
|
||||
- **Direct (ws/wss)**: Web Chat connects straight to the configured gateway URL.
|
||||
- There is no separate WebChat HTTP server anymore.
|
||||
|
||||
## Permissions
|
||||
- The remote host needs the same TCC approvals as local (Automation, Accessibility, Screen Recording, Microphone, Speech Recognition, Notifications). Run onboarding on that machine to grant them once.
|
||||
- Nodes advertise their permission state via `node.list` / `node.describe` so agents know what’s available.
|
||||
|
||||
## Security notes
|
||||
- Prefer loopback binds on the remote host and connect via SSH or Tailscale.
|
||||
- If you bind the Gateway to a non-loopback interface, require token/password auth.
|
||||
- See [Security](/gateway/security) and [Tailscale](/gateway/tailscale).
|
||||
|
||||
## WhatsApp login flow (remote)
|
||||
- Run `moltbot channels login --verbose` **on the remote host**. Scan the QR with WhatsApp on your phone.
|
||||
- Re-run login on that host if auth expires. Health check will surface link problems.
|
||||
|
||||
## Troubleshooting
|
||||
- **exit 127 / not found**: `moltbot` isn’t on PATH for non-login shells. Add it to `/etc/paths`, your shell rc, or symlink into `/usr/local/bin`/`/opt/homebrew/bin`.
|
||||
- **Health probe failed**: check SSH reachability, PATH, and that Baileys is logged in (`moltbot status --json`).
|
||||
- **Web Chat stuck**: confirm the gateway is running on the remote host and the forwarded port matches the gateway WS port; the UI requires a healthy WS connection.
|
||||
- **Node IP shows 127.0.0.1**: expected with the SSH tunnel. Switch **Transport** to **Direct (ws/wss)** if you want the gateway to see the real client IP.
|
||||
- **Voice Wake**: trigger phrases are forwarded automatically in remote mode; no separate forwarder is needed.
|
||||
|
||||
## Notification sounds
|
||||
Pick sounds per notification from scripts with `moltbot` and `node.invoke`, e.g.:
|
||||
|
||||
```bash
|
||||
moltbot nodes notify --node <id> --title "Ping" --body "Remote gateway ready" --sound Glass
|
||||
```
|
||||
|
||||
There is no global “default sound” toggle in the app anymore; callers choose a sound (or none) per request.
|
||||
43
docker-compose/ez-assistant/docs/platforms/mac/signing.md
Normal file
43
docker-compose/ez-assistant/docs/platforms/mac/signing.md
Normal file
@@ -0,0 +1,43 @@
|
||||
---
|
||||
summary: "Signing steps for macOS debug builds generated by packaging scripts"
|
||||
read_when:
|
||||
- Building or signing mac debug builds
|
||||
---
|
||||
# mac signing (debug builds)
|
||||
|
||||
This app is usually built from [`scripts/package-mac-app.sh`](https://github.com/moltbot/moltbot/blob/main/scripts/package-mac-app.sh), which now:
|
||||
|
||||
- sets a stable debug bundle identifier: `bot.molt.mac.debug`
|
||||
- writes the Info.plist with that bundle id (override via `BUNDLE_ID=...`)
|
||||
- calls [`scripts/codesign-mac-app.sh`](https://github.com/moltbot/moltbot/blob/main/scripts/codesign-mac-app.sh) to sign the main binary and app bundle so macOS treats each rebuild as the same signed bundle and keeps TCC permissions (notifications, accessibility, screen recording, mic, speech). For stable permissions, use a real signing identity; ad-hoc is opt-in and fragile (see [macOS permissions](/platforms/mac/permissions)).
|
||||
- uses `CODESIGN_TIMESTAMP=auto` by default; it enables trusted timestamps for Developer ID signatures. Set `CODESIGN_TIMESTAMP=off` to skip timestamping (offline debug builds).
|
||||
- inject build metadata into Info.plist: `MoltbotBuildTimestamp` (UTC) and `MoltbotGitCommit` (short hash) so the About pane can show build, git, and debug/release channel.
|
||||
- **Packaging requires Node 22+**: the script runs TS builds and the Control UI build.
|
||||
- reads `SIGN_IDENTITY` from the environment. Add `export SIGN_IDENTITY="Apple Development: Your Name (TEAMID)"` (or your Developer ID Application cert) to your shell rc to always sign with your cert. Ad-hoc signing requires explicit opt-in via `ALLOW_ADHOC_SIGNING=1` or `SIGN_IDENTITY="-"` (not recommended for permission testing).
|
||||
- runs a Team ID audit after signing and fails if any Mach-O inside the app bundle is signed by a different Team ID. Set `SKIP_TEAM_ID_CHECK=1` to bypass.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# from repo root
|
||||
scripts/package-mac-app.sh # auto-selects identity; errors if none found
|
||||
SIGN_IDENTITY="Developer ID Application: Your Name" scripts/package-mac-app.sh # real cert
|
||||
ALLOW_ADHOC_SIGNING=1 scripts/package-mac-app.sh # ad-hoc (permissions will not stick)
|
||||
SIGN_IDENTITY="-" scripts/package-mac-app.sh # explicit ad-hoc (same caveat)
|
||||
DISABLE_LIBRARY_VALIDATION=1 scripts/package-mac-app.sh # dev-only Sparkle Team ID mismatch workaround
|
||||
```
|
||||
|
||||
### Ad-hoc Signing Note
|
||||
When signing with `SIGN_IDENTITY="-"` (ad-hoc), the script automatically disables the **Hardened Runtime** (`--options runtime`). This is necessary to prevent crashes when the app attempts to load embedded frameworks (like Sparkle) that do not share the same Team ID. Ad-hoc signatures also break TCC permission persistence; see [macOS permissions](/platforms/mac/permissions) for recovery steps.
|
||||
|
||||
## Build metadata for About
|
||||
|
||||
`package-mac-app.sh` stamps the bundle with:
|
||||
- `MoltbotBuildTimestamp`: ISO8601 UTC at package time
|
||||
- `MoltbotGitCommit`: short git hash (or `unknown` if unavailable)
|
||||
|
||||
The About tab reads these keys to show version, build date, git commit, and whether it’s a debug build (via `#if DEBUG`). Run the packager to refresh these values after code changes.
|
||||
|
||||
## Why
|
||||
|
||||
TCC permissions are tied to the bundle identifier *and* code signature. Unsigned debug builds with changing UUIDs were causing macOS to forget grants after each rebuild. Signing the binaries (ad‑hoc by default) and keeping a fixed bundle id/path (`dist/Moltbot.app`) preserves the grants between builds, matching the VibeTunnel approach.
|
||||
27
docker-compose/ez-assistant/docs/platforms/mac/skills.md
Normal file
27
docker-compose/ez-assistant/docs/platforms/mac/skills.md
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
summary: "macOS Skills settings UI and gateway-backed status"
|
||||
read_when:
|
||||
- Updating the macOS Skills settings UI
|
||||
- Changing skills gating or install behavior
|
||||
---
|
||||
# Skills (macOS)
|
||||
|
||||
The macOS app surfaces Moltbot skills via the gateway; it does not parse skills locally.
|
||||
|
||||
## Data source
|
||||
- `skills.status` (gateway) returns all skills plus eligibility and missing requirements
|
||||
(including allowlist blocks for bundled skills).
|
||||
- Requirements are derived from `metadata.clawdbot.requires` in each `SKILL.md`.
|
||||
|
||||
## Install actions
|
||||
- `metadata.clawdbot.install` defines install options (brew/node/go/uv).
|
||||
- The app calls `skills.install` to run installers on the gateway host.
|
||||
- The gateway surfaces only one preferred installer when multiple are provided
|
||||
(brew when available, otherwise node manager from `skills.install`, default npm).
|
||||
|
||||
## Env/API keys
|
||||
- The app stores keys in `~/.clawdbot/moltbot.json` under `skills.entries.<skillKey>`.
|
||||
- `skills.update` patches `enabled`, `apiKey`, and `env`.
|
||||
|
||||
## Remote mode
|
||||
- Install + config updates happen on the gateway host (not the local Mac).
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
summary: "Voice overlay lifecycle when wake-word and push-to-talk overlap"
|
||||
read_when:
|
||||
- Adjusting voice overlay behavior
|
||||
---
|
||||
# Voice Overlay Lifecycle (macOS)
|
||||
|
||||
Audience: macOS app contributors. Goal: keep the voice overlay predictable when wake-word and push-to-talk overlap.
|
||||
|
||||
### Current intent
|
||||
- If the overlay is already visible from wake-word and the user presses the hotkey, the hotkey session *adopts* the existing text instead of resetting it. The overlay stays up while the hotkey is held. When the user releases: send if there is trimmed text, otherwise dismiss.
|
||||
- Wake-word alone still auto-sends on silence; push-to-talk sends immediately on release.
|
||||
|
||||
### Implemented (Dec 9, 2025)
|
||||
- Overlay sessions now carry a token per capture (wake-word or push-to-talk). Partial/final/send/dismiss/level updates are dropped when the token doesn’t match, avoiding stale callbacks.
|
||||
- Push-to-talk adopts any visible overlay text as a prefix (so pressing the hotkey while the wake overlay is up keeps the text and appends new speech). It waits up to 1.5s for a final transcript before falling back to the current text.
|
||||
- Chime/overlay logging is emitted at `info` in categories `voicewake.overlay`, `voicewake.ptt`, and `voicewake.chime` (session start, partial, final, send, dismiss, chime reason).
|
||||
|
||||
### Next steps
|
||||
1. **VoiceSessionCoordinator (actor)**
|
||||
- Owns exactly one `VoiceSession` at a time.
|
||||
- API (token-based): `beginWakeCapture`, `beginPushToTalk`, `updatePartial`, `endCapture`, `cancel`, `applyCooldown`.
|
||||
- Drops callbacks that carry stale tokens (prevents old recognizers from reopening the overlay).
|
||||
2. **VoiceSession (model)**
|
||||
- Fields: `token`, `source` (wakeWord|pushToTalk), committed/volatile text, chime flags, timers (auto-send, idle), `overlayMode` (display|editing|sending), cooldown deadline.
|
||||
3. **Overlay binding**
|
||||
- `VoiceSessionPublisher` (`ObservableObject`) mirrors the active session into SwiftUI.
|
||||
- `VoiceWakeOverlayView` renders only via the publisher; it never mutates global singletons directly.
|
||||
- Overlay user actions (`sendNow`, `dismiss`, `edit`) call back into the coordinator with the session token.
|
||||
4. **Unified send path**
|
||||
- On `endCapture`: if trimmed text is empty → dismiss; else `performSend(session:)` (plays send chime once, forwards, dismisses).
|
||||
- Push-to-talk: no delay; wake-word: optional delay for auto-send.
|
||||
- Apply a short cooldown to the wake runtime after push-to-talk finishes so wake-word doesn’t immediately retrigger.
|
||||
5. **Logging**
|
||||
- Coordinator emits `.info` logs in subsystem `bot.molt`, categories `voicewake.overlay` and `voicewake.chime`.
|
||||
- Key events: `session_started`, `adopted_by_push_to_talk`, `partial`, `finalized`, `send`, `dismiss`, `cancel`, `cooldown`.
|
||||
|
||||
### Debugging checklist
|
||||
- Stream logs while reproducing a sticky overlay:
|
||||
|
||||
```bash
|
||||
sudo log stream --predicate 'subsystem == "bot.molt" AND category CONTAINS "voicewake"' --level info --style compact
|
||||
```
|
||||
- Verify only one active session token; stale callbacks should be dropped by the coordinator.
|
||||
- Ensure push-to-talk release always calls `endCapture` with the active token; if text is empty, expect `dismiss` without chime or send.
|
||||
|
||||
### Migration steps (suggested)
|
||||
1. Add `VoiceSessionCoordinator`, `VoiceSession`, and `VoiceSessionPublisher`.
|
||||
2. Refactor `VoiceWakeRuntime` to create/update/end sessions instead of touching `VoiceWakeOverlayController` directly.
|
||||
3. Refactor `VoicePushToTalk` to adopt existing sessions and call `endCapture` on release; apply runtime cooldown.
|
||||
4. Wire `VoiceWakeOverlayController` to the publisher; remove direct calls from runtime/PTT.
|
||||
5. Add integration tests for session adoption, cooldown, and empty-text dismissal.
|
||||
56
docker-compose/ez-assistant/docs/platforms/mac/voicewake.md
Normal file
56
docker-compose/ez-assistant/docs/platforms/mac/voicewake.md
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
summary: "Voice wake and push-to-talk modes plus routing details in the mac app"
|
||||
read_when:
|
||||
- Working on voice wake or PTT pathways
|
||||
---
|
||||
# Voice Wake & Push-to-Talk
|
||||
|
||||
|
||||
## Modes
|
||||
- **Wake-word mode** (default): always-on Speech recognizer waits for trigger tokens (`swabbleTriggerWords`). On match it starts capture, shows the overlay with partial text, and auto-sends after silence.
|
||||
- **Push-to-talk (Right Option hold)**: hold the right Option key to capture immediately—no trigger needed. The overlay appears while held; releasing finalizes and forwards after a short delay so you can tweak text.
|
||||
|
||||
## Runtime behavior (wake-word)
|
||||
- Speech recognizer lives in `VoiceWakeRuntime`.
|
||||
- Trigger only fires when there’s a **meaningful pause** between the wake word and the next word (~0.55s gap). The overlay/chime can start on the pause even before the command begins.
|
||||
- Silence windows: 2.0s when speech is flowing, 5.0s if only the trigger was heard.
|
||||
- Hard stop: 120s to prevent runaway sessions.
|
||||
- Debounce between sessions: 350ms.
|
||||
- Overlay is driven via `VoiceWakeOverlayController` with committed/volatile coloring.
|
||||
- After send, recognizer restarts cleanly to listen for the next trigger.
|
||||
|
||||
## Lifecycle invariants
|
||||
- If Voice Wake is enabled and permissions are granted, the wake-word recognizer should be listening (except during an explicit push-to-talk capture).
|
||||
- Overlay visibility (including manual dismiss via the X button) must never prevent the recognizer from resuming.
|
||||
|
||||
## Sticky overlay failure mode (previous)
|
||||
Previously, if the overlay got stuck visible and you manually closed it, Voice Wake could appear “dead” because the runtime’s restart attempt could be blocked by overlay visibility and no subsequent restart was scheduled.
|
||||
|
||||
Hardening:
|
||||
- Wake runtime restart is no longer blocked by overlay visibility.
|
||||
- Overlay dismiss completion triggers a `VoiceWakeRuntime.refresh(...)` via `VoiceSessionCoordinator`, so manual X-dismiss always resumes listening.
|
||||
|
||||
## Push-to-talk specifics
|
||||
- Hotkey detection uses a global `.flagsChanged` monitor for **right Option** (`keyCode 61` + `.option`). We only observe events (no swallowing).
|
||||
- Capture pipeline lives in `VoicePushToTalk`: starts Speech immediately, streams partials to the overlay, and calls `VoiceWakeForwarder` on release.
|
||||
- When push-to-talk starts we pause the wake-word runtime to avoid dueling audio taps; it restarts automatically after release.
|
||||
- Permissions: requires Microphone + Speech; seeing events needs Accessibility/Input Monitoring approval.
|
||||
- External keyboards: some may not expose right Option as expected—offer a fallback shortcut if users report misses.
|
||||
|
||||
## User-facing settings
|
||||
- **Voice Wake** toggle: enables wake-word runtime.
|
||||
- **Hold Cmd+Fn to talk**: enables the push-to-talk monitor. Disabled on macOS < 26.
|
||||
- Language & mic pickers, live level meter, trigger-word table, tester (local-only; does not forward).
|
||||
- Mic picker preserves the last selection if a device disconnects, shows a disconnected hint, and temporarily falls back to the system default until it returns.
|
||||
- **Sounds**: chimes on trigger detect and on send; defaults to the macOS “Glass” system sound. You can pick any `NSSound`-loadable file (e.g. MP3/WAV/AIFF) for each event or choose **No Sound**.
|
||||
|
||||
## Forwarding behavior
|
||||
- When Voice Wake is enabled, transcripts are forwarded to the active gateway/agent (the same local vs remote mode used by the rest of the mac app).
|
||||
- Replies are delivered to the **last-used main provider** (WhatsApp/Telegram/Discord/WebChat). If delivery fails, the error is logged and the run is still visible via WebChat/session logs.
|
||||
|
||||
## Forwarding payload
|
||||
- `VoiceWakeForwarder.prefixedTranscript(_:)` prepends the machine hint before sending. Shared between wake-word and push-to-talk paths.
|
||||
|
||||
## Quick verification
|
||||
- Toggle push-to-talk on, hold Cmd+Fn, speak, release: overlay should show partials then send.
|
||||
- While holding, menu-bar ears should stay enlarged (uses `triggerVoiceEars(ttl:nil)`); they drop after release.
|
||||
39
docker-compose/ez-assistant/docs/platforms/mac/webchat.md
Normal file
39
docker-compose/ez-assistant/docs/platforms/mac/webchat.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
summary: "How the mac app embeds the gateway WebChat and how to debug it"
|
||||
read_when:
|
||||
- Debugging mac WebChat view or loopback port
|
||||
---
|
||||
# WebChat (macOS app)
|
||||
|
||||
The macOS menu bar app embeds the WebChat UI as a native SwiftUI view. It
|
||||
connects to the Gateway and defaults to the **main session** for the selected
|
||||
agent (with a session switcher for other sessions).
|
||||
|
||||
- **Local mode**: connects directly to the local Gateway WebSocket.
|
||||
- **Remote mode**: forwards the Gateway control port over SSH and uses that
|
||||
tunnel as the data plane.
|
||||
|
||||
## Launch & debugging
|
||||
|
||||
- Manual: Lobster menu → “Open Chat”.
|
||||
- Auto‑open for testing:
|
||||
```bash
|
||||
dist/Moltbot.app/Contents/MacOS/Moltbot --webchat
|
||||
```
|
||||
- Logs: `./scripts/clawlog.sh` (subsystem `bot.molt`, category `WebChatSwiftUI`).
|
||||
|
||||
## How it’s wired
|
||||
|
||||
- Data plane: Gateway WS methods `chat.history`, `chat.send`, `chat.abort`,
|
||||
`chat.inject` and events `chat`, `agent`, `presence`, `tick`, `health`.
|
||||
- Session: defaults to the primary session (`main`, or `global` when scope is
|
||||
global). The UI can switch between sessions.
|
||||
- Onboarding uses a dedicated session to keep first‑run setup separate.
|
||||
|
||||
## Security surface
|
||||
|
||||
- Remote mode forwards only the Gateway WebSocket control port over SSH.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- The UI is optimized for chat sessions (not a full browser sandbox).
|
||||
51
docker-compose/ez-assistant/docs/platforms/mac/xpc.md
Normal file
51
docker-compose/ez-assistant/docs/platforms/mac/xpc.md
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
summary: "macOS IPC architecture for Moltbot app, gateway node transport, and PeekabooBridge"
|
||||
read_when:
|
||||
- Editing IPC contracts or menu bar app IPC
|
||||
---
|
||||
# Moltbot macOS IPC architecture
|
||||
|
||||
**Current model:** a local Unix socket connects the **node host service** to the **macOS app** for exec approvals + `system.run`. A `moltbot-mac` debug CLI exists for discovery/connect checks; agent actions still flow through the Gateway WebSocket and `node.invoke`. UI automation uses PeekabooBridge.
|
||||
|
||||
## Goals
|
||||
- Single GUI app instance that owns all TCC-facing work (notifications, screen recording, mic, speech, AppleScript).
|
||||
- A small surface for automation: Gateway + node commands, plus PeekabooBridge for UI automation.
|
||||
- Predictable permissions: always the same signed bundle ID, launched by launchd, so TCC grants stick.
|
||||
|
||||
## How it works
|
||||
### Gateway + node transport
|
||||
- The app runs the Gateway (local mode) and connects to it as a node.
|
||||
- Agent actions are performed via `node.invoke` (e.g. `system.run`, `system.notify`, `canvas.*`).
|
||||
|
||||
### Node service + app IPC
|
||||
- A headless node host service connects to the Gateway WebSocket.
|
||||
- `system.run` requests are forwarded to the macOS app over a local Unix socket.
|
||||
- The app performs the exec in UI context, prompts if needed, and returns output.
|
||||
|
||||
Diagram (SCI):
|
||||
```
|
||||
Agent -> Gateway -> Node Service (WS)
|
||||
| IPC (UDS + token + HMAC + TTL)
|
||||
v
|
||||
Mac App (UI + TCC + system.run)
|
||||
```
|
||||
|
||||
### PeekabooBridge (UI automation)
|
||||
- UI automation uses a separate UNIX socket named `bridge.sock` and the PeekabooBridge JSON protocol.
|
||||
- Host preference order (client-side): Peekaboo.app → Claude.app → Moltbot.app → local execution.
|
||||
- Security: bridge hosts require an allowed TeamID; DEBUG-only same-UID escape hatch is guarded by `PEEKABOO_ALLOW_UNSIGNED_SOCKET_CLIENTS=1` (Peekaboo convention).
|
||||
- See: [PeekabooBridge usage](/platforms/mac/peekaboo) for details.
|
||||
|
||||
## Operational flows
|
||||
- Restart/rebuild: `SIGN_IDENTITY="Apple Development: <Developer Name> (<TEAMID>)" scripts/restart-mac.sh`
|
||||
- Kills existing instances
|
||||
- Swift build + package
|
||||
- Writes/bootstraps/kickstarts the LaunchAgent
|
||||
- Single instance: app exits early if another instance with the same bundle ID is running.
|
||||
|
||||
## Hardening notes
|
||||
- Prefer requiring a TeamID match for all privileged surfaces.
|
||||
- PeekabooBridge: `PEEKABOO_ALLOW_UNSIGNED_SOCKET_CLIENTS=1` (DEBUG-only) may allow same-UID callers for local development.
|
||||
- All communication remains local-only; no network sockets are exposed.
|
||||
- TCC prompts originate only from the GUI app bundle; keep the signed bundle ID stable across rebuilds.
|
||||
- IPC hardening: socket mode `0600`, token, peer-UID checks, HMAC challenge/response, short TTL.
|
||||
275
docker-compose/ez-assistant/docs/platforms/macos-vm.md
Normal file
275
docker-compose/ez-assistant/docs/platforms/macos-vm.md
Normal file
@@ -0,0 +1,275 @@
|
||||
---
|
||||
summary: "Run Moltbot in a sandboxed macOS VM (local or hosted) when you need isolation or iMessage"
|
||||
read_when:
|
||||
- You want Moltbot isolated from your main macOS environment
|
||||
- You want iMessage integration (BlueBubbles) in a sandbox
|
||||
- You want a resettable macOS environment you can clone
|
||||
- You want to compare local vs hosted macOS VM options
|
||||
---
|
||||
|
||||
# Moltbot on macOS VMs (Sandboxing)
|
||||
|
||||
## Recommended default (most users)
|
||||
|
||||
- **Small Linux VPS** for an always-on Gateway and low cost. See [VPS hosting](/vps).
|
||||
- **Dedicated hardware** (Mac mini or Linux box) if you want full control and a **residential IP** for browser automation. Many sites block data center IPs, so local browsing often works better.
|
||||
- **Hybrid:** keep the Gateway on a cheap VPS, and connect your Mac as a **node** when you need browser/UI automation. See [Nodes](/nodes) and [Gateway remote](/gateway/remote).
|
||||
|
||||
Use a macOS VM when you specifically need macOS-only capabilities (iMessage/BlueBubbles) or want strict isolation from your daily Mac.
|
||||
|
||||
## macOS VM options
|
||||
|
||||
### Local VM on your Apple Silicon Mac (Lume)
|
||||
|
||||
Run Moltbot in a sandboxed macOS VM on your existing Apple Silicon Mac using [Lume](https://cua.ai/docs/lume).
|
||||
|
||||
This gives you:
|
||||
- Full macOS environment in isolation (your host stays clean)
|
||||
- iMessage support via BlueBubbles (impossible on Linux/Windows)
|
||||
- Instant reset by cloning VMs
|
||||
- No extra hardware or cloud costs
|
||||
|
||||
### Hosted Mac providers (cloud)
|
||||
|
||||
If you want macOS in the cloud, hosted Mac providers work too:
|
||||
- [MacStadium](https://www.macstadium.com/) (hosted Macs)
|
||||
- Other hosted Mac vendors also work; follow their VM + SSH docs
|
||||
|
||||
Once you have SSH access to a macOS VM, continue at step 6 below.
|
||||
|
||||
---
|
||||
|
||||
## Quick path (Lume, experienced users)
|
||||
|
||||
1. Install Lume
|
||||
2. `lume create moltbot --os macos --ipsw latest`
|
||||
3. Complete Setup Assistant, enable Remote Login (SSH)
|
||||
4. `lume run moltbot --no-display`
|
||||
5. SSH in, install Moltbot, configure channels
|
||||
6. Done
|
||||
|
||||
---
|
||||
|
||||
## What you need (Lume)
|
||||
|
||||
- Apple Silicon Mac (M1/M2/M3/M4)
|
||||
- macOS Sequoia or later on the host
|
||||
- ~60 GB free disk space per VM
|
||||
- ~20 minutes
|
||||
|
||||
---
|
||||
|
||||
## 1) Install Lume
|
||||
|
||||
```bash
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/trycua/cua/main/libs/lume/scripts/install.sh)"
|
||||
```
|
||||
|
||||
If `~/.local/bin` isn't in your PATH:
|
||||
|
||||
```bash
|
||||
echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.zshrc && source ~/.zshrc
|
||||
```
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
lume --version
|
||||
```
|
||||
|
||||
Docs: [Lume Installation](https://cua.ai/docs/lume/guide/getting-started/installation)
|
||||
|
||||
---
|
||||
|
||||
## 2) Create the macOS VM
|
||||
|
||||
```bash
|
||||
lume create moltbot --os macos --ipsw latest
|
||||
```
|
||||
|
||||
This downloads macOS and creates the VM. A VNC window opens automatically.
|
||||
|
||||
Note: The download can take a while depending on your connection.
|
||||
|
||||
---
|
||||
|
||||
## 3) Complete Setup Assistant
|
||||
|
||||
In the VNC window:
|
||||
1. Select language and region
|
||||
2. Skip Apple ID (or sign in if you want iMessage later)
|
||||
3. Create a user account (remember the username and password)
|
||||
4. Skip all optional features
|
||||
|
||||
After setup completes, enable SSH:
|
||||
1. Open System Settings → General → Sharing
|
||||
2. Enable "Remote Login"
|
||||
|
||||
---
|
||||
|
||||
## 4) Get the VM's IP address
|
||||
|
||||
```bash
|
||||
lume get moltbot
|
||||
```
|
||||
|
||||
Look for the IP address (usually `192.168.64.x`).
|
||||
|
||||
---
|
||||
|
||||
## 5) SSH into the VM
|
||||
|
||||
```bash
|
||||
ssh youruser@192.168.64.X
|
||||
```
|
||||
|
||||
Replace `youruser` with the account you created, and the IP with your VM's IP.
|
||||
|
||||
---
|
||||
|
||||
## 6) Install Moltbot
|
||||
|
||||
Inside the VM:
|
||||
|
||||
```bash
|
||||
npm install -g moltbot@latest
|
||||
moltbot onboard --install-daemon
|
||||
```
|
||||
|
||||
Follow the onboarding prompts to set up your model provider (Anthropic, OpenAI, etc.).
|
||||
|
||||
---
|
||||
|
||||
## 7) Configure channels
|
||||
|
||||
Edit the config file:
|
||||
|
||||
```bash
|
||||
nano ~/.clawdbot/moltbot.json
|
||||
```
|
||||
|
||||
Add your channels:
|
||||
|
||||
```json
|
||||
{
|
||||
"channels": {
|
||||
"whatsapp": {
|
||||
"dmPolicy": "allowlist",
|
||||
"allowFrom": ["+15551234567"]
|
||||
},
|
||||
"telegram": {
|
||||
"botToken": "YOUR_BOT_TOKEN"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then login to WhatsApp (scan QR):
|
||||
|
||||
```bash
|
||||
moltbot channels login
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8) Run the VM headlessly
|
||||
|
||||
Stop the VM and restart without display:
|
||||
|
||||
```bash
|
||||
lume stop moltbot
|
||||
lume run moltbot --no-display
|
||||
```
|
||||
|
||||
The VM runs in the background. Moltbot's daemon keeps the gateway running.
|
||||
|
||||
To check status:
|
||||
|
||||
```bash
|
||||
ssh youruser@192.168.64.X "moltbot status"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Bonus: iMessage integration
|
||||
|
||||
This is the killer feature of running on macOS. Use [BlueBubbles](https://bluebubbles.app) to add iMessage to Moltbot.
|
||||
|
||||
Inside the VM:
|
||||
|
||||
1. Download BlueBubbles from bluebubbles.app
|
||||
2. Sign in with your Apple ID
|
||||
3. Enable the Web API and set a password
|
||||
4. Point BlueBubbles webhooks at your gateway (example: `https://your-gateway-host:3000/bluebubbles-webhook?password=<password>`)
|
||||
|
||||
Add to your Moltbot config:
|
||||
|
||||
```json
|
||||
{
|
||||
"channels": {
|
||||
"bluebubbles": {
|
||||
"serverUrl": "http://localhost:1234",
|
||||
"password": "your-api-password",
|
||||
"webhookPath": "/bluebubbles-webhook"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Restart the gateway. Now your agent can send and receive iMessages.
|
||||
|
||||
Full setup details: [BlueBubbles channel](/channels/bluebubbles)
|
||||
|
||||
---
|
||||
|
||||
## Save a golden image
|
||||
|
||||
Before customizing further, snapshot your clean state:
|
||||
|
||||
```bash
|
||||
lume stop moltbot
|
||||
lume clone moltbot moltbot-golden
|
||||
```
|
||||
|
||||
Reset anytime:
|
||||
|
||||
```bash
|
||||
lume stop moltbot && lume delete moltbot
|
||||
lume clone moltbot-golden moltbot
|
||||
lume run moltbot --no-display
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Running 24/7
|
||||
|
||||
Keep the VM running by:
|
||||
- Keeping your Mac plugged in
|
||||
- Disabling sleep in System Settings → Energy Saver
|
||||
- Using `caffeinate` if needed
|
||||
|
||||
For true always-on, consider a dedicated Mac mini or a small VPS. See [VPS hosting](/vps).
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Solution |
|
||||
|---------|----------|
|
||||
| Can't SSH into VM | Check "Remote Login" is enabled in VM's System Settings |
|
||||
| VM IP not showing | Wait for VM to fully boot, run `lume get moltbot` again |
|
||||
| Lume command not found | Add `~/.local/bin` to your PATH |
|
||||
| WhatsApp QR not scanning | Ensure you're logged into the VM (not host) when running `moltbot channels login` |
|
||||
|
||||
---
|
||||
|
||||
## Related docs
|
||||
|
||||
- [VPS hosting](/vps)
|
||||
- [Nodes](/nodes)
|
||||
- [Gateway remote](/gateway/remote)
|
||||
- [BlueBubbles channel](/channels/bluebubbles)
|
||||
- [Lume Quickstart](https://cua.ai/docs/lume/guide/getting-started/quickstart)
|
||||
- [Lume CLI Reference](https://cua.ai/docs/lume/reference/cli-reference)
|
||||
- [Unattended VM Setup](https://cua.ai/docs/lume/guide/fundamentals/unattended-setup) (advanced)
|
||||
- [Docker Sandboxing](/install/docker) (alternative isolation approach)
|
||||
195
docker-compose/ez-assistant/docs/platforms/macos.md
Normal file
195
docker-compose/ez-assistant/docs/platforms/macos.md
Normal file
@@ -0,0 +1,195 @@
|
||||
---
|
||||
summary: "Moltbot macOS companion app (menu bar + gateway broker)"
|
||||
read_when:
|
||||
- Implementing macOS app features
|
||||
- Changing gateway lifecycle or node bridging on macOS
|
||||
---
|
||||
# Moltbot macOS Companion (menu bar + gateway broker)
|
||||
|
||||
The macOS app is the **menu‑bar companion** for Moltbot. It owns permissions,
|
||||
manages/attaches to the Gateway locally (launchd or manual), and exposes macOS
|
||||
capabilities to the agent as a node.
|
||||
|
||||
## What it does
|
||||
|
||||
- Shows native notifications and status in the menu bar.
|
||||
- Owns TCC prompts (Notifications, Accessibility, Screen Recording, Microphone,
|
||||
Speech Recognition, Automation/AppleScript).
|
||||
- Runs or connects to the Gateway (local or remote).
|
||||
- Exposes macOS‑only tools (Canvas, Camera, Screen Recording, `system.run`).
|
||||
- Starts the local node host service in **remote** mode (launchd), and stops it in **local** mode.
|
||||
- Optionally hosts **PeekabooBridge** for UI automation.
|
||||
- Installs the global CLI (`moltbot`) via npm/pnpm on request (bun not recommended for the Gateway runtime).
|
||||
|
||||
## Local vs remote mode
|
||||
|
||||
- **Local** (default): the app attaches to a running local Gateway if present;
|
||||
otherwise it enables the launchd service via `moltbot gateway install`.
|
||||
- **Remote**: the app connects to a Gateway over SSH/Tailscale and never starts
|
||||
a local process.
|
||||
The app starts the local **node host service** so the remote Gateway can reach this Mac.
|
||||
The app does not spawn the Gateway as a child process.
|
||||
|
||||
## Launchd control
|
||||
|
||||
The app manages a per‑user LaunchAgent labeled `bot.molt.gateway`
|
||||
(or `bot.molt.<profile>` when using `--profile`/`CLAWDBOT_PROFILE`; legacy `com.clawdbot.*` still unloads).
|
||||
|
||||
```bash
|
||||
launchctl kickstart -k gui/$UID/bot.molt.gateway
|
||||
launchctl bootout gui/$UID/bot.molt.gateway
|
||||
```
|
||||
|
||||
Replace the label with `bot.molt.<profile>` when running a named profile.
|
||||
|
||||
If the LaunchAgent isn’t installed, enable it from the app or run
|
||||
`moltbot gateway install`.
|
||||
|
||||
## Node capabilities (mac)
|
||||
|
||||
The macOS app presents itself as a node. Common commands:
|
||||
|
||||
- Canvas: `canvas.present`, `canvas.navigate`, `canvas.eval`, `canvas.snapshot`, `canvas.a2ui.*`
|
||||
- Camera: `camera.snap`, `camera.clip`
|
||||
- Screen: `screen.record`
|
||||
- System: `system.run`, `system.notify`
|
||||
|
||||
The node reports a `permissions` map so agents can decide what’s allowed.
|
||||
|
||||
Node service + app IPC:
|
||||
- When the headless node host service is running (remote mode), it connects to the Gateway WS as a node.
|
||||
- `system.run` executes in the macOS app (UI/TCC context) over a local Unix socket; prompts + output stay in-app.
|
||||
|
||||
Diagram (SCI):
|
||||
```
|
||||
Gateway -> Node Service (WS)
|
||||
| IPC (UDS + token + HMAC + TTL)
|
||||
v
|
||||
Mac App (UI + TCC + system.run)
|
||||
```
|
||||
|
||||
## Exec approvals (system.run)
|
||||
|
||||
`system.run` is controlled by **Exec approvals** in the macOS app (Settings → Exec approvals).
|
||||
Security + ask + allowlist are stored locally on the Mac in:
|
||||
|
||||
```
|
||||
~/.clawdbot/exec-approvals.json
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"defaults": {
|
||||
"security": "deny",
|
||||
"ask": "on-miss"
|
||||
},
|
||||
"agents": {
|
||||
"main": {
|
||||
"security": "allowlist",
|
||||
"ask": "on-miss",
|
||||
"allowlist": [
|
||||
{ "pattern": "/opt/homebrew/bin/rg" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
- `allowlist` entries are glob patterns for resolved binary paths.
|
||||
- Choosing “Always Allow” in the prompt adds that command to the allowlist.
|
||||
- `system.run` environment overrides are filtered (drops `PATH`, `DYLD_*`, `LD_*`, `NODE_OPTIONS`, `PYTHON*`, `PERL*`, `RUBYOPT`) and then merged with the app’s environment.
|
||||
|
||||
## Deep links
|
||||
|
||||
The app registers the `moltbot://` URL scheme for local actions.
|
||||
|
||||
### `moltbot://agent`
|
||||
|
||||
Triggers a Gateway `agent` request.
|
||||
|
||||
```bash
|
||||
open 'moltbot://agent?message=Hello%20from%20deep%20link'
|
||||
```
|
||||
|
||||
Query parameters:
|
||||
- `message` (required)
|
||||
- `sessionKey` (optional)
|
||||
- `thinking` (optional)
|
||||
- `deliver` / `to` / `channel` (optional)
|
||||
- `timeoutSeconds` (optional)
|
||||
- `key` (optional unattended mode key)
|
||||
|
||||
Safety:
|
||||
- Without `key`, the app prompts for confirmation.
|
||||
- With a valid `key`, the run is unattended (intended for personal automations).
|
||||
|
||||
## Onboarding flow (typical)
|
||||
|
||||
1) Install and launch **Moltbot.app**.
|
||||
2) Complete the permissions checklist (TCC prompts).
|
||||
3) Ensure **Local** mode is active and the Gateway is running.
|
||||
4) Install the CLI if you want terminal access.
|
||||
|
||||
## Build & dev workflow (native)
|
||||
|
||||
- `cd apps/macos && swift build`
|
||||
- `swift run Moltbot` (or Xcode)
|
||||
- Package app: `scripts/package-mac-app.sh`
|
||||
|
||||
## Debug gateway connectivity (macOS CLI)
|
||||
|
||||
Use the debug CLI to exercise the same Gateway WebSocket handshake and discovery
|
||||
logic that the macOS app uses, without launching the app.
|
||||
|
||||
```bash
|
||||
cd apps/macos
|
||||
swift run moltbot-mac connect --json
|
||||
swift run moltbot-mac discover --timeout 3000 --json
|
||||
```
|
||||
|
||||
Connect options:
|
||||
- `--url <ws://host:port>`: override config
|
||||
- `--mode <local|remote>`: resolve from config (default: config or local)
|
||||
- `--probe`: force a fresh health probe
|
||||
- `--timeout <ms>`: request timeout (default: `15000`)
|
||||
- `--json`: structured output for diffing
|
||||
|
||||
Discovery options:
|
||||
- `--include-local`: include gateways that would be filtered as “local”
|
||||
- `--timeout <ms>`: overall discovery window (default: `2000`)
|
||||
- `--json`: structured output for diffing
|
||||
|
||||
Tip: compare against `moltbot gateway discover --json` to see whether the
|
||||
macOS app’s discovery pipeline (NWBrowser + tailnet DNS‑SD fallback) differs from
|
||||
the Node CLI’s `dns-sd` based discovery.
|
||||
|
||||
## Remote connection plumbing (SSH tunnels)
|
||||
|
||||
When the macOS app runs in **Remote** mode, it opens an SSH tunnel so local UI
|
||||
components can talk to a remote Gateway as if it were on localhost.
|
||||
|
||||
### Control tunnel (Gateway WebSocket port)
|
||||
- **Purpose:** health checks, status, Web Chat, config, and other control-plane calls.
|
||||
- **Local port:** the Gateway port (default `18789`), always stable.
|
||||
- **Remote port:** the same Gateway port on the remote host.
|
||||
- **Behavior:** no random local port; the app reuses an existing healthy tunnel
|
||||
or restarts it if needed.
|
||||
- **SSH shape:** `ssh -N -L <local>:127.0.0.1:<remote>` with BatchMode +
|
||||
ExitOnForwardFailure + keepalive options.
|
||||
- **IP reporting:** the SSH tunnel uses loopback, so the gateway will see the node
|
||||
IP as `127.0.0.1`. Use **Direct (ws/wss)** transport if you want the real client
|
||||
IP to appear (see [macOS remote access](/platforms/mac/remote)).
|
||||
|
||||
For setup steps, see [macOS remote access](/platforms/mac/remote). For protocol
|
||||
details, see [Gateway protocol](/gateway/protocol).
|
||||
|
||||
## Related docs
|
||||
|
||||
- [Gateway runbook](/gateway)
|
||||
- [Gateway (macOS)](/platforms/mac/bundled-gateway)
|
||||
- [macOS permissions](/platforms/mac/permissions)
|
||||
- [Canvas](/platforms/mac/canvas)
|
||||
291
docker-compose/ez-assistant/docs/platforms/oracle.md
Normal file
291
docker-compose/ez-assistant/docs/platforms/oracle.md
Normal file
@@ -0,0 +1,291 @@
|
||||
---
|
||||
summary: "Moltbot on Oracle Cloud (Always Free ARM)"
|
||||
read_when:
|
||||
- Setting up Moltbot on Oracle Cloud
|
||||
- Looking for low-cost VPS hosting for Moltbot
|
||||
- Want 24/7 Moltbot on a small server
|
||||
---
|
||||
|
||||
# Moltbot on Oracle Cloud (OCI)
|
||||
|
||||
## Goal
|
||||
|
||||
Run a persistent Moltbot Gateway on Oracle Cloud's **Always Free** ARM tier.
|
||||
|
||||
Oracle’s free tier can be a great fit for Moltbot (especially if you already have an OCI account), but it comes with tradeoffs:
|
||||
|
||||
- ARM architecture (most things work, but some binaries may be x86-only)
|
||||
- Capacity and signup can be finicky
|
||||
|
||||
## Cost Comparison (2026)
|
||||
|
||||
| Provider | Plan | Specs | Price/mo | Notes |
|
||||
|----------|------|-------|----------|-------|
|
||||
| Oracle Cloud | Always Free ARM | up to 4 OCPU, 24GB RAM | $0 | ARM, limited capacity |
|
||||
| Hetzner | CX22 | 2 vCPU, 4GB RAM | ~ $4 | Cheapest paid option |
|
||||
| DigitalOcean | Basic | 1 vCPU, 1GB RAM | $6 | Easy UI, good docs |
|
||||
| Vultr | Cloud Compute | 1 vCPU, 1GB RAM | $6 | Many locations |
|
||||
| Linode | Nanode | 1 vCPU, 1GB RAM | $5 | Now part of Akamai |
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Oracle Cloud account ([signup](https://www.oracle.com/cloud/free/)) — see [community signup guide](https://gist.github.com/rssnyder/51e3cfedd730e7dd5f4a816143b25dbd) if you hit issues
|
||||
- Tailscale account (free at [tailscale.com](https://tailscale.com))
|
||||
- ~30 minutes
|
||||
|
||||
## 1) Create an OCI Instance
|
||||
|
||||
1. Log into [Oracle Cloud Console](https://cloud.oracle.com/)
|
||||
2. Navigate to **Compute → Instances → Create Instance**
|
||||
3. Configure:
|
||||
- **Name:** `moltbot`
|
||||
- **Image:** Ubuntu 24.04 (aarch64)
|
||||
- **Shape:** `VM.Standard.A1.Flex` (Ampere ARM)
|
||||
- **OCPUs:** 2 (or up to 4)
|
||||
- **Memory:** 12 GB (or up to 24 GB)
|
||||
- **Boot volume:** 50 GB (up to 200 GB free)
|
||||
- **SSH key:** Add your public key
|
||||
4. Click **Create**
|
||||
5. Note the public IP address
|
||||
|
||||
**Tip:** If instance creation fails with "Out of capacity", try a different availability domain or retry later. Free tier capacity is limited.
|
||||
|
||||
## 2) Connect and Update
|
||||
|
||||
```bash
|
||||
# Connect via public IP
|
||||
ssh ubuntu@YOUR_PUBLIC_IP
|
||||
|
||||
# Update system
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
sudo apt install -y build-essential
|
||||
```
|
||||
|
||||
**Note:** `build-essential` is required for ARM compilation of some dependencies.
|
||||
|
||||
## 3) Configure User and Hostname
|
||||
|
||||
```bash
|
||||
# Set hostname
|
||||
sudo hostnamectl set-hostname moltbot
|
||||
|
||||
# Set password for ubuntu user
|
||||
sudo passwd ubuntu
|
||||
|
||||
# Enable lingering (keeps user services running after logout)
|
||||
sudo loginctl enable-linger ubuntu
|
||||
```
|
||||
|
||||
## 4) Install Tailscale
|
||||
|
||||
```bash
|
||||
curl -fsSL https://tailscale.com/install.sh | sh
|
||||
sudo tailscale up --ssh --hostname=moltbot
|
||||
```
|
||||
|
||||
This enables Tailscale SSH, so you can connect via `ssh moltbot` from any device on your tailnet — no public IP needed.
|
||||
|
||||
Verify:
|
||||
```bash
|
||||
tailscale status
|
||||
```
|
||||
|
||||
**From now on, connect via Tailscale:** `ssh ubuntu@moltbot` (or use the Tailscale IP).
|
||||
|
||||
## 5) Install Moltbot
|
||||
|
||||
```bash
|
||||
curl -fsSL https://molt.bot/install.sh | bash
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
When prompted "How do you want to hatch your bot?", select **"Do this later"**.
|
||||
|
||||
> Note: If you hit ARM-native build issues, start with system packages (e.g. `sudo apt install -y build-essential`) before reaching for Homebrew.
|
||||
|
||||
## 6) Configure Gateway (loopback + token auth) and enable Tailscale Serve
|
||||
|
||||
Use token auth as the default. It’s predictable and avoids needing any “insecure auth” Control UI flags.
|
||||
|
||||
```bash
|
||||
# Keep the Gateway private on the VM
|
||||
moltbot config set gateway.bind loopback
|
||||
|
||||
# Require auth for the Gateway + Control UI
|
||||
moltbot config set gateway.auth.mode token
|
||||
moltbot doctor --generate-gateway-token
|
||||
|
||||
# Expose over Tailscale Serve (HTTPS + tailnet access)
|
||||
moltbot config set gateway.tailscale.mode serve
|
||||
moltbot config set gateway.trustedProxies '["127.0.0.1"]'
|
||||
|
||||
systemctl --user restart moltbot-gateway
|
||||
```
|
||||
|
||||
## 7) Verify
|
||||
|
||||
```bash
|
||||
# Check version
|
||||
moltbot --version
|
||||
|
||||
# Check daemon status
|
||||
systemctl --user status moltbot-gateway
|
||||
|
||||
# Check Tailscale Serve
|
||||
tailscale serve status
|
||||
|
||||
# Test local response
|
||||
curl http://localhost:18789
|
||||
```
|
||||
|
||||
## 8) Lock Down VCN Security
|
||||
|
||||
Now that everything is working, lock down the VCN to block all traffic except Tailscale. OCI's Virtual Cloud Network acts as a firewall at the network edge — traffic is blocked before it reaches your instance.
|
||||
|
||||
1. Go to **Networking → Virtual Cloud Networks** in the OCI Console
|
||||
2. Click your VCN → **Security Lists** → Default Security List
|
||||
3. **Remove** all ingress rules except:
|
||||
- `0.0.0.0/0 UDP 41641` (Tailscale)
|
||||
4. Keep default egress rules (allow all outbound)
|
||||
|
||||
This blocks SSH on port 22, HTTP, HTTPS, and everything else at the network edge. From now on, you can only connect via Tailscale.
|
||||
|
||||
---
|
||||
|
||||
## Access the Control UI
|
||||
|
||||
From any device on your Tailscale network:
|
||||
|
||||
```
|
||||
https://moltbot.<tailnet-name>.ts.net/
|
||||
```
|
||||
|
||||
Replace `<tailnet-name>` with your tailnet name (visible in `tailscale status`).
|
||||
|
||||
No SSH tunnel needed. Tailscale provides:
|
||||
- HTTPS encryption (automatic certs)
|
||||
- Authentication via Tailscale identity
|
||||
- Access from any device on your tailnet (laptop, phone, etc.)
|
||||
|
||||
---
|
||||
|
||||
## Security: VCN + Tailscale (recommended baseline)
|
||||
|
||||
With the VCN locked down (only UDP 41641 open) and the Gateway bound to loopback, you get strong defense-in-depth: public traffic is blocked at the network edge, and admin access happens over your tailnet.
|
||||
|
||||
This setup often removes the *need* for extra host-based firewall rules purely to stop Internet-wide SSH brute force — but you should still keep the OS updated, run `moltbot security audit`, and verify you aren’t accidentally listening on public interfaces.
|
||||
|
||||
### What's Already Protected
|
||||
|
||||
| Traditional Step | Needed? | Why |
|
||||
|------------------|---------|-----|
|
||||
| UFW firewall | No | VCN blocks before traffic reaches instance |
|
||||
| fail2ban | No | No brute force if port 22 blocked at VCN |
|
||||
| sshd hardening | No | Tailscale SSH doesn't use sshd |
|
||||
| Disable root login | No | Tailscale uses Tailscale identity, not system users |
|
||||
| SSH key-only auth | No | Tailscale authenticates via your tailnet |
|
||||
| IPv6 hardening | Usually not | Depends on your VCN/subnet settings; verify what’s actually assigned/exposed |
|
||||
|
||||
### Still Recommended
|
||||
|
||||
- **Credential permissions:** `chmod 700 ~/.clawdbot`
|
||||
- **Security audit:** `moltbot security audit`
|
||||
- **System updates:** `sudo apt update && sudo apt upgrade` regularly
|
||||
- **Monitor Tailscale:** Review devices in [Tailscale admin console](https://login.tailscale.com/admin)
|
||||
|
||||
### Verify Security Posture
|
||||
|
||||
```bash
|
||||
# Confirm no public ports listening
|
||||
sudo ss -tlnp | grep -v '127.0.0.1\|::1'
|
||||
|
||||
# Verify Tailscale SSH is active
|
||||
tailscale status | grep -q 'offers: ssh' && echo "Tailscale SSH active"
|
||||
|
||||
# Optional: disable sshd entirely
|
||||
sudo systemctl disable --now ssh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fallback: SSH Tunnel
|
||||
|
||||
If Tailscale Serve isn't working, use an SSH tunnel:
|
||||
|
||||
```bash
|
||||
# From your local machine (via Tailscale)
|
||||
ssh -L 18789:127.0.0.1:18789 ubuntu@moltbot
|
||||
```
|
||||
|
||||
Then open `http://localhost:18789`.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Instance creation fails ("Out of capacity")
|
||||
Free tier ARM instances are popular. Try:
|
||||
- Different availability domain
|
||||
- Retry during off-peak hours (early morning)
|
||||
- Use the "Always Free" filter when selecting shape
|
||||
|
||||
### Tailscale won't connect
|
||||
```bash
|
||||
# Check status
|
||||
sudo tailscale status
|
||||
|
||||
# Re-authenticate
|
||||
sudo tailscale up --ssh --hostname=moltbot --reset
|
||||
```
|
||||
|
||||
### Gateway won't start
|
||||
```bash
|
||||
moltbot gateway status
|
||||
moltbot doctor --non-interactive
|
||||
journalctl --user -u moltbot-gateway -n 50
|
||||
```
|
||||
|
||||
### Can't reach Control UI
|
||||
```bash
|
||||
# Verify Tailscale Serve is running
|
||||
tailscale serve status
|
||||
|
||||
# Check gateway is listening
|
||||
curl http://localhost:18789
|
||||
|
||||
# Restart if needed
|
||||
systemctl --user restart moltbot-gateway
|
||||
```
|
||||
|
||||
### ARM binary issues
|
||||
Some tools may not have ARM builds. Check:
|
||||
```bash
|
||||
uname -m # Should show aarch64
|
||||
```
|
||||
|
||||
Most npm packages work fine. For binaries, look for `linux-arm64` or `aarch64` releases.
|
||||
|
||||
---
|
||||
|
||||
## Persistence
|
||||
|
||||
All state lives in:
|
||||
- `~/.clawdbot/` — config, credentials, session data
|
||||
- `~/clawd/` — workspace (SOUL.md, memory, artifacts)
|
||||
|
||||
Back up periodically:
|
||||
```bash
|
||||
tar -czvf moltbot-backup.tar.gz ~/.clawdbot ~/clawd
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Gateway remote access](/gateway/remote) — other remote access patterns
|
||||
- [Tailscale integration](/gateway/tailscale) — full Tailscale docs
|
||||
- [Gateway configuration](/gateway/configuration) — all config options
|
||||
- [DigitalOcean guide](/platforms/digitalocean) — if you want paid + easier signup
|
||||
- [Hetzner guide](/platforms/hetzner) — Docker-based alternative
|
||||
354
docker-compose/ez-assistant/docs/platforms/raspberry-pi.md
Normal file
354
docker-compose/ez-assistant/docs/platforms/raspberry-pi.md
Normal file
@@ -0,0 +1,354 @@
|
||||
---
|
||||
summary: "Moltbot on Raspberry Pi (budget self-hosted setup)"
|
||||
read_when:
|
||||
- Setting up Moltbot on a Raspberry Pi
|
||||
- Running Moltbot on ARM devices
|
||||
- Building a cheap always-on personal AI
|
||||
---
|
||||
|
||||
# Moltbot on Raspberry Pi
|
||||
|
||||
## Goal
|
||||
|
||||
Run a persistent, always-on Moltbot Gateway on a Raspberry Pi for **~$35-80** one-time cost (no monthly fees).
|
||||
|
||||
Perfect for:
|
||||
- 24/7 personal AI assistant
|
||||
- Home automation hub
|
||||
- Low-power, always-available Telegram/WhatsApp bot
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
| Pi Model | RAM | Works? | Notes |
|
||||
|----------|-----|--------|-------|
|
||||
| **Pi 5** | 4GB/8GB | ✅ Best | Fastest, recommended |
|
||||
| **Pi 4** | 4GB | ✅ Good | Sweet spot for most users |
|
||||
| **Pi 4** | 2GB | ✅ OK | Works, add swap |
|
||||
| **Pi 4** | 1GB | ⚠️ Tight | Possible with swap, minimal config |
|
||||
| **Pi 3B+** | 1GB | ⚠️ Slow | Works but sluggish |
|
||||
| **Pi Zero 2 W** | 512MB | ❌ | Not recommended |
|
||||
|
||||
**Minimum specs:** 1GB RAM, 1 core, 500MB disk
|
||||
**Recommended:** 2GB+ RAM, 64-bit OS, 16GB+ SD card (or USB SSD)
|
||||
|
||||
## What You'll Need
|
||||
|
||||
- Raspberry Pi 4 or 5 (2GB+ recommended)
|
||||
- MicroSD card (16GB+) or USB SSD (better performance)
|
||||
- Power supply (official Pi PSU recommended)
|
||||
- Network connection (Ethernet or WiFi)
|
||||
- ~30 minutes
|
||||
|
||||
## 1) Flash the OS
|
||||
|
||||
Use **Raspberry Pi OS Lite (64-bit)** — no desktop needed for a headless server.
|
||||
|
||||
1. Download [Raspberry Pi Imager](https://www.raspberrypi.com/software/)
|
||||
2. Choose OS: **Raspberry Pi OS Lite (64-bit)**
|
||||
3. Click the gear icon (⚙️) to pre-configure:
|
||||
- Set hostname: `gateway-host`
|
||||
- Enable SSH
|
||||
- Set username/password
|
||||
- Configure WiFi (if not using Ethernet)
|
||||
4. Flash to your SD card / USB drive
|
||||
5. Insert and boot the Pi
|
||||
|
||||
## 2) Connect via SSH
|
||||
|
||||
```bash
|
||||
ssh user@gateway-host
|
||||
# or use the IP address
|
||||
ssh user@192.168.x.x
|
||||
```
|
||||
|
||||
## 3) System Setup
|
||||
|
||||
```bash
|
||||
# Update system
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# Install essential packages
|
||||
sudo apt install -y git curl build-essential
|
||||
|
||||
# Set timezone (important for cron/reminders)
|
||||
sudo timedatectl set-timezone America/Chicago # Change to your timezone
|
||||
```
|
||||
|
||||
## 4) Install Node.js 22 (ARM64)
|
||||
|
||||
```bash
|
||||
# Install Node.js via NodeSource
|
||||
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
|
||||
sudo apt install -y nodejs
|
||||
|
||||
# Verify
|
||||
node --version # Should show v22.x.x
|
||||
npm --version
|
||||
```
|
||||
|
||||
## 5) Add Swap (Important for 2GB or less)
|
||||
|
||||
Swap prevents out-of-memory crashes:
|
||||
|
||||
```bash
|
||||
# Create 2GB swap file
|
||||
sudo fallocate -l 2G /swapfile
|
||||
sudo chmod 600 /swapfile
|
||||
sudo mkswap /swapfile
|
||||
sudo swapon /swapfile
|
||||
|
||||
# Make permanent
|
||||
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
|
||||
|
||||
# Optimize for low RAM (reduce swappiness)
|
||||
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
|
||||
sudo sysctl -p
|
||||
```
|
||||
|
||||
## 6) Install Moltbot
|
||||
|
||||
### Option A: Standard Install (Recommended)
|
||||
|
||||
```bash
|
||||
curl -fsSL https://molt.bot/install.sh | bash
|
||||
```
|
||||
|
||||
### Option B: Hackable Install (For tinkering)
|
||||
|
||||
```bash
|
||||
git clone https://github.com/moltbot/moltbot.git
|
||||
cd moltbot
|
||||
npm install
|
||||
npm run build
|
||||
npm link
|
||||
```
|
||||
|
||||
The hackable install gives you direct access to logs and code — useful for debugging ARM-specific issues.
|
||||
|
||||
## 7) Run Onboarding
|
||||
|
||||
```bash
|
||||
moltbot onboard --install-daemon
|
||||
```
|
||||
|
||||
Follow the wizard:
|
||||
1. **Gateway mode:** Local
|
||||
2. **Auth:** API keys recommended (OAuth can be finicky on headless Pi)
|
||||
3. **Channels:** Telegram is easiest to start with
|
||||
4. **Daemon:** Yes (systemd)
|
||||
|
||||
## 8) Verify Installation
|
||||
|
||||
```bash
|
||||
# Check status
|
||||
moltbot status
|
||||
|
||||
# Check service
|
||||
sudo systemctl status moltbot
|
||||
|
||||
# View logs
|
||||
journalctl -u moltbot -f
|
||||
```
|
||||
|
||||
## 9) Access the Dashboard
|
||||
|
||||
Since the Pi is headless, use an SSH tunnel:
|
||||
|
||||
```bash
|
||||
# From your laptop/desktop
|
||||
ssh -L 18789:localhost:18789 user@gateway-host
|
||||
|
||||
# Then open in browser
|
||||
open http://localhost:18789
|
||||
```
|
||||
|
||||
Or use Tailscale for always-on access:
|
||||
|
||||
```bash
|
||||
# On the Pi
|
||||
curl -fsSL https://tailscale.com/install.sh | sh
|
||||
sudo tailscale up
|
||||
|
||||
# Update config
|
||||
moltbot config set gateway.bind tailnet
|
||||
sudo systemctl restart moltbot
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Optimizations
|
||||
|
||||
### Use a USB SSD (Huge Improvement)
|
||||
|
||||
SD cards are slow and wear out. A USB SSD dramatically improves performance:
|
||||
|
||||
```bash
|
||||
# Check if booting from USB
|
||||
lsblk
|
||||
```
|
||||
|
||||
See [Pi USB boot guide](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#usb-mass-storage-boot) for setup.
|
||||
|
||||
### Reduce Memory Usage
|
||||
|
||||
```bash
|
||||
# Disable GPU memory allocation (headless)
|
||||
echo 'gpu_mem=16' | sudo tee -a /boot/config.txt
|
||||
|
||||
# Disable Bluetooth if not needed
|
||||
sudo systemctl disable bluetooth
|
||||
```
|
||||
|
||||
### Monitor Resources
|
||||
|
||||
```bash
|
||||
# Check memory
|
||||
free -h
|
||||
|
||||
# Check CPU temperature
|
||||
vcgencmd measure_temp
|
||||
|
||||
# Live monitoring
|
||||
htop
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ARM-Specific Notes
|
||||
|
||||
### Binary Compatibility
|
||||
|
||||
Most Moltbot features work on ARM64, but some external binaries may need ARM builds:
|
||||
|
||||
| Tool | ARM64 Status | Notes |
|
||||
|------|--------------|-------|
|
||||
| Node.js | ✅ | Works great |
|
||||
| WhatsApp (Baileys) | ✅ | Pure JS, no issues |
|
||||
| Telegram | ✅ | Pure JS, no issues |
|
||||
| gog (Gmail CLI) | ⚠️ | Check for ARM release |
|
||||
| Chromium (browser) | ✅ | `sudo apt install chromium-browser` |
|
||||
|
||||
If a skill fails, check if its binary has an ARM build. Many Go/Rust tools do; some don't.
|
||||
|
||||
### 32-bit vs 64-bit
|
||||
|
||||
**Always use 64-bit OS.** Node.js and many modern tools require it. Check with:
|
||||
|
||||
```bash
|
||||
uname -m
|
||||
# Should show: aarch64 (64-bit) not armv7l (32-bit)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Recommended Model Setup
|
||||
|
||||
Since the Pi is just the Gateway (models run in the cloud), use API-based models:
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"model": {
|
||||
"primary": "anthropic/claude-sonnet-4-20250514",
|
||||
"fallbacks": ["openai/gpt-4o-mini"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Don't try to run local LLMs on a Pi** — even small models are too slow. Let Claude/GPT do the heavy lifting.
|
||||
|
||||
---
|
||||
|
||||
## Auto-Start on Boot
|
||||
|
||||
The onboarding wizard sets this up, but to verify:
|
||||
|
||||
```bash
|
||||
# Check service is enabled
|
||||
sudo systemctl is-enabled moltbot
|
||||
|
||||
# Enable if not
|
||||
sudo systemctl enable moltbot
|
||||
|
||||
# Start on boot
|
||||
sudo systemctl start moltbot
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Out of Memory (OOM)
|
||||
|
||||
```bash
|
||||
# Check memory
|
||||
free -h
|
||||
|
||||
# Add more swap (see Step 5)
|
||||
# Or reduce services running on the Pi
|
||||
```
|
||||
|
||||
### Slow Performance
|
||||
|
||||
- Use USB SSD instead of SD card
|
||||
- Disable unused services: `sudo systemctl disable cups bluetooth avahi-daemon`
|
||||
- Check CPU throttling: `vcgencmd get_throttled` (should return `0x0`)
|
||||
|
||||
### Service Won't Start
|
||||
|
||||
```bash
|
||||
# Check logs
|
||||
journalctl -u moltbot --no-pager -n 100
|
||||
|
||||
# Common fix: rebuild
|
||||
cd ~/moltbot # if using hackable install
|
||||
npm run build
|
||||
sudo systemctl restart moltbot
|
||||
```
|
||||
|
||||
### ARM Binary Issues
|
||||
|
||||
If a skill fails with "exec format error":
|
||||
1. Check if the binary has an ARM64 build
|
||||
2. Try building from source
|
||||
3. Or use a Docker container with ARM support
|
||||
|
||||
### WiFi Drops
|
||||
|
||||
For headless Pis on WiFi:
|
||||
|
||||
```bash
|
||||
# Disable WiFi power management
|
||||
sudo iwconfig wlan0 power off
|
||||
|
||||
# Make permanent
|
||||
echo 'wireless-power off' | sudo tee -a /etc/network/interfaces
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cost Comparison
|
||||
|
||||
| Setup | One-Time Cost | Monthly Cost | Notes |
|
||||
|-------|---------------|--------------|-------|
|
||||
| **Pi 4 (2GB)** | ~$45 | $0 | + power (~$5/yr) |
|
||||
| **Pi 4 (4GB)** | ~$55 | $0 | Recommended |
|
||||
| **Pi 5 (4GB)** | ~$60 | $0 | Best performance |
|
||||
| **Pi 5 (8GB)** | ~$80 | $0 | Overkill but future-proof |
|
||||
| DigitalOcean | $0 | $6/mo | $72/year |
|
||||
| Hetzner | $0 | €3.79/mo | ~$50/year |
|
||||
|
||||
**Break-even:** A Pi pays for itself in ~6-12 months vs cloud VPS.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Linux guide](/platforms/linux) — general Linux setup
|
||||
- [DigitalOcean guide](/platforms/digitalocean) — cloud alternative
|
||||
- [Hetzner guide](/platforms/hetzner) — Docker setup
|
||||
- [Tailscale](/gateway/tailscale) — remote access
|
||||
- [Nodes](/nodes) — pair your laptop/phone with the Pi gateway
|
||||
153
docker-compose/ez-assistant/docs/platforms/windows.md
Normal file
153
docker-compose/ez-assistant/docs/platforms/windows.md
Normal file
@@ -0,0 +1,153 @@
|
||||
---
|
||||
summary: "Windows (WSL2) support + companion app status"
|
||||
read_when:
|
||||
- Installing Moltbot on Windows
|
||||
- Looking for Windows companion app status
|
||||
---
|
||||
# Windows (WSL2)
|
||||
|
||||
Moltbot on Windows is recommended **via WSL2** (Ubuntu recommended). The
|
||||
CLI + Gateway run inside Linux, which keeps the runtime consistent and makes
|
||||
tooling far more compatible (Node/Bun/pnpm, Linux binaries, skills). Native
|
||||
Windows installs are untested and more problematic.
|
||||
|
||||
Native Windows companion apps are planned.
|
||||
|
||||
## Install (WSL2)
|
||||
- [Getting Started](/start/getting-started) (use inside WSL)
|
||||
- [Install & updates](/install/updating)
|
||||
- Official WSL2 guide (Microsoft): https://learn.microsoft.com/windows/wsl/install
|
||||
|
||||
## Gateway
|
||||
- [Gateway runbook](/gateway)
|
||||
- [Configuration](/gateway/configuration)
|
||||
|
||||
## Gateway service install (CLI)
|
||||
|
||||
Inside WSL2:
|
||||
|
||||
```
|
||||
moltbot onboard --install-daemon
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```
|
||||
moltbot gateway install
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```
|
||||
moltbot configure
|
||||
```
|
||||
|
||||
Select **Gateway service** when prompted.
|
||||
|
||||
Repair/migrate:
|
||||
|
||||
```
|
||||
moltbot doctor
|
||||
```
|
||||
|
||||
## Advanced: expose WSL services over LAN (portproxy)
|
||||
|
||||
WSL has its own virtual network. If another machine needs to reach a service
|
||||
running **inside WSL** (SSH, a local TTS server, or the Gateway), you must
|
||||
forward a Windows port to the current WSL IP. The WSL IP changes after restarts,
|
||||
so you may need to refresh the forwarding rule.
|
||||
|
||||
Example (PowerShell **as Administrator**):
|
||||
|
||||
```powershell
|
||||
$Distro = "Ubuntu-24.04"
|
||||
$ListenPort = 2222
|
||||
$TargetPort = 22
|
||||
|
||||
$WslIp = (wsl -d $Distro -- hostname -I).Trim().Split(" ")[0]
|
||||
if (-not $WslIp) { throw "WSL IP not found." }
|
||||
|
||||
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=$ListenPort `
|
||||
connectaddress=$WslIp connectport=$TargetPort
|
||||
```
|
||||
|
||||
Allow the port through Windows Firewall (one-time):
|
||||
|
||||
```powershell
|
||||
New-NetFirewallRule -DisplayName "WSL SSH $ListenPort" -Direction Inbound `
|
||||
-Protocol TCP -LocalPort $ListenPort -Action Allow
|
||||
```
|
||||
|
||||
Refresh the portproxy after WSL restarts:
|
||||
|
||||
```powershell
|
||||
netsh interface portproxy delete v4tov4 listenport=$ListenPort listenaddress=0.0.0.0 | Out-Null
|
||||
netsh interface portproxy add v4tov4 listenport=$ListenPort listenaddress=0.0.0.0 `
|
||||
connectaddress=$WslIp connectport=$TargetPort | Out-Null
|
||||
```
|
||||
|
||||
Notes:
|
||||
- SSH from another machine targets the **Windows host IP** (example: `ssh user@windows-host -p 2222`).
|
||||
- Remote nodes must point at a **reachable** Gateway URL (not `127.0.0.1`); use
|
||||
`moltbot status --all` to confirm.
|
||||
- Use `listenaddress=0.0.0.0` for LAN access; `127.0.0.1` keeps it local only.
|
||||
- If you want this automatic, register a Scheduled Task to run the refresh
|
||||
step at login.
|
||||
|
||||
## Step-by-step WSL2 install
|
||||
|
||||
### 1) Install WSL2 + Ubuntu
|
||||
|
||||
Open PowerShell (Admin):
|
||||
|
||||
```powershell
|
||||
wsl --install
|
||||
# Or pick a distro explicitly:
|
||||
wsl --list --online
|
||||
wsl --install -d Ubuntu-24.04
|
||||
```
|
||||
|
||||
Reboot if Windows asks.
|
||||
|
||||
### 2) Enable systemd (required for gateway install)
|
||||
|
||||
In your WSL terminal:
|
||||
|
||||
```bash
|
||||
sudo tee /etc/wsl.conf >/dev/null <<'EOF'
|
||||
[boot]
|
||||
systemd=true
|
||||
EOF
|
||||
```
|
||||
|
||||
Then from PowerShell:
|
||||
|
||||
```powershell
|
||||
wsl --shutdown
|
||||
```
|
||||
|
||||
Re-open Ubuntu, then verify:
|
||||
|
||||
```bash
|
||||
systemctl --user status
|
||||
```
|
||||
|
||||
### 3) Install Moltbot (inside WSL)
|
||||
|
||||
Follow the Linux Getting Started flow inside WSL:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/moltbot/moltbot.git
|
||||
cd moltbot
|
||||
pnpm install
|
||||
pnpm ui:build # auto-installs UI deps on first run
|
||||
pnpm build
|
||||
moltbot onboard
|
||||
```
|
||||
|
||||
Full guide: [Getting Started](/start/getting-started)
|
||||
|
||||
## Windows companion app
|
||||
|
||||
We do not have a Windows companion app yet. Contributions are welcome if you want
|
||||
contributions to make it happen.
|
||||
Reference in New Issue
Block a user