Files
openclaw/extensions/clickclack
Peter Steinberger cca5b14785 feat(ui): path-based session and dashboard URLs (#113883)
* feat(ui): path-based session and dashboard URLs

* docs(ui): document control UI URLs

* fix(ui): finalize session path routing

* feat(ui): anchor session URLs on stable keys

* docs(ui): clarify stable session URL identity

* fix(ui): resolve session prefixes with full prefix and pagination

Query sessions.list with the full supplied prefix instead of an eight-char
truncation, and paginate up to a bounded page count so longer disambiguation
links resolve instead of being reported ambiguous. Zero strict-prefix matches
now fall through to literal-key resolution rather than rendering an empty
ambiguity view.

Also document the ~dot/~dotdot segment escape: peer ids reach session keys
trimmed and lowercased only (src/routing/session-key.ts), so a literal '.' or
'..' segment is reachable and browsers would normalize it away.

* fix(ui): synchronize committed session routes

* test(ui): split native shell host coverage

* fix(ui): thread configured mainKey through session URL builders

Reserved-set disambiguation needs the operator-configured mainKey at runtime, so
thread it from agentsList through every session path builder and the ClickClack
control URL. Unambiguous non-hex single-segment rests now resolve literally while
short-id-shaped rests still fail closed, which restores ClickClack channel
compatibility detection and control-link reconciliation.

Also bound prefix-resolution retries, preserve catalog thread identity, and keep
draft state on ambiguous candidate links.

* fix(ui): repair session URL CI integration

* perf(ui): lazy-load session route resolution

* perf(ui): isolate session prefix resolution

* perf(ui): defer session path parsing

* perf(ui): defer session navigation startup

* fix(ui): preserve first-run and literal session navigation

* fix(ui): satisfy session routing type and export gates

* fix(clickclack): preserve unscoped control link agent

* style(ui): satisfy chat page line limit

* refactor(ui): move chat page helpers to owning modules

* fix(ui): preserve destination session route identity

* fix(ui): preserve agent identity in session routes

* fix(ui): escape dots in literal session path segments

encodeURIComponent leaves periods intact, so a literal key segment like
channel:release.js produced /chat/main/channel/release.js. In-app navigation is
intercepted by the SPA, but a refresh, an external link, or a ClickClack link
would be served as a static asset request and never reach the app.

pathForWorkboardBoard already escapes dots for this reason; mirror it in both the
session URL contract and the ClickClack encoder, route the agent id through the
same segment encoder, and pin the case in both shared vector tables.

* fix(ui): stop bootstrap after teardown race

* refactor(ui): centralize session navigation targets

* fix(ui): consume bootstrap teardown abort

* fix(ui): canonicalize configured main session routes

* fix(ui): preserve distinct session references

* fix(ui): redirect released session query links

* fix(ui): make bootstrap teardown abort-safe
2026-07-26 12:46:04 -04:00
..
2026-06-04 08:12:22 -04:00

ClickClack OpenClaw channel

Official OpenClaw channel plugin for ClickClack.

Install

openclaw plugins install @openclaw/clickclack

Setup

The recommended setup path uses the one-time command generated by ClickClack:

openclaw channels add clickclack --code 'https://clickclack.example.com/#XXXX-XXXX-XXXX'

Split-origin and path-mounted ClickClack deployments generate an exact /api/bot-setup-codes/claim#CODE endpoint. OpenClaw validates the versioned claim response and saves its canonical API base.

For manual token setup:

openclaw channels add clickclack \
  --base-url https://clickclack.example.com \
  --token ccb_... \
  --workspace default
openclaw gateway

Run openclaw onboard for guided setup. The workspace value can be a wsp_... id, slug, or display name.

For the default account only, --use-env reads CLICKCLACK_BOT_TOKEN; config storage is the normal setup path.

Public and private endpoints

baseUrl is the public ClickClack URL used in links that people open. Set the optional apiBaseUrl when the gateway should call ClickClack through a different server-to-server endpoint:

{
  channels: {
    clickclack: {
      baseUrl: "https://clack.openclaw.ai",
      apiBaseUrl: "http://127.0.0.1:8484",
      token: { source: "env", provider: "default", id: "CLICKCLACK_BOT_TOKEN" },
      workspace: "default",
    },
  },
}

This same-host pattern lets the public hostname stay fully protected by an authentication gateway such as Cloudflare Access while the local OpenClaw gateway talks directly to ClickClack. REST requests, setup verification, and the realtime WebSocket use apiBaseUrl; browser-facing discussion links keep using baseUrl. When apiBaseUrl is unset, it defaults to baseUrl.

Command menus

ClickClack command menus are enabled by default. At gateway startup, the extension publishes OpenClaw's native commands for composer autocomplete, labeled with the bot's handle. The bot token must include commands:write; current bot:write and bot:admin bundles include it.

Set commandMenu: false on an account to disable menu sync. Sync failures do not prevent the gateway from starting, so older tokens and ClickClack servers continue to work without a menu.

Discussions

ClickClack can create one managed channel for each OpenClaw session:

The account token needs channels:write, which is included in bot:admin but not in the normal bot:write setup token. The ClickClack server must also support and return the managed-channel fields used by this integration.

{
  channels: {
    clickclack: {
      baseUrl: "https://clickclack.example.com",
      token: { source: "env", provider: "default", id: "CLICKCLACK_BOT_TOKEN" },
      workspace: "default",
      discussions: {
        enabled: true,
        workspace: "default",
        controlUrlBase: "https://team.openclaw.ai",
        section: "Sessions",
      },
    },
  },
}

Opening a session discussion creates a public, externally managed channel and stores its binding in the ClickClack plugin's SQLite state. Session archive, restore, label, category, and deletion changes are reflected in the channel; deletion archives the channel and never deletes its messages. workspace defaults to the account workspace, and section defaults to Sessions. controlUrlBase adds a link back to /chat?session=<session-key> in the OpenClaw Control UI.

Enable discussions on exactly one ClickClack account. Multiple enabled discussion accounts are rejected because the session discussion provider does not have an account selector.

Messages in the managed channel run in a stable side session under the same agent id as the attached main session. The plugin installs a scoped host grant for sessions_history, session_status, and sessions_send between that side session and its attached main session, so tools.sessions.visibility can stay at its safer default tree. A second host-side policy blocks session discovery and alternate targets; the side-agent prompt is not the authorization boundary. The agent still needs those three tools in its effective tool allowlist.

The binding, managed ownership reference, and side-session identity include the concrete OpenClaw session id as well as the pinned server and channel. Resetting a reusable session key, replacing a binding, or retargeting it therefore revokes the old channel locally, archives it when the old credential remains usable, and starts a fresh channel and side transcript. Messages arriving through an archived, reset, disabled, or retargeted managed binding are dropped instead of falling back to the account's normal channel routing. Released bindings leave a durable revoked-channel marker so delayed realtime events remain fail-closed. Remote ownership is keyed by ClickClack server and channel id, so renaming the local account cannot turn a managed channel into an ordinary one.

Managed-channel ownership references include a durable per-installation id, so two OpenClaw gateways using the same ClickClack workspace do not adopt each other's discussion channels. They also include the destination and a durable binding generation, so an account or workspace round trip cannot re-adopt a previous channel. Changing or removing controlUrlBase is reflected on the next lifecycle reconciliation pass.

If a channel-create response is lost, the pending ownership reservation temporarily quarantines otherwise-unbound events in that workspace. The same coarse reconciler then adopts the created channel or clears/archives the ambiguous attempt; a reset cannot make the old channel fall through to ordinary routing.

When a workspace move keeps the original workspace credential configured, the plugin archives the old channel before release. If the token is replaced with a workspace-scoped credential that cannot access the old workspace, OpenClaw releases the binding into the revoked-channel marker without trying the new token against the old channel; archive that leftover channel from ClickClack.

The main session gets a read-only discussion tool that pulls the latest channel messages, including recent thread replies. The pull uses bounded history and thread-request budgets; its output says when older active threads may have been omitted. It never posts, archives, renames, or otherwise mutates the discussion.

Docs

See docs/channels/clickclack.md in the OpenClaw repository, or the published docs at https://docs.openclaw.ai/channels/clickclack.