@partme.ai/openclaw-web-stomp
v0.1.11
Published
STOMP over WebSocket bridge for OpenClaw — enterprise integration with Spring STOMP clients and web apps
Downloads
137
Maintainers
Readme
OpenClaw Web STOMP
OpenClaw plugin — STOMP 1.x over WebSocket (stomp-ws) with topic bindings and session.dmScope isolation
Introduction
@partme.ai/openclaw-web-stomp is an OpenClaw channel plugin that exposes STOMP over WebSocket and bridges browser or Spring-style clients to agents. It follows the official channel pattern: defineChannelPluginEntry and ChannelPlugin (not definePluginEntry).
Behavior is aligned with openclaw-mqtt, openclaw-web-mqtt, and openclaw-stomp (TCP):
subscribeTopics— inbound SEND (and optional SUBSCRIBE) allowlist using*/#patterns on full STOMP destinations.topicBindings— explicittopicPattern → agentId(+ optionalaccountId,replyTopicas reply destination).- Standard fallback — destinations matching
agent.<id>under/queue/(same idea as TCP STOMP plugin). - Session keys — only from OpenClaw global
session.dmScopevia sharedbuildSessionKeyFromDmScope(no channel-local duplicate scope config).
Capabilities
- Gateway lifecycle — server starts in
gateway.startAccount, stops on abort (same model asopenclaw-web-mqtt). - Status HTTP —
GET /stomp-ws/status(auth: plugin) — connections, subscription stats, ACK stats, redacted config snapshot. - Enterprise-style controls — max connections, max frame / payload size, optional TLS (HTTPS server + WS upgrade), per-user
publishAllow/subscribeAllow/aclRules(RabbitMQ-style topic ACL inspiration; see also Web MQTT operational patterns). openclaw.setupEntry—dist/setup-entry.jsfor setup-only loads (SDK setup).
Message flow
- Client CONNECT (optional
login/passcodeperchannels["stomp-ws"].auth). - Client SUBSCRIBE to
/topic/session.<sessionKey>(or your policy-approved destinations). - Client SEND to a destination allowed by
subscribeTopics. - Plugin resolves agent via
topicBindingsfirst, then standard agent destination fallback. - OpenClaw
dispatchReplyFromConfigruns; replies publish toreplyTopicor/topic/session.<sessionKey>derived fromdmScope.
Quick start
Prerequisites
- OpenClaw
>= 2026.4.0 - Node.js
22+
Install
openclaw plugins install @partme.ai/openclaw-web-stompMinimal openclaw.json
{
"session": {
"dmScope": "per-channel-peer"
},
"channels": {
"stomp-ws": {
"wsPort": 15674,
"path": "/ws",
"subscribeTopics": ["/queue/devices/+/in", "/queue/agent.*"],
"topicBindings": [
{
"topicPattern": "/queue/devices/*/in",
"agentId": "iot-agent",
"accountId": "default",
"replyTopic": "/topic/devices/reply"
}
],
"auth": {
"required": false,
"allowAnonymous": true
}
}
}
}Migration from legacy channels.stomp: use channels["stomp-ws"] and channel id stomp-ws. Legacy keys under channels.stomp are merged for convenience but stomp-ws overrides on conflict.
Session and dmScope
Session isolation uses only the OpenClaw root key session.dmScope (same as mqtt, mqtt-ws, stomp-tcp). Allowed values: main, per-peer, per-channel-peer, per-account-channel-peer.
- The plugin does not read a channel-local
session.dmScopeunderchannels["stomp-ws"]for isolation (if present elsewhere, it is ignored for this purpose). - Inbound
fromis the STOMP peer id (headersx-peer-id/peer-id/sender, else login /client-id/ connection id). - Replies go to
topicBindings[].replyTopicwhen set, otherwise/topic/session.<sessionKey>wheresessionKeyis frombuildSessionKeyFromDmScopewithchannel: "stomp-ws".
Match mqtt-ws / stomp-tcp docs for how each dmScope affects the session key string.
Security
- Production: set
auth.required: true, disableallowAnonymous, and useauth.users(plainpasswordin config today — prefer env-backed secret injection or a reverse proxy for credential handling). - ACL: optional
publishAllow,subscribeAllow, andaclRulesper user (same semantics asopenclaw-web-mqtt). - TLS:
tls.enabledwithcertFile/keyFilestarts HTTPS and attaches the WebSocket server; alternatively terminate TLS at your edge and proxy to plainwsinternally. - Limits: tune
maxConnections,limits.maxPayloadBytes,maxFrameSize, andlimits.maxSubscriptionsPerClientto match broker-style hardening (see RabbitMQ Web MQTT for operational parallels).
Troubleshooting
| Symptom | Check |
| --- | --- |
| CONNECT fails with Authentication failed | auth.users / defaultUser+defaultPass, or set allowAnonymous: true for dev. |
| SEND accepted but no agent reply | Gateway running, agent route for stomp-ws, topicBindings / fallback agent id, and client SUBSCRIBE to the actual reply destination (often /topic/session.<sessionKey>). |
| SUBSCRIBE ignored | If subscribeTopics is non-empty, destination must match a pattern; check maxSubscriptionsPerClient. |
| test:client timeout | Wrong STOMP_SUBSCRIBE_DESTINATION for current session.dmScope; inspect GET /stomp-ws/status and logs. |
Testing
pnpm test
pnpm run test:clientTest client env vars: STOMP_WS_URL, STOMP_LOGIN, STOMP_PASSCODE, STOMP_SEND_DESTINATION, STOMP_SUBSCRIBE_DESTINATION, STOMP_PAYLOAD, STOMP_TIMEOUT_MS.
GitHub Actions
| Workflow | Trigger | Purpose |
| --- | --- | --- |
| .github/workflows/ci.yml | Push / PR main / master | pnpm install, typecheck, build, test, artifact dist/ |
| .github/workflows/release.yml | Tag v* / workflow_dispatch | Publish npm + GitHub Packages, GitHub Release |
Publishing
- Package:
@partme.ai/openclaw-web-stomp - Secret:
NPM_TOKEN - Details:
RELEASING.md
Project layout
src/
index.ts # defineChannelPluginEntry + registerFull
setup-entry.ts # defineSetupPluginEntry
channel.ts # ChannelPlugin + gateway.startAccount
stomp-server.ts # WS + STOMP frame handling
stomp-config.ts # resolve channels["stomp-ws"]
inbound.ts # dispatchReplyFromConfig + dmScope session key
dm-scope.ts # same logic as stomp-tcp / web-mqtt
route-inbound.ts # topicBindings + fallback
topic-router.ts # * / # matching
acl.ts # optional per-user destination ACL
outbound.ts # publish to /topic/session.<key>