Most agent chat channels assume a platform bot identity. You register a bot username, a phone number, an application account, or some other platform-managed endpoint, and the agent becomes reachable through that platform’s identity model.
That works well enough in many cases, but it is not the only model worth supporting.
What I wanted for OpenClaw was more specific: a private, end-to-end encrypted transport for agents, without having to provision another phone number and without relying on an unofficial integration path for a core channel.
I built @dangoldbj/openclaw-simplex, a SimpleX Chat channel plugin for OpenClaw, to support a different model: no public bot identity, invitation-based onboarding, and an explicit runtime boundary between the agent platform and the transport layer.
The problem with normal bot channels
For most chat integrations, your agent is reachable because the platform says it exists. That reachability usually depends on some centralized registration step:
- a bot username on a messaging platform
- a phone-number-backed account
- an app registration inside a workspace product
- a hosted bot API endpoint
In other words, the transport decides how the agent is discovered.
That is often convenient. But it is not always a good fit for more constrained deployments:
- private client-specific agents
- internal tools inside isolated environments
- deployments that want operator-controlled transport, not only operator-controlled inference
- agent-to-agent setups that do not want to depend on a third-party bot platform
What I actually wanted was something closer to Signal-level privacy, or better, without the awkward parts that usually come with personal-account-oriented messaging systems.
One obvious route would have been an existing phone-number-centered messaging channel. In OpenClaw, the Signal path is one example: it goes through signal-cli, and signal-cli describes itself as an unofficial interface for Signal. That does not make it unusable, but it was enough to make me cautious about depending on that path for a core agent channel.
There was also the onboarding model. Phone-number-based setup is common in personal messaging systems, but I did not want to buy and manage another phone number just to make an OpenClaw agent reachable. For an agent transport, that is unnecessary operational friction. A personal messaging identity model is often the wrong abstraction for an agent.
So the requirement set was more specific than “I want invite links”. I wanted a channel that was:
- end-to-end encrypted
- privacy-oriented by design
- usable without provisioning a new phone number
- simple enough to operate locally
- explicit about who can reach the agent
SimpleX matched that shape much better. Invitation-first reachability was the result of those constraints, not the starting point.
Why SimpleX
SimpleX is interesting because it gives a very different trust and onboarding model from mainstream chat platforms.
With this plugin, the contact surface begins with a SimpleX invite link or address link. The agent is not globally discoverable through a public bot username. There is no phone number to provision. There is no hosted platform account that has to exist before the first conversation starts.
That creates a different shape of access:
- you generate a link
- you share it intentionally
- the other side connects through that link
- you can revoke the link when that access should disappear
This is a better fit for deployments where explicit onboarding matters more than broad discoverability.
Just as importantly, SimpleX makes it possible to think about self-hosted transport more seriously. A lot of people talk about self-hosting the model runtime while the transport path still goes through someone else’s platform identity and account system. With SimpleX, if you want, you can run the runtime locally and keep the relay path under infrastructure you control.
What the plugin actually adds to OpenClaw
The shortest description is that it makes OpenClaw reachable over SimpleX, but that undersells what a real channel integration has to do.
The plugin has to:
- attach to a running
simplex-chatruntime over WebSocket - normalize incoming SimpleX events into OpenClaw’s channel/message model
- apply OpenClaw’s policy model on top of SimpleX reachability
- translate outbound replies and actions back into SimpleX commands
- expose invite and address management flows in a way operators can actually use
In practical terms, the package now supports:
- direct and group messaging
- pairing approval and allowlist enforcement
- media send/receive
- invite link, address link, and QR generation
- shared message actions such as edits, deletes, reactions, and file upload
- gateway methods and plugin tools for invite automation and group administration
- runtime status reporting
- multi-account configuration
That is what turns the project from “a bridge script” into a real OpenClaw channel implementation.
The architecture that mattered
The most important design choice in the project is that OpenClaw should not own the lifecycle of the SimpleX runtime for this plugin.
The architecture looks like this:
+-------------------------+
| OpenClaw |
| (agent + router/core) |
+------------+------------+
|
| channel plugin API
v
+-------------------------+
| @dangoldbj/openclaw- |
| simplex |
| - inbound monitor |
| - outbound translation |
| - account/runtime state |
+------------+------------+
|
| WebSocket API
v
+-------------------------+
| SimpleX CLI Runtime |
| (simplex-chat) |
+------------+------------+
|
| network
v
+-------------------------+
| SimpleX Network |
+-------------------------+
OpenClaw is responsible for routing and policy. The plugin is responsible for translating channel behavior. The simplex-chat runtime is a separately managed process.
This separation is deliberate.
If the plugin spawned and supervised simplex-chat itself, the integration would look simpler at first glance, but it would blur the runtime boundary and hide operational assumptions inside plugin startup. I wanted the deployment model to stay explicit:
- operators run
simplex-chat - OpenClaw connects to its WebSocket endpoint
- host-level service supervision stays a host concern
- OpenClaw remains responsible for policy and agent routing, not process management
Over time I pushed that separation further by removing the earlier managed mode and making the external runtime path the supported model.
Reachability is not authorization
One subtle point in this integration is that invitation-based messaging is not, by itself, the whole security story.
SimpleX gives the first boundary: who can reach the agent at all.
OpenClaw then adds another boundary: who is allowed to trigger agent work after a message arrives.
That second layer matters. In this plugin, OpenClaw still applies:
- direct-message policy
- allowlists
- pairing approval
- group policy
- command authorization
So the security model is not just “messages are encrypted” or “the link is private”. It is a layered model:
- the invite or address link creates the initial contact path
- OpenClaw policy determines whether that sender is allowed to interact with the agent
- the runtime boundary determines where process and relay trust live
That is the kind of distinction that becomes important once a project moves from demo to something operators may actually rely on.
The operator workflow
The operator flow is intentionally small.
You run simplex-chat as a separate process, point OpenClaw at its WebSocket endpoint, and generate an invite link for the first contact. After that, the interesting parts are not the setup steps themselves but the operational surfaces around them:
- pairing approval for first-time contacts
- invite and address management
- runtime status visibility
- gateway methods for automation
- host-level supervision through
systemd --userorlaunchd
That was an important part of the design. I did not want the project to stop at “messages can be exchanged.” I wanted the channel to be operable.
The docs and screenshots for the project live at openclaw-simplex.mintlify.app.
Why I think this matters
What interests me most about this project is not that OpenClaw can now talk over SimpleX. It is that this integration expands what a channel can mean inside an agent platform.
Instead of assuming a public platform bot identity, the channel can start from an invitation. Instead of hiding the transport runtime inside the plugin, the runtime boundary can stay explicit. Instead of treating transport choice as only a UX detail, it can shape the trust model of the deployment.
I think that is a useful direction.
There are many cases where a public bot account is exactly the right abstraction. But there are also cases where private, operator-controlled messaging is a better fit, and I wanted OpenClaw to have that option.
The package, source, and docs are here: