openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
235 lines (189 loc) • 13.7 kB
Markdown
---
summary: "Nextcloud Talk support status, capabilities, and configuration"
read_when:
- Working on Nextcloud Talk channel features
title: "Nextcloud Talk"
---
Nextcloud Talk is a downloadable channel plugin (`@openclaw/nextcloud-talk`) that connects OpenClaw to a self-hosted Nextcloud instance through a Talk webhook bot. Direct messages, rooms, reactions, and markdown messages are supported; media goes out as URLs.
## Install
```bash
openclaw plugins install @openclaw/nextcloud-talk
```
Use the bare package spec to follow the current official release tag. Pin an exact version only when you need a reproducible install.
From a local checkout (dev workflows):
```bash
openclaw plugins install ./path/to/local/nextcloud-talk-plugin
```
Check the [application result](/plugins/manage-plugins#apply-changes-and-inspect) after installing.
## Quick setup (beginner)
1. Install the plugin (above).
2. Publish the Gateway webhook route `/nextcloud-talk-webhook` through your HTTPS reverse proxy, forwarding to the Gateway port (default `18789`). On your Nextcloud server, create a bot using that public URL:
```bash
./occ talk:bot:install "OpenClaw" "<shared-secret>" "<webhook-url>" --feature webhook --feature response --feature reaction
```
Keep `--feature response`: without it, outbound replies fail with 401. Repair an existing bot with `./occ talk:bot:state --feature webhook --feature response --feature reaction <botId> 1`.
3. Enable the bot in the target room settings.
4. Configure OpenClaw:
- Config: `channels.nextcloud-talk.baseUrl` + `channels.nextcloud-talk.botSecret`
- Or env: `NEXTCLOUD_TALK_BOT_SECRET` (default account only)
CLI setup (`--url`/`--token` are aliases for the explicit fields; `nc-talk` and `nc` work as channel aliases):
```bash
openclaw channels add --channel nextcloud-talk \
--url https://cloud.example.com \
--token "<shared-secret>"
```
Equivalent explicit fields:
```bash
openclaw channels add --channel nextcloud-talk \
--base-url https://cloud.example.com \
--secret "<shared-secret>"
```
File-backed secret:
```bash
openclaw channels add --channel nextcloud-talk \
--base-url https://cloud.example.com \
--secret-file /path/to/nextcloud-talk-secret
```
5. Check `openclaw channels status --probe`; start the Gateway if it is offline. Config changes follow [hot reload](/gateway/configuration/hot-reload). If you changed the service environment, restart the Gateway to load it.
Minimal config:
```json5
{
channels: {
"nextcloud-talk": {
enabled: true,
baseUrl: "https://cloud.example.com",
botSecret: "shared-secret",
legacyWebhook: false,
dmPolicy: "pairing",
},
},
}
```
## Notes
- Bots cannot initiate DMs. The user must message the bot first.
- The webhook URL must be reachable from the Nextcloud server. The Gateway serves `webhookPath` on its own HTTP port. A shared compatibility listener also forwards the former port `8788` by default; set `legacyWebhook: false` to use only the Gateway port. Set `webhookPublicUrl` to the bot's external callback URL when using a proxy. Webhook requests are HMAC-SHA256 signed with the bot secret; invalid signatures are rejected and rate limited.
- Message webhooks return HTTP 200 only after the raw event is durably stored; storage failures return HTTP 500. The durable `200` carries `x-openclaw-delivery-accepted: durable`, so reverse proxies can require the marker to distinguish OpenClaw acceptance from a generic `200`. Unsupported non-message events return HTTP 200 without the marker and are logged as ignored.
- The webhook listener admits at most 64 concurrent unauthenticated body reads; overflow requests receive `HTTP/1.1 429` with `Connection: close`. Requests on one keep-alive connection are answered in order, so a queued delivery's `200` acknowledgement always flushes before any overflow rejection closes the socket. The 64-read budget is fixed and not configurable. Accounts sharing a Gateway pathname share its admission and failed-authentication budgets; each retained legacy host and port keeps independent budgets. Deployments that regularly saturate it should reduce or buffer upstream concurrency (for example, cap reverse-proxy fan-in toward the listener) and accept that deliveries refused during saturation may be lost.
- Media uploads are not supported by the bot API; outbound media is appended as an `Attachment: <url>` line.
- The webhook payload does not distinguish DMs from rooms; set `apiUser` + `apiPassword` to enable room-type lookups (cached about 5 minutes). Without them, every conversation is treated as a room.
- Outbound requests go through the SSRF guard. For a Nextcloud host on a trusted private/internal network, opt in with `channels.nextcloud-talk.network.dangerouslyAllowPrivateNetwork: true`.
- With `apiUser`/`apiPassword` and `webhookPublicUrl` set, `openclaw channels status` probes the bot and warns when the `response` feature is missing.
## Moving existing webhook endpoints to the Gateway
Updates preserve the previous webhook listener address. When `legacyWebhook` is
omitted, the Gateway opens a shared forwarding listener on `0.0.0.0:8788`.
An explicit `{ port, host? }` object selects that endpoint; an omitted `host`
uses `0.0.0.0`. `legacyWebhook: false` disables the account's legacy forwarding. Both
listeners use the same Gateway route, HMAC verification, and channel handler.
The forwarding listener has no automatic expiry or scheduled retirement.
Nextcloud stores the bot callback URL outside OpenClaw, so an update cannot safely
rewrite it. To use only the Gateway listener, keep the public HTTPS address and
change the reverse proxy's upstream to the Gateway HTTP port (`18789` by default),
preserving `/nextcloud-talk-webhook` or your configured `webhookPath`. If Nextcloud
connects directly, update the bot callback to a reachable HTTPS endpoint for that
Gateway route instead. Update `webhookPublicUrl` if its public address changes;
this field records the address for status checks and does not change Nextcloud's
bot registration.
`openclaw doctor --fix` migrates old `webhookPort` and `webhookHost` settings to
`legacyWebhook`, using Doctor's normal config backup and write flow. Host-only
settings preserve that host with port `8788`. Named accounts preserve their
effective endpoint. Existing canonical settings, including an inherited `false`,
take precedence over retired keys. Doctor and startup report the effective
listener and Gateway destination without changing the external callback URL.
The deprecated TypeScript `webhookPort` and `webhookHost` input fields remain
source-compatible until the next Plugin SDK major. Runtime config uses
`legacyWebhook`; run `openclaw doctor --fix` to migrate the old keys.
Accounts can share a Gateway path: backend origin and signature must identify
exactly one account, so give accounts on the same Nextcloud backend distinct bot
secrets when sharing a Gateway path. Separate legacy endpoints preserve their
original account selection and independent admission and failed-authentication
budgets even when the accounts have the same backend and secret.
Webhook paths retain exact request matching, including query strings, case, and
trailing slashes. `/health`, `/healthz`, `/ready`, `/readyz`, `/startup`, and
`/startupz` belong to Gateway probes, including when a query string follows.
Paths under `/api/channels` require Gateway authentication, including encoded
aliases; Nextcloud's signature does not supply that authentication.
Doctor warns about these paths, and an account with `legacyWebhook: false` cannot
start with one. Set `webhookPath` to `/nextcloud-talk-webhook` and update the
Nextcloud bot callback and reverse-proxy upstream to the Gateway port and that
path. An enabled legacy listener keeps serving its configured path during this
cutover; OpenClaw does not silently rewrite the callback path.
After verifying delivery through the Gateway route, set `legacyWebhook: false`
and restart the account to disable its legacy forwarding. A shared listener stays
open while another account uses that endpoint. Removing `legacyWebhook`
reenables the default listener; use explicit `false` to keep it disabled.
Legacy ports preserve the exact `/healthz` response: `200 ok` with
`Content-Type: text/plain` for every ordinary HTTP method (HEAD has no body).
Query strings, case changes, and trailing slashes do not match that health path.
This keeps existing reverse-proxy health checks working. When moving the proxy
upstream, use the Gateway's own health checks and `openclaw channels status --probe`;
the main Gateway port keeps its existing JSON probe responses.
## Access control (DMs)
- Default: `channels.nextcloud-talk.dmPolicy = "pairing"`. Unknown senders get a pairing code.
- Approve via:
- `openclaw pairing list nextcloud-talk`
- `openclaw pairing approve nextcloud-talk <CODE>`
- Public DMs: `channels.nextcloud-talk.dmPolicy="open"` plus `channels.nextcloud-talk.allowFrom=["*"]`.
- `allowFrom` matches Nextcloud user IDs only (lowercased); display names are ignored.
## Rooms (groups)
- Default: `channels.nextcloud-talk.groupPolicy = "allowlist"` (mention-gated).
- Allowlist rooms with `channels.nextcloud-talk.rooms`, keyed by room token; `"*"` sets a wildcard default:
```json5
{
channels: {
"nextcloud-talk": {
rooms: {
"room-token": { requireMention: true },
},
},
},
}
```
- Per-room keys: `requireMention` (default true), `enabled` (false disables the room), `allowFrom` (per-room sender allowlist), `tools` (allow/deny tool overrides), `skills` (limit loaded skills), `systemPrompt`.
- To allow no rooms, keep the allowlist empty or set `channels.nextcloud-talk.groupPolicy="disabled"`.
## Capabilities
| Feature | Status |
| --------------- | ------------- |
| Direct messages | Supported |
| Rooms | Supported |
| Threads | Not supported |
| Media | URL-only |
| Reactions | Supported |
| Native commands | Not supported |
## Configuration reference (Nextcloud Talk)
Full configuration: [Configuration](/gateway/configuration)
Provider options:
- `channels.nextcloud-talk.enabled`: enable/disable channel startup.
- `channels.nextcloud-talk.baseUrl`: Nextcloud instance URL.
- `channels.nextcloud-talk.botSecret`: bot shared secret (string or secret reference).
- `channels.nextcloud-talk.botSecretFile`: regular-file secret path. Symlinks are rejected.
- `channels.nextcloud-talk.apiUser`: API user for room lookups (DM detection) and the status probe.
- `channels.nextcloud-talk.apiPassword`: API/app password for room lookups.
- `channels.nextcloud-talk.apiPasswordFile`: API password file path.
- `channels.nextcloud-talk.legacyWebhook`: `false | { port, host? }`. Omitted: forwards `0.0.0.0:8788` to the Gateway route. An object overrides the port and optionally the host; `false` disables the listener after callback or proxy cutover. Named accounts inherit the root setting unless they override it.
- `channels.nextcloud-talk.webhookPath`: webhook path (default: /nextcloud-talk-webhook).
- `channels.nextcloud-talk.webhookPublicUrl`: externally reachable webhook URL.
- `channels.nextcloud-talk.dmPolicy`: `pairing | allowlist | open | disabled` (default: pairing). `open` requires `allowFrom=["*"]`.
- `channels.nextcloud-talk.allowFrom`: DM allowlist (user IDs).
- `channels.nextcloud-talk.groupPolicy`: `allowlist | open | disabled` (default: allowlist).
- `channels.nextcloud-talk.groupAllowFrom`: room sender allowlist (user IDs); falls back to `allowFrom` when unset.
- `channels.nextcloud-talk.rooms`: per-room settings and allowlist (see above).
- Static sender access groups can be referenced from `allowFrom` and `groupAllowFrom` with `accessGroup:<name>`.
- `channels.nextcloud-talk.historyLimit`: group history limit (0 disables).
- `channels.nextcloud-talk.dmHistoryLimit`: DM history limit (0 disables).
- `channels.nextcloud-talk.dms`: per-DM overrides keyed by user ID (`historyLimit`).
- `channels.nextcloud-talk.textChunkLimit`: outbound text chunk size in chars (default: 4000).
- `channels.nextcloud-talk.streaming.chunkMode`: `length` (default) or `newline` to split on blank lines (paragraph boundaries) before length chunking.
- `channels.nextcloud-talk.streaming.block.enabled`: enable or disable block streaming for this channel.
- `channels.nextcloud-talk.streaming.block.coalesce`: block streaming coalesce tuning.
- `channels.nextcloud-talk.replyToMode`: reply-reference mode (`off | first | all | batched`; default: `all`). Named accounts can override it with `channels.nextcloud-talk.accounts.<id>.replyToMode`.
- `channels.nextcloud-talk.responsePrefix`: outbound reply prefix.
- `channels.nextcloud-talk.markdown.tables`: markdown table rendering mode (`off | bullets | code | block`).
- `channels.nextcloud-talk.network.dangerouslyAllowPrivateNetwork`: allow private/internal Nextcloud hosts past the SSRF guard.
- `channels.nextcloud-talk.accounts.<id>`: per-account overrides (same keys); `defaultAccount` picks the default. Env vars `NEXTCLOUD_TALK_BOT_SECRET` / `NEXTCLOUD_TALK_API_PASSWORD` apply to the default account only.
## Related
- [Channels Overview](/channels) — all supported channels
- [Pairing](/channels/pairing) — DM authentication and pairing flow
- [Groups](/channels/groups) — group chat behavior and mention gating
- [Channel routing](/channels/channel-routing) — session routing for messages
- [Reactions](/tools/reactions) — emoji reaction semantics for the `message` tool
- [Security](/gateway/security) — access model and hardening