openclaw-rs vs TypeScript OpenClaw
Same project, same primitives, same plugin contract — different runtime. When to pick the Rust core vs when to stay on the original TypeScript implementation.
The original TypeScript OpenClaw is a real, well-designed framework with active maintenance. openclaw-rs is not a replacement — it’s a sibling runtime built around the same primitives in a different language.
What’s identical
- Config —
~/.openclaw/openclaw.jsonJSON5 schema is the same. - Skills — Markdown bundles with YAML frontmatter, same loader semantics.
- Plugin contract — 8 lifecycle hooks, same names, same payload shapes.
- Event format — append-only log with the same
SessionEventKindvariants on disk. - Workspace —
~/.openclaw/layout: skills, plugins, credentials, events.
What’s different
| Surface | TypeScript OpenClaw | openclaw-rs |
|---|---|---|
| Runtime | Node.js | Statically-linked Rust binary |
| Memory model | Garbage collected | Ownership + RAII |
| Type safety | TypeScript at compile, JS at runtime | Rust at compile, exhaustive at runtime |
| Sandboxing | Process-level | bwrap / sandbox-exec / Job Objects (per OS) |
| Credential store | OS keychain or env vars | AES-256-GCM + Argon2id, file-backed |
| Gateway | Express / Fastify | axum (tower middleware, WebSocket native) |
| Dashboard deployment | Separate web app | Embedded in the gateway binary |
| Cold start | Seconds (V8 + module load) | Sub-second |
| Binary deploy size | ~100 MB (Node + deps) | ~15 MB target |
The plugin bridge
The key compatibility move: openclaw-plugins runs unmodified TypeScript plugins.
Each plugin is a Node subprocess. The runtime talks to it over nng (a small embedded message-passing transport) using JSON-RPC. The 8 lifecycle hooks (BeforeMessage, AfterMessage, BeforeToolCall, AfterToolCall, SessionStart, SessionEnd, AgentResponse, Error) dispatch as JSON-RPC calls. The plugin’s existing code doesn’t change.
The cost is one process per plugin. The benefit is zero plugin rewrites.
Compatibility gaps
Honest list of what TypeScript OpenClaw has that openclaw-rs doesn’t yet:
- Google Gemini provider — planned, see
docs/ROADMAP.md. - Ollama provider — planned.
- Discord / Slack / Signal / Matrix / WhatsApp channels — planned. Telegram is the only shipped Rust adapter.
- WASM plugin runtime — under evaluation (wasmtime vs wasmer).
If your TypeScript deployment leans on any of these, you have three options:
- Wait for the Rust implementation to ship.
- Keep TS for those specific concerns and run a hybrid deployment (Rust gateway + TS channel adapter, talking to the same workspace).
- Contribute the missing piece — the trait surface is stable and PRs are welcome.
When this is genuinely a wash
For teams with:
- A Node-only production stack already.
- A small set of trusted plugins they wrote themselves.
- No memory or cold-start pain.
- No security requirement that motivates sandboxing at the OS level.
…the Rust rewrite is nice to have, not load-bearing. Stay on TS and don’t fix what isn’t broken.
When this is decisive
For teams that:
- Run agents in environments where a Node deployment is awkward (locked-down hosts, constrained images, regulated CI).
- Need defence-in-depth at the runtime level.
- Are watching tail-latency or memory pressure under sustained load.
- Want a single-binary deploy story.
…the runtime properties are the reason to switch. Compatibility is what makes the switch cheap.
The honest pitch
We use both. The TypeScript version is faster to prototype in, and it pioneered the architecture we love. The Rust version is what we trust under sustained production load.
If you have a working TS OpenClaw deployment and no specific reason to move, stay. If you do have a reason — performance, deployment, security — the migration path is short.
- You want a single statically-linked binary instead of a Node.js deployment.
- You care about predictable memory and sub-millisecond message routing.
- You ship production agent infrastructure and want defence-in-depth security at the runtime level.
- You operate on hosts where running Node is awkward (constrained environments, regulated images, IoT-adjacent boxes).
- You want compile-time guarantees that errors don't degrade into runtime crashes on user input.
- You depend on Google Gemini or Ollama today — those providers are still on the openclaw-rs roadmap.
- You need Discord, Slack, Signal, Matrix, or WhatsApp channels today (Telegram is the only shipped Rust adapter).
- You write plugins natively in TypeScript and don't want them running in a subprocess.
- You're prototyping and value the JS REPL/dev velocity over runtime properties.
FAQ
- Are they really interchangeable?
- Configs (~/.openclaw/openclaw.json), skills (Markdown + YAML), and the plugin contract are identical. Workspace layouts are identical. The runtime is what differs.
- Can I migrate gradually?
- Yes. Run both gateways side-by-side on different ports during the migration. The event format on disk is wire-compatible.
- Will my TypeScript plugins keep working?
- Yes — the openclaw-plugins crate ships an nng IPC bridge that runs each TypeScript plugin in its own Node subprocess and dispatches the same 8 lifecycle hooks.