A secure, WASM-sandboxed AI agent runtime written in Rust.
- Secure agent runtime -- AI agents run behind a WASM plugin sandbox. Plugins cannot access the host filesystem, network, or memory unless explicitly granted capabilities.
- Multi-channel messaging gateway -- WhatsApp, Telegram, Discord, and other messaging channels are loaded as WASM plugins. Adding a channel means shipping a
.wasmfile, not modifying the host binary. - Multi-provider LLM support -- Anthropic, OpenAI, Gemini, and Ollama (planned). Streaming responses with tool-use loops: send messages, get response, execute tool via sandbox, feed result back, repeat.
- Single binary, runs anywhere -- One static binary (~15 MB release build with LTO + strip). No interpreters, no node_modules, no container required.
OpenClaw is a proven, production-grade agent runtime written in TypeScript. exoclaw takes the same architecture and rebuilds it with different tradeoffs:
| OpenClaw | exoclaw | |
|---|---|---|
| Plugin isolation | Process-level (trust boundary is npm) | WASM sandbox (plugins cannot crash host or touch the filesystem) |
| Concurrency | Single-threaded event loop | Tokio tasks (100K+ concurrent sessions) |
| Codebase | ~50K LOC TypeScript | ~500 LOC Rust (target: ~3K) |
| Distribution | npm install + Node.js 22 | Single static binary |
NanoClaw is a lightweight macOS-native agent built on Apple Containers. exoclaw targets a different niche:
| NanoClaw | exoclaw | |
|---|---|---|
| Platform | macOS only (Apple Container sandbox) | Cross-platform (Linux, macOS, Windows) |
| Sandbox | Apple Container (macOS-specific) | WASM (portable) |
| Channels | WhatsApp only | Multi-channel via plugins |
"Exo" as in exoskeleton -- the hard outer shell that protects what's inside. That is what this runtime does for AI agents: provides a rigid, sandboxed boundary between untrusted plugin code and the host system.
graph LR
C1[WebSocket Client] --> GW[axum Gateway :7200]
C2[CLI] --> GW
GW --> AUTH[Auth<br/>constant-time token verify]
AUTH --> RPC[JSON-RPC Protocol]
RPC --> SR[Session Router<br/>peer > guild > team > account > channel]
SR --> AR[Agent Runner<br/>Anthropic / OpenAI streaming]
SR --> PH[WASM Plugin Host<br/>Extism sandbox]
AR -->|tool calls| PH
PH -->|tool results| AR
SR --> BUS[NATS Message Bus<br/>exoclaw.channel.account.peer]
SR --> SS[Session Store<br/>in-memory / SurrealDB planned]
Request flow:
- Client connects via WebSocket, authenticates with a token (constant-time comparison).
- Sends JSON-RPC messages (
chat.send,plugin.list,status,ping). - Session router resolves the target agent using hierarchical binding priority: peer > guild > team > account > channel > default.
- Agent runner streams the LLM response (SSE). Tool-use results are executed in the WASM sandbox and fed back into the conversation loop.
- Messages are published to the NATS bus for cross-component routing. If NATS is unavailable, the runtime falls back to local-only in-process routing.
# Clone and build
git clone https://github.com/exoclaw/exoclaw.git
cd exoclaw
cargo build --release
# First-time setup (secure prompt for provider + API key)
cargo run -- onboard
# Start the gateway (loopback, no auth required)
cargo run -- gateway
# Start on a specific port with auth
cargo run -- gateway --port 8080 --bind 0.0.0.0 --token my-secret
# Check status
cargo run -- status
# Load a WASM plugin
cargo run -- plugin load ./plugins/telegram.wasmonboard stores the API key in ~/.exoclaw/credentials/{provider}.key with file mode 600. API key resolution order:
ANTHROPIC_API_KEY/OPENAI_API_KEYenvironment variable (highest priority)- Credential file at
~/.exoclaw/credentials/{provider}.key api_keyfield in config file (not recommended)
The gateway binds to 127.0.0.1:7200 by default. When binding to a non-loopback address, an auth token is required (via --token or EXOCLAW_TOKEN env var).
See TESTING.md for the full red/green workflow and CI layout.
Quick commands:
./scripts/test-rust.sh # backend + coverage gate
./scripts/test-wasm-ui.sh # wasm-bindgen-test via wasm-pack
./scripts/test-e2e.sh # Playwright browser flows
./scripts/test-all.sh # full stackEarly development. Not production ready.
- Gateway server with WebSocket transport and health endpoint
- JSON-RPC protocol with
ping,status,chat.send,plugin.listmethods - Constant-time token authentication (required for non-loopback binds)
- WASM plugin host -- load, validate, and call plugin functions via Extism
- Hierarchical session router (peer/guild/team/account/channel bindings)
- Agent runner with streaming SSE for Anthropic and OpenAI APIs
- Tool-use loop with WASM sandbox dispatch and streamed
tool_use/tool_resultevents - Config loading from TOML + env with zero-config defaults
- Token metering and budget enforcement (session/daily/monthly)
- Memory engine (soul + semantic + episodic) integrated in message context assembly
- Webhook channel adapter pipeline (
POST /webhook/{channel}) with host-side proxy allowlists - NATS message bus with graceful fallback to local-only mode
- In-memory session store with conversation history
- CLI with
gateway,plugin, andstatussubcommands - Unit/integration test suites for auth/router/metering/memory/sandbox/channel flows
- Gemini and Ollama provider support
- SurrealDB-backed persistent session store
- NATS JetStream for message replay and durability
- Production channel plugins (Telegram/Discord/WhatsApp)
- Plugin SDK and guest-side API
- TLS termination
- Metrics and observability (OpenTelemetry)
- Multi-agent orchestration
- Performance benchmarks and production hardening
| Component | Crate | Role |
|---|---|---|
| Async runtime | tokio |
Task scheduling, I/O, timers |
| HTTP / WebSocket | axum |
Gateway server, WebSocket upgrade |
| WASM plugins | extism |
Sandboxed plugin host (Wasmtime-backed) |
| Message bus | async-nats |
Inter-component routing, pub/sub |
| Storage | surrealdb (planned) |
Session persistence, agent config |
| Wire format | rmp-serde |
MessagePack serialization |
| HTTP client | reqwest |
LLM API calls (streaming SSE) |
| CLI | clap |
Command parsing, subcommands |
| Logging | tracing |
Structured, filterable logging |
MIT OR Apache-2.0