# How WindowsNodeClient Communicates with the OpenClaw Gateway WebSocket Protocol

> Learn how WindowsNodeClient uses WebSocket protocols to connect with the OpenClaw gateway. Explore stateful message processing JSON, challenges, pairing, commands, and events.

- Repository: [openclaw/openclaw-windows-node](https://github.com/openclaw/openclaw-windows-node)
- Tags: how-to-guide
- Published: 2026-06-05

---

**WindowsNodeClient communicates with the OpenClaw gateway by inheriting from `WebSocketClientBase` to handle low-level socket operations, then implementing a stateful protocol layer that processes JSON message types—handling challenges, pairing flows, command invocations, and events through specific override methods like `ProcessMessageAsync` and `HandleEventAsync`.**

The `WindowsNodeClient` class in the openclaw/openclaw-windows-node repository serves as the primary communication bridge between Windows nodes and the OpenClaw gateway. Acting as a specialized WebSocket client, it manages the complete lifecycle of node registration, authentication, and real-time bidirectional messaging. Understanding how this client implements the gateway protocol is essential for developers building custom node capabilities or debugging connectivity issues.

## WebSocket Client Architecture and Configuration

The `WindowsNodeClient` extends the base functionality defined in `WebSocketClientBase` rather than implementing raw WebSocket logic from scratch. This inheritance provides robust reconnection handling, buffer management, and connection state tracking out of the box.

According to the source in [`src/OpenClaw.Shared/WindowsNodeClient.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/src/OpenClaw.Shared/WindowsNodeClient.cs), the client configures itself with two critical overrides:

- **`ReceiveBufferSize`** set to `65536` bytes (64 KB) at line 108 to handle large message payloads
- **`ClientRole`** returning `"node"` at line 109 to identify itself to the gateway as a participant node rather than an operator client

These configurations ensure the gateway routes messages correctly and allocates appropriate buffer resources for node-specific traffic. The class declaration at line 17 establishes this inheritance: `public class WindowsNodeClient : WebSocketClientBase`.

## Message Dispatch and Protocol Handling

All inbound WebSocket traffic flows through the `ProcessMessageAsync` method at line 443, which parses raw JSON strings and dispatches them based on the top-level `"type"` field. This method implements the core protocol router, delegating to three primary handlers:

- **`HandleEventAsync`** for gateway-initiated events like challenges and pairing updates
- **`HandleResponse`** for replies to client-initiated requests
- **`HandleRequestAsync`** for direct gateway requests requiring immediate action

At line 462, the event branch processes critical gateway signals including `connect.challenge`, `node.pair.requested`, `node.invoke.request`, and `health` pings. This centralized dispatch system ensures protocol messages reach the appropriate handlers while maintaining async flow control.

## Handshake and Pairing Flow

The authentication sequence begins when the gateway emits a `connect.challenge` event, handled at line 299 via `HandleConnectChallengeAsync`. This challenge-response mechanism prevents replay attacks and verifies node identity.

Upon receiving a challenge, the client:

1. Stores the nonce in `_pendingNonce`
2. Constructs a `node.connect` request via `BuildNodeConnectMessage` (line 605)
3. Signs the nonce using `DeviceIdentity` cryptographic methods (Ed25519 signatures)
4. Transmits metadata including capabilities, commands, platform info, and authentication tokens

The `SendNodeConnectAsync` method at line 578 orchestrates this transmission. If the gateway responds with a `hello-ok` payload containing an `auth.deviceToken` (line 722), the client transitions to the paired state and stores the token for subsequent reconnections. Without a device token, the client enters a pending-approval mode, blocking auto-reconnect until explicit pairing approval arrives.

## Command Invocation and Execution

Once paired, the gateway can dispatch remote commands through `node.invoke.request` events, processed at line 300 by `HandleNodeInvokeEventAsync`. The execution flow follows a structured pipeline:

**Capability Resolution** — The client extracts `requestId` and `command` from the payload, then queries the frozen `_commandMap` (built at line 214) to locate the appropriate `INodeCapability` implementation.

**Bounded Execution** — To prevent health-check traffic from blocking, command execution runs on background tasks gated by a semaphore, limiting concurrent operations.

**Result Transmission** — After execution, `SendNodeInvokeResultAsync` (line 636) transmits the output or error details back to the gateway with the matching `requestId`, completing the request-response cycle.

## Publishing Node Events

Beyond responding to gateway commands, nodes can proactively push status updates and custom events using the public `SendNodeEventAsync` method at line 1310. This method accepts an event name and `JsonObject` payload, serializing them into a `node.event` protocol message.

```csharp
// Send a custom telemetry event to the gateway
await client.SendNodeEventAsync(
    eventName: "system.metrics",
    payload: new JsonObject 
    { 
        ["cpu_percent"] = 12.5,
        ["memory_mb"] = 4096 
    });

```

This bidirectional capability enables real-time monitoring scenarios where nodes report state changes without waiting for gateway polling.

## Connection Resilience and State Management

The client maintains sophisticated connection logic through the `ShouldAutoReconnect` override at line 1184, which prevents reconnection attempts during specific error conditions:

- **`_pairingBlocked`** — Set while waiting for admin approval, preventing infinite reconnection loops against unapproved nodes
- **`_rateLimited`** — Set when the gateway signals rate limiting, implementing backoff behavior

Private state fields declared at lines 28-38 track the connection lifecycle: `_isConnected`, `_isPendingApproval`, `_isPaired`, and `_pairingApprovedAwaitingReconnect`. These drive the `PairingStatusChanged` event system, allowing UI components or service managers to react to connectivity transitions.

## Summary

- **Inheritance Model** — `WindowsNodeClient` derives from `WebSocketClientBase` to leverage proven reconnection and buffering logic while adding OpenClaw-protocol specifics.
- **Challenge-Response Auth** — The client signs nonces with `DeviceIdentity` during the `connect.challenge` handshake, transmitting capabilities via `node.connect` messages.
- **Command Dispatch** — Incoming `node.invoke.request` messages route through capability maps to execute registered commands on background threads, returning results via `node.invoke.result`.
- **Event Publication** — Use `SendNodeEventAsync` to push arbitrary JSON events to the gateway when operating in paired state.
- **Smart Reconnection** — Auto-reconnect logic respects pairing status and rate limits, preventing connection storms during approval workflows or gateway overload.

## Frequently Asked Questions

### What is the relationship between WindowsNodeClient and WebSocketClientBase?

`WindowsNodeClient` inherits from `WebSocketClientBase` to obtain low-level WebSocket handling, including buffer management, automatic reconnection with exponential backoff, and connection state monitoring. The base class lives in [`src/OpenClaw.Shared/WebSocketClientBase.cs`](https://github.com/openclaw/openclaw-windows-node/blob/main/src/OpenClaw.Shared/WebSocketClientBase.cs), while `WindowsNodeClient` adds the OpenClaw-specific protocol layer for pairing, authentication, and command execution.

### How does the pairing approval process work?

When the client connects without a stored device token, it sends a `node.connect` request and enters a pending state. If the gateway returns a `hello-ok` response containing an `auth.deviceToken`, the client stores this token and transitions to paired status. If no token is present, the client sets `_pairingBlocked` to true, preventing auto-reconnection until a subsequent `node.pair.resolved` event arrives or the user manually reinitiates the connection.

### What happens when the gateway sends a node.invoke.request?

The client extracts the command name and request ID from the JSON payload, looks up the capability in the `_commandMap` dictionary, and executes the command on a semaphored background task to avoid blocking health pings. After execution, the client automatically transmits the results using `SendNodeInvokeResultAsync`, correlating the response with the original `requestId` so the gateway can match it to the originating request.

### Can WindowsNodeClient operate without automatic reconnection?

Yes. While the base class provides `ShouldAutoReconnect` logic, the `WindowsNodeClient` overrides this at line 1184 to suppress reconnection during pairing approval workflows (`_pairingBlocked`) or rate-limiting scenarios (`_rateLimited`). Developers can also call `DisconnectAsync` to permanently close the connection when cleanup is required, as the reconnection logic only triggers on unexpected disconnections.