npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@flomesh/ztm-chat

v2026.3.11

Published

ZTM Chat channel plugin for OpenClaw

Readme

ZTM Chat Channel Plugin for OpenClaw

OpenClaw Plugin ZTM npm version Build Status Test Coverage TypeScript Vitest Release Version License: MIT

This plugin integrates OpenClaw with ZTM (Zero Trust Mesh) Chat, enabling decentralized P2P messaging through the ZTM network.

Architecture

flowchart TB
    subgraph ZTM["ZTM Network"]
        User["ZTM User"]
        Agent["ZTM Agent"]
    end

    subgraph OpenClaw["OpenClaw Gateway"]
        Plugin["ztm-chat Plugin"]
        Dispatcher["Message Dispatcher"]
        AgentLLM["AI Agent"]
    end

    subgraph Storage["Local Storage"]
        State["Message State"]
        Pairing["Pairing Store"]
    end

    User -->|"DM/Group Message"| Agent
    Agent -->|"Chat App API"| Plugin
    Plugin -->|"Route"| Dispatcher
    Dispatcher -->|"Check Policy"| AgentLLM
    AgentLLM -->|"Response"| Plugin
    Plugin -->|"Chat App API"| Agent
    Agent -->|"Deliver"| User

    Plugin --> State
    Plugin --> Pairing

Data Flow:

  1. User sends message to ZTM Agent
  2. Plugin polls Chat App API for new messages
  3. Dispatcher checks DM/Group policy
  4. If allowed, route to AI Agent
  5. AI Agent generates response
  6. Plugin sends response via Chat App API
  7. ZTM Agent delivers to user

Features

  • Peer-to-Peer Messaging: Send and receive messages with other ZTM users
  • Remote Connection: Connect to ZTM Agent from anywhere via HTTP API
  • Secure: Supports mTLS authentication with ZTM certificates
  • Decentralized: Messages flow through the ZTM P2P network
  • Multi-Account: Support for multiple ZTM bot accounts with isolated state
  • User Discovery: Browse and discover other users in your ZTM mesh
  • Real-Time Updates: Watch mechanism for message monitoring (1-second polling interval)
  • Message Deduplication: Prevents duplicate message processing
  • Structured Logging: Context-aware logger with sensitive data filtering
  • Interactive Wizard: CLI-guided configuration setup
  • Group Chat Support: Multi-user group conversations with permission control
  • Fine-Grained Access Control: Per-group policies, mention gating, and tool restrictions

Installation

1. Install ZTM CLI

Download ZTM from GitHub releases and install to /usr/local/bin:

# Download (example: v2.0.0 for Linux x86_64)
curl -L "https://github.com/flomesh-io/ztm/releases/download/v2.0.0/ztm-aio-v2.0.0-generic_linux-x86_64.tar.gz" -o /tmp/ztm.tar.gz

# Extract
tar -xzf /tmp/ztm.tar.gz -C /tmp

# Install to /usr/local/bin (requires sudo)
sudo mv /tmp/bin/ztm /usr/local/bin/ztm

# Cleanup
rm /tmp/ztm.tar.gz

# Verify
ztm version

2. Start ZTM Agent

ztm start agent

The agent will start listening on http://localhost:7777 by default.

3. Install Plugin

Option A: Install from npm (recommended for users)

openclaw plugins install @flomesh/ztm-chat

Option B: Local development installation

# Install dependencies first
npm install

# Install from local path
openclaw plugins install -l .

# Or link for development
npm link
openclaw plugins install -l .

After installation, the plugin will be available as ztm-chat (or ztm as alias).

4. Run Configuration Wizard

openclaw onboard

Select "ZTM Chat (P2P)" from the channel list.

The wizard will guide you through:

  1. ZTM Agent URL (default: http://localhost:7777)
  2. Permit Source Selection
    • Permit Source: server (from permit server) or file (from local file)
    • Permit Server URL (when server): https://clawparty.flomesh.io:7779/permit
    • Permit File Path (when file): path to local permit.json
  3. Bot Username (default: openclaw-bot)
  4. Security Settings
    • DM Policy: pairing (recommended), allow, or deny
    • Allow From: Whitelist of usernames (or * for all)
  5. Group Chat Settings (if enabled)
    • Enable Groups: Yes/No
    • Group Policy: allowlist, open, or disabled
    • Require Mention: Yes/No (default: Yes)
  6. Summary & Save

5. Restart OpenClaw

openclaw gateway restart

Group Chat

Overview

ZTM Chat supports group conversations with fine-grained permission control. When enableGroups is enabled, the bot can:

  • Receive and process messages from group chats
  • Reply to group messages with @mention support
  • Apply per-group access policies
  • Restrict available tools based on group membership

How It Works

flowchart TB
    subgraph Remote["Remote User Environment"]
        User1["Member 1"]
        User2["Member 2"]
        User3["Member 3"]
        RemotePlugin["ZTM Chat Plugin<br/>(HTTP API Client)"]
        RemoteAgent["ZTM Agent<br/>(Remote)"]
        RemoteFiles["Message Files<br/>(Remote)"]
    end

    subgraph P2P["ZTM P2P Network"]
        Hub["Mesh Hub<br/>(Coordinates Sync)"]
    end

    subgraph Local["Local Bot Environment"]
        LocalAgent["ZTM Agent<br/>(Local)"]
        LocalFiles["Message Files<br/>(Local)"]
        LocalPlugin["ZTM Chat Plugin<br/>(HTTP API Client)"]

        subgraph PluginFlow["Bot Message Processing"]
            Watch["Watch Loop<br/>(1s interval)"]
            Classify["Classify Changes<br/>(peer/group)"]
            Fetch["Fetch Messages<br/>(HTTP API)"]
            Policy["Policy Check"]
            Dispatch["Dispatch Callbacks"]
            AI["AI Agent"]
            Send["Send Response<br/>(HTTP API)"]
        end
    end

    User1 -->|"@mention"| RemotePlugin
    User2 -->|"@mention"| RemotePlugin
    User3 -->|"@mention"| RemotePlugin

    RemotePlugin -->|"HTTP Request"| RemoteAgent
    RemoteAgent -->|"HTTP Response"| RemotePlugin
    RemoteAgent -->|"Read/Write"| RemoteFiles

    RemoteFiles -->|"P2P Sync"| Hub
    Hub -->|"P2P Sync"| LocalFiles
    LocalAgent -->|"Read/Write"| LocalFiles

    LocalPlugin -->|"HTTP Request"| LocalAgent
    LocalAgent -->|"HTTP Response"| LocalPlugin

    LocalPlugin -->|"1. watchChanges"| Watch
    Watch -->|"2. Changed Items"| Classify
    Classify -->|"3. Peer/Group"| Fetch
    Fetch -->|"4. getMessages"| LocalPlugin
    LocalPlugin -->|"Messages"| Fetch

    Fetch -->|"5. Messages"| Policy
    Policy -->|"Allow"| Dispatch
    Policy -->|"Deny"| Ignore[Ignore Message]

    Dispatch -->|"6. Notify Callbacks"| AI
    AI -->|"7. Response"| Send
    Send -->|"8. sendGroupMessage"| LocalPlugin

    LocalPlugin -->|"9. HTTP POST"| LocalAgent
    LocalAgent -->|"Write to Files"| LocalFiles
    LocalFiles -->|"P2P Sync"| Hub
    Hub -->|"P2P Sync"| RemoteFiles
    RemoteAgent -->|"Write to Files"| RemoteFiles

    RemotePlugin -->|"Display"| User1
    RemotePlugin -->|"Display"| User2
    RemotePlugin -->|"Display"| User3

Mention Gating

When requireMention is enabled (default), the bot will only process messages that @mention the bot username:

# Bot username: my-bot

# These messages will be processed:
@my-bot can you help me?
Hey @my-bot what's up?

# These messages will be ignored:
hello everyone!
good morning

Note: requireMention applies to ALL users, including the group creator. This ensures even the group owner must explicitly mention the bot to trigger a response.

Per-Group Configuration

You can configure different policies for different groups:

channels:
  ztm-chat:
    accounts:
      my-bot:
        enableGroups: true
        groupPolicy: allowlist  # Default for unknown groups
        requireMention: true   # Global default (can be overridden per group)
        groupPermissions:
          alice/team:
            groupPolicy: open
            requireMention: false
          bob/project-x:
            groupPolicy: allowlist
            requireMention: true
            allowFrom: [bob, charlie, david]
          private/secret-group:
            groupPolicy: disabled

Tool Restrictions

Control which tools are available in each group:

channels:
  ztm-chat:
    accounts:
      my-bot:
        groupPermissions:
          alice/team:
            groupPolicy: open
            requireMention: false
            tools:
              allow:
                - group:messaging
                - group:sessions
                - group:runtime
            toolsBySender:
              admin:
                alsoAllow:
                  - exec
                  - fs

Tool Policy Options

| Option | Description | |--------|-------------| | tools.allow | Only allow these tools (deny all others) | | tools.deny | Deny these tools (allow all others) | | toolsBySender.{user}.alsoAllow | Additional tools for specific users | | toolsBySender.{user}.deny | Deny tools for specific users |

Default Tools

By default, groups only have access to:

  • group:messaging - Send/receive messages
  • group:sessions - Session management

Creator Privileges

Group creators have special privileges that allow them to bypass certain policy checks:

| Check | Creator Bypass? | |-------|---------------| | groupPolicy (disabled/allowlist/open) | ✅ Yes | | allowFrom whitelist | ✅ Yes | | requireMention | ❌ No (still required) |

This ensures the bot owner can always interact with their own groups while still requiring explicit @mentions to trigger responses.

Usage

Sending a Message

From any ZTM user, send a message to your bot:

Hello! Can you help me with something?

The bot will respond through OpenClaw's AI agent.

Pairing Mode

By default, the bot uses pairing mode (dmPolicy: "pairing"):

  1. New users must be approved before they can send messages
  2. When an unapproved user sends a message, the bot sends them a pairing code
  3. Approve users using the CLI with their pairing code

List Pending Requests

openclaw pairing list ztm-chat

Approve a Pairing Request

openclaw pairing approve ztm-chat <code>

Pairing Mode Policies

| Policy | Behavior | |--------|----------| | allow | Accept messages from all users (no approval needed) | | deny | Reject messages from all users (except allowFrom list) | | pairing | Require explicit approval for new users (recommended) |

CLI Commands

Onboarding Commands

# Interactive setup wizard (recommended)
openclaw onboard

# Select "ZTM Chat" from the channel list
# Follow the 6-step configuration wizard

# Manage existing configuration
openclaw onboard
# Select "ZTM Chat" -> "Manage" -> Choose option:
#   - Test Connection: Verify ZTM Agent connectivity
#   - Update Configuration: Re-run the wizard
#   - Remove: Display removal instructions

Channel Commands

# Check channel status
openclaw channels status ztm-chat

# View configuration
openclaw channels describe ztm-chat

# Probe connection
openclaw channels status ztm-chat --probe

# Enable/disable channel
openclaw channels disable ztm-chat
openclaw channels enable ztm-chat

# List connected peers
openclaw channels directory ztm-chat peers

# List groups (if enabled)
openclaw channels directory ztm-chat groups

Pairing Commands

# List pending pairing requests
openclaw pairing list ztm-chat

# Approve a pairing request
openclaw pairing approve ztm-chat <code>

Configuration

Configuration File

Configuration is stored in openclaw.yaml under channels.ztm-chat:

Mode 1: Server (from permit server)

channels:
  ztm-chat:
    enabled: true
    accounts:
      my-bot:
        agentUrl: "http://localhost:7777"
        permitSource: "server"
        permitUrl: "https://clawparty.flomesh.io:7779/permit"
        meshName: "production-mesh"
        username: "my-bot"
        enableGroups: true
        dmPolicy: "pairing"
        allowFrom:
          - alice
          - trusted-team
        groupPolicy: "allowlist"
        requireMention: true
        groupPermissions:
          alice/team:
            creator: "alice"
            group: "team"
            groupPolicy: "open"
            requireMention: false
            allowFrom: []
            tools:

Mode 2: File (from local permit.json)

channels:
  ztm-chat:
    enabled: true
    accounts:
      my-bot:
        agentUrl: "http://localhost:7777"
        permitSource: "file"
        permitFilePath: "/path/to/permit.json"
        meshName: "production-mesh"
        username: "my-bot"
        enableGroups: true
        dmPolicy: "pairing"
        allowFrom:
          - alice
          - trusted-team
        groupPolicy: "allowlist"
        requireMention: true
        groupPermissions:
          alice/team:
            creator: "alice"
            group: "team"
            groupPolicy: "open"
            requireMention: false
            allowFrom: []
            tools:
              allow:
                - group:messaging
                - group:sessions
                - group:runtime
            toolsBySender:
              admin:
                alsoAllow:
                  - exec

Configuration Options

Required:

| Option | Type | Description | |--------|------|-------------| | agentUrl | string | ZTM Agent API URL | | permitSource | string | Permit source: "server" (from permit server) or "file" (from local file) | | meshName | string | Name of your ZTM mesh | | username | string | Bot's ZTM username |

Required (when permitSource is "server"):

| Option | Type | Description | |--------|------|-------------| | permitUrl | string | Permit Server URL |

Optional (when permitSource is "file"):

| Option | Type | Default | Description | |--------|------|---------|-------------| | permitFilePath | string | - | Path to local permit.json file |

Optional - Basic:

| Option | Type | Default | Description | |--------|------|---------|-------------| | enabled | boolean | true | Enable/disable account | | enableGroups | boolean | false | Enable group chat support | | dmPolicy | string | "pairing" | DM policy: allow, deny, pairing | | allowFrom | string[] | [] | List of approved usernames | | apiTimeout | number | 30000 | API timeout in milliseconds (1000-300000) |

Optional - Group:

| Option | Type | Default | Description | |--------|------|---------|-------------| | groupPolicy | string | "allowlist" | Default group policy: open, allowlist, disabled | | requireMention | boolean | true | Require @mention for group messages (global default) | | groupPermissions | object | {} | Per-group permission overrides |

Group Permission Options

| Option | Type | Description | |--------|------|-------------| | groupPolicy | string | Policy for this group: open, allowlist, disabled | | requireMention | boolean | Require @mention to process message (default: true) | | allowFrom | string[] | Whitelist of allowed senders | | tools.allow | string[] | Only allow these tools | | tools.deny | string[] | Deny these tools | | toolsBySender | object | Sender-specific tool overrides |

Environment Variables

| Variable | Description | |----------|-------------| | ZTM_CHAT_LOG_LEVEL | Logging level: debug, info, warn, error |

Message Processing Pipeline (ADR-010 Compliant)

This plugin follows ADR-010: Multi-Layer Message Processing Pipeline for consistent message handling:

Architecture Layers

| Layer | Module | Responsibility | |-------|--------|----------------| | Layer 1 | watcher.ts | Chat Processing (orchestration) | | Layer 2 | processor.ts | Message Processing (validation, watermark, normalization) | | Layer 3 | policy-checker.ts | Policy Enforcement (unified DM/Group checking) | | Layer 4 | message-dispatcher.ts | Dispatch (callback execution) | | Layer 5 | dispatcher.ts | Persistence (watermark updates) |

Key Design Principle

Unified Policy Checking (ADR-010 Layer 3):

  • DM messages: Check DM policy (pairing/allowlist/deny modes)
  • Group messages: Check ONLY Group policy (DM policy is NOT applied)
  • Timing: Policy checks happen before watermark updates

This fixes the critical bug where dmPolicy:deny was incorrectly rejecting group messages.

DM Message Flow

1. Message arrives from ZTM
2. processPeerMessage() validates self-message check
3. checkMessagePolicy() applies DM policy (Layer 3)
4. processIncomingMessage() normalizes (Layer 2, skipPolicyCheck=true)
5. notifyMessageCallbacks() updates watermark (Layer 5)
6. handleInboundMessage() dispatches to AI agent (Layer 4)

Group Message Flow

1. Message arrives from ZTM
2. processGroupMessage() validates self-message check
3. checkMessagePolicy() applies Group policy (Layer 3) - NOT DM policy
4. processIncomingMessage() normalizes (Layer 2, skipPolicyCheck=true)
5. notifyMessageCallbacks() updates watermark (Layer 5)
6. handleInboundMessage() dispatches to AI agent (Layer 4)

Message Flow

Direct Message (DM)

sequenceDiagram
    participant U as ZTM User
    participant A as ZTM Agent
    participant P as Plugin
    participant B as AI Agent

    U->>A: 1. Send DM to bot
    A->>A: 2. Store message
    P->>A: 3. Poll /api/meshes/{mesh}/apps/ztm/chat/api/peers/{bot}/messages
    A->>P: 4. Return new messages
    P->>P: 5. Check DM policy (allow/deny/pairing)
    alt Policy allows
        P->>B: 6. Route to AI agent
        B->>P: 7. Generate response
        P->>A: 8. Send via Chat App API
        A->>U: 9. Deliver to recipient
    else Policy denied
        P->>P: 6. Ignore message
    end

Group Message

sequenceDiagram
    participant M as ZTM Member
    participant A as ZTM Agent
    participant P as Plugin
    participant B as AI Agent

    M->>A: 1. Send @mention to group
    A->>A: 2. Store message
    P->>A: 3. Poll Chat App API for new messages
    A->>P: 4. Return new messages
    P->>P: 5. Get group permissions (creator/groupId)
    P->>P: 6. Check: creator? → allow
    P->>P: 7. Check: policy (open/allowlist/disabled)
    P->>P: 8. Check: allowFrom whitelist
    P->>P: 9. Check: requireMention (@{bot})
    alt All checks pass
        P->>B: 10. Route to AI agent (with tools filter)
        B->>P: 11. Generate response
        P->>A: 12. Send reply to group
        A->>M: 13. Deliver to all members
    else Any check fails
        P->>P: Log and ignore message
    end

Message Processing Pipeline

flowchart TD
    A[Incoming Message] --> B{isGroup?}

    B -->|No| C[DM Flow]
    B -->|Yes| D[Group Flow]

    C --> C1{DM Policy}
    C1 -->|allow| E[Route to AI]
    C1 -->|deny| F[Ignore]
    C1 -->|pairing| G{Paired?}
    G -->|Yes| E
    G -->|No| H[Send Pairing Request]

    D --> D1{Get Group Permissions}
    D1 --> D2{Is Creator?}
    D2 -->|Yes| E
    D2 -->|No| D3{Policy}
    D3 -->|disabled| F
    D3 -->|allowlist| D4{In allowFrom?}
    D3 -->|open| D5{requireMention?}
    D4 -->|Yes| E
    D4 -->|No| F
    D5 -->|Yes| D6{Mention?}
    D5 -->|No| E
    D6 -->|Yes| E
    D6 -->|No| F

    E --> E1{Resolve Agent Route}
    E1 --> E2{Dispatch to Agent}
    E2 --> E3{Filter Tools}

    E3 --> I[Generate Response]
    I --> J{Send Response}
    J -->|DM| J1[sendZTMMessage]
    J -->|Group| J2[sendGroupMessage]

    F --> K[Log and Ignore]
    H --> K

Note: This diagram shows the functional behavior of policy checks from a user perspective. The internal implementation uses a unified policy checking architecture (ADR-010 Layer 3) where all policy decisions happen before message normalization. See ADR-010: Multi-Layer Message Processing Pipeline for implementation details.

Policy Decision Matrix

DM Policy Check Order:

| Step | Condition | Next Step | |------|-----------|-----------| | 1 | Empty sender | → Deny (ignore) | | 2 | Sender in allowFrom config | → Allow (whitelisted) | | 3 | Sender in pairing store | → Allow (whitelisted) | | 4 | Policy = allow | → Allow (allowed) | | 5 | Policy = deny | → Deny (denied) | | 6 | Policy = pairing | → Send pairing request |

Group Policy Check Order:

| Step | Condition | Next Step | |------|-----------|-----------| | 1 | Empty sender | → Deny (ignore) | | 2 | Sender = creator | → Step 6 (bypass policy) | | 3 | groupPolicy = disabled | → Deny (denied) | | 4 | groupPolicy = allowlist + not in allowFrom | → Deny (whitelisted) | | 5 | groupPolicy = open | → Continue | | 6 | requireMention = true + no @mention | → Deny (mention_required) | | 7 | All checks passed | → Allow (creator/whitelisted/allowed) |

Result Actions:

| Action | Description | |--------|-------------| | process | Message allowed, route to AI agent | | ignore | Message denied, log and discard | | pairing | Send pairing request to user |

ZTM API

The plugin uses the ZTM Agent API for identity/mesh operations and the Chat App API for messaging:

Agent API (Identity & Mesh)

| Method | Path | Description | |--------|------|-------------| | GET | /api/identity | Get agent identity (certificate) | | GET | /api/meshes/{meshName} | Get mesh connection status | | POST | /api/meshes/{meshName} | Join mesh with permit data |

Chat App API

| Method | Path | Description | |--------|------|-------------| | GET | /api/meshes/{meshName}/apps/ztm/chat/api/users | List all users in mesh | | GET | /api/meshes/{meshName}/apps/ztm/chat/api/chats | Get all chats (DMs and groups) | | GET | /api/meshes/{meshName}/apps/ztm/chat/api/peers/{peer}/messages | Get peer messages (with since/before) | | POST | /api/meshes/{meshName}/apps/ztm/chat/api/peers/{peer}/messages | Send message to peer | | GET | /api/meshes/{meshName}/apps/ztm/chat/api/groups/{creator}/{group}/messages | Get group messages | | POST | /api/meshes/{meshName}/apps/ztm/chat/api/groups/{creator}/{group}/messages | Send message to group |

Message API Parameters

| Parameter | Type | Description | |-----------|------|-------------| | since | number | Get messages after this timestamp (Unix ms) | | before | number | Get messages before this timestamp (Unix ms) | | limit | number | Maximum number of messages to return (default: 50) |

Example API Calls

# Get agent identity (certificate)
curl http://localhost:7777/api/identity

# Get mesh status
curl http://localhost:7777/api/meshes/openclaw-mesh

# Join mesh (with permit data)
curl -X POST http://localhost:7777/api/meshes/openclaw-mesh \
  -H "Content-Type: application/json" \
  -d '{"ca":"...","agent":{"certificate":"..."},"bootstraps":["host:port"]}'

# List users
curl http://localhost:7777/api/meshes/openclaw-mesh/apps/ztm/chat/api/users

# Get peer messages (last 10)
curl "http://localhost:7777/api/meshes/openclaw-mesh/apps/ztm/chat/api/peers/alice/messages?limit=10"

# Send message to peer
curl -X POST http://localhost:7777/api/meshes/openclaw-mesh/apps/ztm/chat/api/peers/alice/messages \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello!"}'

# Get group messages
curl "http://localhost:7777/api/meshes/openclaw-mesh/apps/ztm/chat/api/groups/alice/team/messages"

# Send message to group
curl -X POST http://localhost:7777/api/meshes/openclaw-mesh/apps/ztm/chat/api/groups/alice/team/messages \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello everyone!"}'

Troubleshooting

Connection Failed

  1. Verify ZTM Agent is running:

    curl http://localhost:7777/api/meshes
  2. Check mesh name matches:

    curl http://localhost:7777/api/meshes
  3. Check plugin logs:

    openclaw logs --level debug --channel ztm-chat

No Messages Received

  1. Check bot username is correct in configuration
  2. Verify ZTM Agent is running:
    curl http://localhost:7777/api/meshes
  3. Check mesh connectivity:
    openclaw channels status ztm-chat --probe

Development

Running Tests

npm install
npm test            # Run all tests
npm test:watch     # Watch mode
npm run test:coverage  # Run tests with coverage

Debug Logging

ZTM_CHAT_LOG_LEVEL=debug openclaw restart