Skip to main content
Use this page after the first setup is already working and you want to make the SimpleX runtime persistent or split multiple accounts across separate runtimes. For the first install and pairing flow, start with Getting Started.

Keep simplex-chat running

If you want the SimpleX runtime to start automatically on login or machine boot, let the host OS supervise it and keep OpenClaw focused on the channel connection itself. The plugin CLI can generate and install a host service for the current machine:
The service helper auto-detects systemd —user on Linux, launchd on macOS, and SysV init as a Linux fallback. It prints the generated service file and next commands first, and it asks for interactive approval before writing files. It prints supervisor commands for the operator to run instead of executing them from the plugin. Use —provider systemd, —provider launchd, or —provider sysvinit to override detection. Common install options:
Use —dry-run with install to print the plan without writing files.
The runtime must run with both —files-folder and —temp-folder, and those directories must exist before it starts, or sending and receiving files fails. This failure is silent: simplex-chat started with -p does not log it. The service the CLI helper generates creates both folders on start, so this is handled for you. If you hand-write a service file or run simplex-chat directly, create them first with mkdir -p ~/.simplex/files ~/.simplex/tmp. openclaw simplex runtime doctor warns when the files folder is missing or not writable.
The repo also ships deployment templates under examples/:
  • examples/docker-compose.sidecar.yml: OpenClaw plus a private simplex-chat sidecar network.
  • examples/systemd/simplex-chat.service: hardened user service template.
  • examples/caddy/Caddyfile: TLS/auth proxy example for exceptional remote WebSocket access.

Decide which settings go where

Use this rule:
  • put OpenClaw channel behavior in channels.openclaw-simplex
  • put simplex-chat process startup flags in the supervised service command line
Plugin-side settings:
  • connection.wsUrl
  • connection.allowUnsafeRemoteWs
  • connection.connectTimeoutMs
  • connection.autoAcceptFiles
  • connection.filesFolder
  • connection.outboundFolder
  • connection.outboundFolderOnClient
  • streaming.nativeTransport and related live-reply throttling fields
  • messageTtlSeconds and filePolicy
  • dmPolicy, allowFrom, groupPolicy
Runtime-side startup flags:
  • relay and proxy selection: —server, —xftp-server, —socks-proxy, —host-mode, —smp-proxy
  • local storage/layout: —database, —files-folder, —temp-folder, —log-file
  • runtime process behavior: —device-name, —maintenance, —mute, —mark-read

Locating received files (connection.filesFolder)

connection.filesFolder is the path where OpenClaw reads files the runtime received. When the runtime is started with —files-folder, it reports received files by name only (not a full path), and the plugin joins that name to connection.filesFolder (default ~/.simplex/files) to read the bytes. Without —files-folder the runtime reports absolute paths and this setting is unused.
The name-only reporting is deliberate, and it is what lets the runtime and OpenClaw refer to the same files from different locations. How you set connection.filesFolder depends on the topology:
  • Shared filesystem (OpenClaw and the runtime see the same paths — e.g. both on one host, or both in one container): set connection.filesFolder to the same path as —files-folder.
  • Containerized runtime with a shared volume: when the runtime runs in a container, its filesystem is separate from OpenClaw’s (whether or not OpenClaw is containerized too), and each side usually mounts the shared volume at a different path — that is fine. Set —files-folder to the runtime’s mount and connection.filesFolder to OpenClaw’s mount of the same volume. An absolute path would break here, because the runtime’s directory does not exist on OpenClaw’s side; the name-only reporting is exactly what bridges the two mounts.
The sidecar writes /data/files/photo.jpg and reports photo.jpg; OpenClaw reads it from /shared/simplex/photo.jpg — same volume, different mount paths, bridged by the file name.

Sending files (connection.outboundFolder)

connection.outboundFolder is the directory OpenClaw stages an outgoing file into before telling the runtime to send it. There is no runtime flag for this — on send OpenClaw passes a path that the runtime resolves on its own side, so the file must be readable there. When OpenClaw and the runtime share a filesystem (the default), leave this unset and the local file path is passed as-is; it only matters when the runtime is containerized.
This is the mirror image of inbound, with one crucial difference. Inbound is name-only, so the two sides may mount the shared directory at any paths. Outbound sends a full path to the runtime, so the path OpenClaw sends has to be valid on the runtime’s side. There are two ways to arrange that. Same path on both sides (simplest). Mount the shared volume at the identical absolute path in both, and set only connection.outboundFolder:
OpenClaw stages pic.jpg into /tmp/simplex-outbound and passes /tmp/simplex-outbound/pic.jpg; the runtime reads that same path, then the staged file is removed after the send. Different paths (path translation). When the two sides can’t mount the volume at the same path, add connection.outboundFolderOnClient — the same directory as the runtime sees it. OpenClaw writes to outboundFolder but rewrites the directory prefix to outboundFolderOnClient before sending, so no verbatim path is needed:
OpenClaw stages pic.jpg into /srv/openclaw/outbound and sends /data/.simplex/outbound/pic.jpg; the runtime reads its own path. (This is also the case when OpenClaw runs on the host and the runtime in a container — set each side’s path accordingly.)

Manual service files

The CLI helper above is the preferred path. These examples show what it writes and are useful when you want to manage the service definition yourself.
Adjust the ExecStart path if simplex-chat is installed somewhere other than %h/.local/bin/simplex-chat. The extra flags above are examples of runtime-owned settings that do not belong in OpenClaw channel config.

Start it

Check status

Expected result: the service status should be active (running).

Common startup flag patterns

These are reasonable patterns to consider when you run simplex-chat as an external service:
  • fixed local identity label: —device-name “OpenClaw SimpleX”
  • explicit file locations: —files-folder ~/.simplex/files —temp-folder ~/.simplex/tmp
  • custom relay policy: —server “smp1.example.com smp2.example.com” —xftp-server “xftp1.example.com”
  • SOCKS/Tor routing: —socks-proxy :9050 —host-mode onion —required-host-mode
  • stricter message routing: —smp-proxy always —smp-proxy-fallback no
Do not copy every CLI flag into the service blindly. Flags such as proxy mode, relay selection, maintenance mode, and custom database paths materially change runtime behavior and should be chosen deliberately for your deployment.

Maintenance mode

If you need to bring up the runtime without immediately serving chat traffic, run it with —maintenance and start chat manually inside the runtime later. This is a simplex-chat operational mode, not an OpenClaw channel config field, so it belongs in the service command only when you intentionally want that behavior.

Remote WebSocket endpoints

Prefer loopback, a private sidecar network, or wss:// with access controls. Plaintext ws:// endpoints on non-loopback hosts are blocked by default because the WebSocket API controls the SimpleX runtime. Only set connection.allowUnsafeRemoteWs: true when that endpoint is protected by a private network, firewall, or authenticated TLS proxy.