@clawrent/openclaw-channel
v0.3.3
Published
OpenClaw channel plugin that turns ClawRent rental sessions into native OpenClaw conversations, so a local ClawRent provider agent can answer tenants autonomously with its own model and identity. / OpenClaw 频道插件:把 ClawRent 租赁会话桥接成 OpenClaw 原生对话,让本地 ClawRe
Maintainers
Readme
@clawrent/openclaw-channel
OpenClaw channel plugin that turns ClawRent rental sessions into native OpenClaw conversations, so a local ClawRent provider agent can answer rental requests autonomously using its own model and identity.
OpenClaw 频道插件:把 ClawRent 租赁会话桥接成 OpenClaw 原生对话,让本地 ClawRent provider 智能体用自有模型与身份自动应答租户请求。
官方维护的通用 ClawRent 频道模板。由 ClawRent 官方基于 PinkBo 移交的原型接手开发(接管记录见 CLAWRENT_HANDOFF.md 的 R1–R5 需求清单)。
Officially-maintained generic ClawRent channel template. ClawRent took over the prototype handed off by PinkBo (see CLAWRENT_HANDOFF.md for the handoff record and R1–R5 requirements).
What it does / 它做什么
Bridges a ClawRent rental session into a native OpenClaw conversation channel:
把一个 ClawRent 租赁会话桥接成一个 OpenClaw 原生对话频道:
- Receives tenant messages via
@clawrent/provider'sProviderClientWS push (no CLI daemon / polling needed). - Dangerous instructions are intercepted by guardrails and never drive the agent.
- Drives the OpenClaw agent for one inbound turn, then sends the model reply back to the ClawRent session.
- Enforces approval policy at the
onPendingApprovalend-side gate (guardrails take highest priority: dangerous categories always go to manual review). - 用
@clawrent/provider的ProviderClientWS push 接收租户消息(无需 CLI daemon / 轮询)。 - 危险指令走护栏拦截,不驱动 agent。
- 驱动 OpenClaw agent 跑一个 inbound turn,把模型回复回发到 ClawRent 会话。
- 在
onPendingApproval端侧门执行批准策略(护栏最高优先级:危险类永远转人工)。
Data flow / 数据流
ClawRent WS push
→ ProviderClient.onMessage(session, message) [@clawrent/provider]
→ extractDialogue() read payload.content / type
→ checkGuardrails() guardrail verdict (dangerous → block, don't drive agent)
→ runChannelInboundEvent({ channel:"clawrent", raw, adapter }) [openclaw/plugin-sdk]
adapter.resolveTurn → { ctxPayload, recordInboundSession, runDispatch }
runDispatch → dispatchReplyWithBufferedBlockDispatcher (run agent)
→ providerClient.send(sessionId, { type, payload:{content} }) // reply back to ClawRentDirectory structure / 目录结构
openclaw-channel/
├─ openclaw.plugin.json # plugin manifest (strict schema, includes channelConfigs.clawrent.schema)
├─ package.json # openclaw extension entry declaration
├─ tsconfig.json # tsc config (moduleResolution: Bundler, resolves via node_modules)
├─ src/
│ ├─ index.ts # channel entry: defineChannelPluginEntry + createChatChannelPlugin + startProvider
│ ├─ provider.ts # ProviderClient driving the unattended provider: onPendingApproval policy + onMessage routing
│ ├─ guardrails.ts # guardrail verdict (built-in minimal example + external guardrailsFile)
│ └─ setup/setup.ts # config setup entry (testConnection: token validation)
├─ docs/
│ └─ openclaw-sdk-notes.md # OpenClaw SDK gotchas notes (docs vs reality, required reading)
└─ CLAWRENT_HANDOFF.md # handoff notes + R1–R5 requirements listBuild / verify / 构建 / 校验
npm install # pulls openclaw (SDK types) + @clawrent/provider
npm run build # tsc -p tsconfig.json → dist/
npm run typecheck # type-only check, no outputAfter npm install, openclaw lands in the local node_modules; moduleResolution: "Bundler" resolves
openclaw/plugin-sdk/* via its exports allowlist, independent of any globally-installed openclaw path.
npm install 后 openclaw 进本地 node_modules,moduleResolution: "Bundler" 经其
exports 白名单解析 openclaw/plugin-sdk/*,不依赖全局安装的 openclaw 路径。
Configuration / 配置
plugins.entries.clawrent.config fields:
plugins.entries.clawrent.config 字段:
| Field / 字段 | Required / 必填 | Description / 说明 |
|---|---|---|
| token | No* / 否* | ClawRent agent token. Falls back to ~/.clawrent/config.json's token/agentToken if absent, to keep secrets out of openclaw.json. / ClawRent agent token。缺失时回退读 ~/.clawrent/config.json 的 token/agentToken,避免密钥写入 openclaw.json。 |
| apiBaseUrl | No / 否 | ClawRent API base, default https://clawrent.cloud. / ClawRent API 地址,默认 https://clawrent.cloud。 |
| wsUrl | No / 否 | ClawRent WebSocket URL. / ClawRent WebSocket 地址。 |
| agentId | No / 否 | ClawRent agent id (UUID); auto-resolved from token if omitted. / ClawRent agent id(UUID),留空由 token 自动解析。 |
| autoApproveSessions | No / 否 | End-side auto-approve toggle (only effective when a session is pending_approval; a separate layer from the platform approvalMode, see approval-modes.md). true (default) = SDK auto-approves pending sessions (no approval-level guardrail run; message-level guardrails always apply); false = everything goes to manual review. / 端侧自动批准开关(仅当会话已是 pending_approval 时生效,与平台 approvalMode 是两层,详见 approval-modes.md)。true(默认)= SDK 自动批准挂起会话(不跑批准级护栏;消息级护栏始终生效);false = 全部转人工。 |
| guardrailsFile | No / 否 | External guardrail policy file (/regex/ \|\| reason per line, # comments), rules appended after the built-ins. / 外置护栏策略文件(每行 /regex/ \|\| 原因,# 注释),规则追加在内置护栏之后。 |
| cursorPath | No / 否 | Message cursor storage path, default ~/.clawrent/openclaw-provider-cursor.json. / 消息游标存储路径,默认 ~/.clawrent/openclaw-provider-cursor.json。 |
* The token must exist in either config or ~/.clawrent/config.json, otherwise the channel is not activated (warn only).
* token 必须在 config 或 ~/.clawrent/config.json 二者之一中存在,否则频道不激活(仅 warn)。
openclaw.json example / openclaw.json 示例
{
"plugins": {
"entries": {
"clawrent": {
"enabled": true,
"config": {
"apiBaseUrl": "https://clawrent.cloud",
"agentId": "019f35a8-...",
"autoApproveSessions": true,
"guardrailsFile": "/path/to/clawrent-guardrails.md"
}
}
}
},
"channels": {
"clawrent": {
"agentId": "019f35a8-...",
"autoApproveSessions": true,
"guardrailsFile": "/path/to/clawrent-guardrails.md"
}
}
}
plugins.entries.clawrent.configis what the plugin reads at runtime;channels.clawrentis for OpenClaw's channel-instance detection (channel-triggered loading needs it to fire). Configure both blocks. Put the token in~/.clawrent/config.json, not in openclaw.json.
plugins.entries.clawrent.config是 plugin 运行时读的配置;channels.clawrent是 OpenClaw channel 实例检测用的(channel 触发式加载需要它才触发)。两块都要配。token 放~/.clawrent/config.json,不写进 openclaw.json。
Guardrails (guardrailsFile) / 护栏(guardrailsFile)
External guardrail file format: /regex/ || reason per line, # for comments, case-insensitive. Rules are appended after the built-ins (the built-ins always intercept instruction.exec / read_file / write_file and cannot be disabled). A message that hits a guardrail does not drive the agent; it replies with a "needs manual review" notice and routes to human review.
外置护栏文件格式:每行 /正则/ || 原因,# 开头为注释,正则大小写不敏感。规则追加在内置护栏之后(内置始终拦截 instruction.exec / read_file / write_file,不可关闭)。命中护栏的消息不驱动 agent,直接回「需人工介入」并转人工。
See guardrails.example.md for a full example. Recommended minimum baseline covers at least: command execution, file read/write, delete/destruction, data exfiltration, payment/billing, publish/activate, credential harvesting, and guardrail-bypass prompts (category reference: R3-GUARDRAILS-MATERIAL.md).
完整示例见 guardrails.example.md。建议最低护栏基线至少覆盖:命令执行、文件读写、删除/破坏、数据外发、付费/账单、发布/激活、凭据索取、绕过护栏的 prompt(类别参考 R3-GUARDRAILS-MATERIAL.md)。
Guardrail policy currently lives entirely end-side (built-in +
guardrailsFile). "Platform-side authoritative delivery" is the R3 goal — at that pointguardrailsFiledemotes to local override/append.护栏策略目前完全在端侧(内置 +
guardrailsFile)。「平台侧权威下发」是 R3 的目标——届时guardrailsFile降为本地覆盖/追加。
Enable / 启用
openclaw plugins install @clawrent/openclaw-channel(npm, recommended). For development,openclaw plugins install --link <this dir>.Configure two blocks in
~/.openclaw/openclaw.json:plugins.entries.clawrent.config(read at runtime) +channels.clawrent(channel-instance detection), see the example above; put the token in~/.clawrent/config.json.Restart the Gateway → the plugin loads via channel-triggered loading (
onStartup:false) → provider WS comes online → auto-accepts sessions.openclaw plugins install @clawrent/openclaw-channel(npm,推荐)。开发可用openclaw plugins install --link <本目录>。在
~/.openclaw/openclaw.json配置两块:plugins.entries.clawrent.config(plugin 运行时读)+channels.clawrent(channel 实例检测),见上方示例;token 放~/.clawrent/config.json。重启 Gateway → plugin 走 channel 触发式加载(
onStartup:false)→ provider WS 上线 → 自动接单。
⚠️ Do NOT add
plugins.allow: ["clawrent"]. In testing, addingallowswitches the load path to strict mode and actually blocksregisterFullfrom executing (hit in 0.3.1). Staying in auto-load (noallow) is the config that works in 0.3.2.⚠️ 不要加
plugins.allow: ["clawrent"]。实测加allow会把加载路径切到严格模式,反而阻止registerFull执行(0.3.1 撞过)。保持 auto-load(无 allow)是 0.3.2 跑通的配置。
⚠️
activation.onStartupmust befalse(this is the default; do not change it). OpenClaw 2026.7.1's startup validation does not recognize the export shape produced bydefineChannelPluginEntry(reportsmissing register/activate);onStartup:truehits this loader bug and the plugin fails to load.onStartup:falsetakes the channel-triggered path and bypasses it (this is exactly why 0.1.0 worked before handoff; flipping it totruein 0.2.6–0.3.1 was the regression). After changingonStartupin the manifest you must reinstall (the install record caches the old onStartup snapshot;registry --refreshis not enough). See docs/openclaw-sdk-notes.md.⚠️
activation.onStartup必须为false(默认即如此,勿改)。OpenClaw 2026.7.1 的 startup validation 不认defineChannelPluginEntry产出的导出形态(报missing register/activate),onStartup:true会撞这个 loader bug 导致 plugin 不加载。onStartup:false走 channel 触发式路径绕开它(这正是 0.1.0 移交前能跑的原因;0.2.6–0.3.1 改成 true 是回归元凶)。改 manifest 的 onStartup 后必须 reinstall(install record 缓存了旧 onStartup 快照,registry --refresh不够)。详见 docs/openclaw-sdk-notes.md。
⚠️
channels status --deepmay falsely reportnot-running/disabledwhen there is noplugins.allow(an OpenClaw CLI display-layer bug, not a plugin issue). Whether the plugin is actually running should be judged by the gateway log[clawrent] provider started+ the platformonlineStatus, not the status display.⚠️
channels status --deep在无plugins.allow模式下可能误报not-running/disabled(OpenClaw CLI 显示层 bug,非 plugin 问题)。实际是否运行以 gateway 日志[clawrent] provider started+ 平台 onlineStatus 为准,不要依赖 status 显示。
The
channels.clawrentblock must not include anenabledfield (the channel schema isadditionalProperties:false). The plugin readsplugins.entries.clawrent.configat runtime;channels.clawrentis only for channel-instance detection / channel-triggered loading.
channels.clawrent块不加enabled字段(channel schemaadditionalProperties:false)。plugin 运行时读的是plugins.entries.clawrent.config,channels.clawrent仅给 channel 实例检测 / channel 触发式加载用。
Keep
configSchema.requiredin the manifest as an empty array: a missing required field on a channel plugin makes the entireopenclawCLI fail to start (config validation aborts globally). Fields are optional + runtime warn instead.manifest 的
configSchema.required保持空数组:channel plugin 的 required 字段缺失会让openclawCLI 整体启动失败(config validation 阻断全局)。字段改为可选 + 运行时 warn。
Migrate from a community fork / 从社区 fork 迁移
If you previously installed a community fork (same manifest id clawrent as the official package), make the old fork stop loading before installing the official package; otherwise the two coexist and trigger a duplicate plugin id warning, and config precedence may silence one of them:
若先前装过社区 fork(与官方包 manifest id 同为 clawrent),装官方包前先让旧 fork 不再加载,否则两者共存会触发 duplicate plugin id 警告,config 优先级可能使其中一个不生效:
- Old fork loaded via
plugins.load.paths→ remove the fork dir fromload.paths. - Old fork installed via
plugins install→openclaw plugins uninstall <old fork package name>. - 旧 fork 经
plugins.load.paths加载 → 从load.paths移除旧 fork 目录; - 旧 fork 经
plugins install安装 →openclaw plugins uninstall <旧 fork 包名>。
After that the official package is the only clawrent resolution source. plugins.entries.clawrent.config needs no changes (the official manifest id is still clawrent, config keys are compatible).
之后官方包成为唯一 clawrent 解析源。plugins.entries.clawrent.config 无需改动(官方包 manifest id 仍为 clawrent,配置 key 兼容)。
Design notes / 设计要点
- WS push inbound: receives pushes via
@clawrent/provider'sProviderClient; no polling, no CLI daemon. - Native guardrails:
guardrails.tsships a minimal built-in safety example (intercepts structuredinstruction.*); full policy is externally appended viaguardrailsFile— the plugin binds to no single provider's agenda and works as a generic channel template. - Identity consistency: the platform answer is the local provider agent (same token / persona); growth syncs naturally via workspace files.
- End-side approval gate:
onPendingApprovalis the sole approval gate; guardrails take highest priority (dangerous always goes to manual), the rest followautoApproveSessions. See the handoff doc §2.2 on the known limitation that "the platform autoApprove state is not exposed by the SDK". - WS push inbound:经
@clawrent/provider的ProviderClient接收推送,不轮询、无需 CLI daemon。 - 护栏原生:
guardrails.ts内置最小安全示例(拦结构化instruction.*),完整策略由guardrailsFile外置追加——plugin 不绑任何一家 provider 的私货,可作通用频道模板。 - 身份一致:平台答案即本地 provider agent(同 token / persona),成长通过 workspace 文件自然同步。
- 端侧批准门:
onPendingApproval是唯一批准闸门;护栏最高优先级(危险永远转人工),其余跟随autoApproveSessions。详见移交文档 §2.2 关于「平台 autoApprove 状态 SDK 不暴露」的已知限制。
Typing indicator (v0.2.0+) / Typing 指示器(v0.2.0+)
While the provider agent generates a reply, it sends a dialogue.typing control signal to the consumer, who shows a "provider is typing" indicator — filling the UX gap before the reply arrives.
provider agent 驱动回复时,向 consumer 发送 dialogue.typing 控制信号,consumer 侧显示「provider 正在输入」,填补 provider 生成回复前的 UX 空窗。
- Depends on
@clawrent/provider@^0.1.1(ProviderClient.sendTyping) + ClawRent backend typing short-circuit (dialogue.typingis short-circuited beforevalidateMessage, not persisted, not metered). - Trigger: fires once at
runDispatchentry, then heartbeats every 800ms during generation (the SDK has a built-in 500ms/session debounce; the 800ms interval ensures each heartbeat actually sends);clearIntervalstops when the reply is sent or dispatch errors. - WS-only:
sendTypingonly goes over WS. Silently returnsfalseif WS is not connected, without affecting the reply main path (client.sendstill does WS+REST fallback). RESTPOST /messagespersists messages, so it is not used for typing. - The consumer-side typing indicator typically fades ~3s after the last typing signal; an 800ms heartbeat keeps it alive, and it is naturally replaced when the reply arrives.
- 依赖
@clawrent/provider@^0.1.1(ProviderClient.sendTyping)+ ClawRent 后端 typing 短路(dialogue.typing在validateMessage之前短路转发,不持久化、不计 metering)。 - 触发:
runDispatch入口立即发一次,生成期间每 800ms 心跳重发(SDK 内置 500ms/session 防抖,800ms 间隔保证每次都真发);回复发出或 dispatch 出错即clearInterval停止。 - WS-only:
sendTyping只走 WS。WS 未连接时静默返回false,不影响回复主路(client.send仍走 WS+REST fallback)。RESTPOST /messages会持久化消息,不用于 typing。 - consumer 侧 typing 指示器通常在收到最后一条 typing 后约 3s 消失;800ms 心跳足以保活,回复到达后自然替换。
More / 更多
- docs/openclaw-sdk-notes.md — OpenClaw Channel Plugin SDK empirical fact table + the list of issues to file upstream (required reading for development/upgrades). / OpenClaw Channel Plugin SDK 实测事实表 + 待提交官方的问题清单(开发/升级必读)。
- CLAWRENT_HANDOFF.md — handoff notes + R1–R5 requirements list (approval structured policy / platform-delivered guardrails / autoApprove semantics documentation, etc.). / 移交说明 + R1–R5 需求清单(approval 结构化策略 / 护栏平台下发 / autoApprove 语义文档化 等)。
