Skip to content

Commit 3eaea54

Browse files
shanselmanCopilot
andcommitted
Merge main into connection snapshot truth
Keep PR 918 current with main and add a maintainer patch so app.settings.set surfaces MCP startup failures as tool errors while MCP startup notifications are shown or dismissed from a single runtime policy. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2 parents 1efcfa1 + f89a88a commit 3eaea54

37 files changed

Lines changed: 1024 additions & 83 deletions

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Required steps:
1313
3. Run tray tests:
1414
- `dotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj --no-restore`
1515

16+
This is the required local closeout subset for agents. CI also builds and runs additional connection, setup, CLI, UI, integration, and E2E suites; see `docs/TEST_COVERAGE.md` for the broader inventory.
17+
1618
If a command fails:
1719

1820
1. Fix the issue.

DEVELOPMENT.md

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,18 @@ openclaw-windows-hub/
4444
│ │ ├── Models.cs # Data models (SessionInfo, ChannelHealth, etc.)
4545
│ │ └── IOpenClawLogger.cs # Logging interface
4646
│ │
47+
│ ├── OpenClaw.Connection/ # Gateway registry, credentials, connection manager
48+
│ │
4749
│ ├── OpenClaw.Chat/ # Native chat model and reducer
4850
│ │ ├── ChatModels.cs # Threads, entries, events, provider contract
4951
│ │ └── ChatTimelineReducer.cs # Timeline state transitions
5052
│ │
53+
│ ├── OpenClaw.Cli/ # WebSocket connect/send/probe validator
54+
│ │
55+
│ ├── OpenClaw.WinNode.Cli/ # winnode local MCP/Windows-node CLI
56+
│ │
57+
│ ├── OpenClaw.SetupEngine/ # Local WSL gateway setup and setup-code support
58+
│ │
5159
│ ├── OpenClawTray.FunctionalUI/ # Small in-repo declarative WinUI helper
5260
│ │ └── FunctionalUI.cs # Components, hooks, elements, host control
5361
│ │
@@ -59,8 +67,12 @@ openclaw-windows-hub/
5967
│ │ └── Helpers/ # Icon generation, utilities
6068
│ │
6169
├── tests/
62-
│ ├── OpenClaw.Shared.Tests/ # Unit tests for shared library
63-
│ └── OpenClaw.Tray.Tests/ # Tests for tray helpers (menu, settings, deep links)
70+
│ ├── OpenClaw.Shared.Tests/ # Unit tests for shared library/capabilities/MCP
71+
│ ├── OpenClaw.Connection.Tests/ # Gateway registry and connection manager tests
72+
│ ├── OpenClaw.Tray.Tests/ # Tests for tray helpers (menu, settings, deep links)
73+
│ ├── OpenClaw.WinNode.Cli.Tests/ # winnode CLI contract tests
74+
│ ├── OpenClaw.SetupEngine.Tests/ # Setup engine tests
75+
│ └── OpenClaw.Tray.UITests/ # Native WinUI/A2UI UI tests
6476
6577
├── tools/
6678
│ └── icongen/ # Icon generation tool
@@ -76,16 +88,18 @@ openclaw-windows-hub/
7688
### Project Dependencies
7789

7890
```
79-
OpenClaw.Tray.WinUI ──depends on──▶ OpenClaw.Shared
80-
OpenClaw.Shared.Tests ──tests──▶ OpenClaw.Shared
81-
OpenClaw.Tray.Tests ──tests──▶ OpenClaw.Shared
91+
OpenClaw.Tray.WinUI ──depends on──▶ OpenClaw.Shared + OpenClaw.Connection + OpenClaw.Chat
92+
OpenClaw.WinNode.Cli ──depends on──▶ OpenClaw.Shared
93+
OpenClaw.SetupEngine ──supports──▶ local WSL gateway setup
94+
OpenClaw.*.Tests ──test──▶ corresponding shared, connection, tray, setup, and CLI surfaces
8295
```
8396

8497
### Key Subsystems
8598

8699
| Subsystem | Location | Purpose |
87100
|-----------|----------|---------|
88101
| **Gateway Communication** | `OpenClaw.Shared/OpenClawGatewayClient.cs` | WebSocket client with protocol v3, reconnect/backoff logic |
102+
| **Connection Management** | `OpenClaw.Connection/` | Gateway registry, credential precedence, pairing, tunnels, and reconnect policy |
89103
| **Notification System** | `OpenClaw.Tray.WinUI/App.xaml.cs` | Event routing, toast notifications, classification |
90104
| **WebView2 Integration** | `OpenClaw.Tray.WinUI/Windows/ChatWindow.xaml.cs` | Embedded chat panel with lifecycle management |
91105
| **Tray Icon Management** | `OpenClaw.Tray.WinUI/Helpers/IconHelper.cs` | GDI handle management, dynamic icon generation |

README.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,26 @@ This monorepo contains the Windows hub, shared client libraries, and CLI utiliti
2121
| Project | Description |
2222
|---------|-------------|
2323
| **OpenClaw.Tray.WinUI** | System tray application (WinUI 3) for quick access to OpenClaw |
24-
| **OpenClaw.Shared** | Shared gateway client library |
24+
| **OpenClaw.Connection** | Gateway registry, credential resolution, and connection manager |
25+
| **OpenClaw.Shared** | Shared gateway client library, capabilities, and MCP bridge |
26+
| **OpenClaw.Chat** | Native chat model and timeline reducer |
2527
| **OpenClaw.Cli** | CLI validator for WebSocket connect/send/probe using tray settings |
28+
| **OpenClaw.WinNode.Cli** | `winnode` CLI for invoking local Windows node/MCP capabilities |
29+
| **OpenClaw.SetupEngine** | Local gateway setup, WSL installation, and setup-code support |
2630

2731
## 🚀 Quick Start
2832

2933
> **End-user installer?** Download the latest stable x64 or ARM64 installer from the [OpenClaw Windows docs](https://docs.openclaw.ai/platforms/windows), or see [docs/SETUP.md](docs/SETUP.md) for step-by-step installation (no build required).
3034
>
3135
> **Managed WSL gateway?** Local setup creates a locked-down app-owned `OpenClawGateway` distro. See [docs/WSL_GATEWAY_ADMIN.md](docs/WSL_GATEWAY_ADMIN.md) for editing `openclaw.json` as the `openclaw` user and using root for protected-file administration.
36+
>
37+
> **Operator or node?** Start with [Operator and node concepts](docs/OPERATOR_NODE_CONCEPTS.md) for the beginner-facing glossary of gateway, operator, node, pairing, reapproval, and allowlisted node capabilities.
3238
33-
Direct downloads from the latest OpenClaw release:
39+
Direct downloads from the latest OpenClaw Windows release:
3440

35-
- [OpenClawCompanion-Setup-x64.exe](https://github.com/openclaw/openclaw/releases/latest/download/OpenClawCompanion-Setup-x64.exe)
36-
- [OpenClawCompanion-Setup-arm64.exe](https://github.com/openclaw/openclaw/releases/latest/download/OpenClawCompanion-Setup-arm64.exe)
37-
- [OpenClawCompanion-SHA256SUMS.txt](https://github.com/openclaw/openclaw/releases/latest/download/OpenClawCompanion-SHA256SUMS.txt)
41+
- [OpenClawCompanion-Setup-x64.exe](https://github.com/openclaw/openclaw-windows-node/releases/latest/download/OpenClawCompanion-Setup-x64.exe)
42+
- [OpenClawCompanion-Setup-arm64.exe](https://github.com/openclaw/openclaw-windows-node/releases/latest/download/OpenClawCompanion-Setup-arm64.exe)
43+
- [OpenClawCompanion-SHA256SUMS.txt](https://github.com/openclaw/openclaw-windows-node/releases/latest/download/OpenClawCompanion-SHA256SUMS.txt)
3844

3945
### Prerequisites
4046
- Windows 10 (20H2+) or Windows 11
@@ -54,6 +60,9 @@ Use the setup script to install or verify local Windows build prerequisites:
5460
# Check only; do not install packages or change git safe.directory
5561
.\scripts\setup-dev.ps1 -CheckOnly
5662
63+
# Install/verify prerequisites without adding the checkout to git safe.directory
64+
.\scripts\setup-dev.ps1 -NoTrustRepository
65+
5766
# Setup and run the required build/test validation
5867
.\scripts\setup-dev.ps1 -RunValidation
5968
```
@@ -211,6 +220,8 @@ These features are available in Windows but not in the Mac app:
211220

212221
### 🔌 Node Mode (Agent Control)
213222

223+
If the operator/node split is new to you, read [Operator and node concepts](docs/OPERATOR_NODE_CONCEPTS.md) before enabling Node Mode.
224+
214225
When Node Mode is enabled in Settings, your Windows PC becomes a **node** that the OpenClaw agent can control - just like the Mac app! The agent can:
215226

216227
| Capability | Commands | Description |

build.ps1

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
<#
1+
<#
22
.SYNOPSIS
33
Build script for OpenClaw Windows Hub
44
55
.DESCRIPTION
66
Builds all projects, checks prerequisites, and provides clear guidance.
77
88
.PARAMETER Project
9-
Which project to build: All, Tray, WinUI, Shared, Cli
9+
Which project to build: All, Tray, WinUI, Shared, Cli, WinNodeCli, SetupEngine
1010
Default: All
1111
1212
.PARAMETER Configuration
@@ -322,7 +322,10 @@ if ($issues.Count -gt 0) {
322322
Write-Header "Building Projects ($Configuration)"
323323

324324
# Detect runtime identifier based on architecture
325-
$rid = if ($arch -eq "ARM64") { "win-arm64" } else { "win-x64" }
325+
$rid = switch ($arch) {
326+
"ARM64" { "win-arm64" }
327+
default { "win-x64" }
328+
}
326329
Write-Info "Runtime identifier: $rid"
327330

328331
$buildResults = @{}

docs/CONNECTION_ARCHITECTURE.md

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,21 @@ Inbound chat and agent timeline events must include the gateway's canonical `ses
6969
## Startup wiring (App.xaml.cs)
7070

7171
```
72-
1. Create GatewayRegistry(dataDir)
73-
2. Create CredentialResolver(identityReader)
74-
3. Create GatewayClientFactory()
75-
4. Create NodeConnector(logger)
76-
5. Create SshTunnelManager(tunnelService, logger)
77-
6. Create GatewayConnectionManager(resolver, factory, registry, ...,
78-
nodeConnector, tunnelManager)
79-
7. Subscribe to StateChanged → update tray icon + hub window
80-
8. Subscribe to OperatorClientChanged → wire/unwire 25+ data event handlers
81-
9. Subscribe to NodeConnector.ClientCreated → NodeService.AttachClient
82-
10. Call ConnectAsync() → connects to active gateway
72+
1. Create GatewayRegistry(SettingsManager.SettingsDirectoryPath)
73+
2. Load gateway registry from gateways.json
74+
3. Create CredentialResolver(DeviceIdentityFileReader.Instance)
75+
4. Create GatewayClientFactory()
76+
5. Create ConnectionDiagnostics()
77+
6. Create NodeConnector(logger, diagnostics)
78+
7. Wire NodeConnector.ClientCreated → NodeService.AttachClient
79+
8. Create SshTunnelService(logger)
80+
9. Create GatewayConnectionManager(resolver, factory, registry, logger,
81+
identityStore, nodeConnector, node mode flag,
82+
diagnostics, tunnelService)
83+
10. Subscribe to OperatorClientChanged → wire/unwire 25+ data event handlers
84+
11. Subscribe to StateChanged → update tray icon + hub window
85+
12. Ensure NodeService exists before gateway initialization
86+
13. Call InitializeGatewayClient() → connects to active gateway
8387
```
8488

8589
Settings changes are classified by `SettingsChangeClassifier.Classify()` which compares `ConnectionSettingsSnapshot` before/after to determine the minimum reconnect action:
@@ -129,7 +133,7 @@ Idle → Connecting → Connected
129133
%APPDATA%\OpenClawTray\gateways\<id>\device-key-ed25519.json — keypair + tokens
130134
```
131135

132-
Each `GatewayRecord` contains: `Id`, `Url`, `FriendlyName`, `SharedGatewayToken`, `BootstrapToken`, `LastConnected`, `SshTunnel` config, and an `IdentityDirName`.
136+
Each `GatewayRecord` contains: `Id`, `Url`, `FriendlyName`, `SharedGatewayToken`, `BootstrapToken`, `LastConnected`, `SshTunnel` config, `IsLocal`, `RequiresV2Signature`, `SetupManagedDistroName`, and `BrowserControlPort`. The `IdentityDirName` property is computed from `Id`.
133137

134138
`SettingsManager` still owns general tray settings (node mode, MCP mode, SSH tunnel toggles, notifications, UI preferences). It may read legacy `Token` / `BootstrapToken` JSON fields into memory for migration, but save must not write those legacy credential fields back.
135139

@@ -146,6 +150,13 @@ The invariant is that a paired device token always wins. Do not downgrade a pair
146150

147151
**`CredentialResolver`** implements the precedence for WebSocket connections (operator and node roles).
148152

153+
Node credential precedence follows the same invariant with a distinct stored token:
154+
155+
1. **Stored node device token** in the per-gateway identity directory.
156+
2. **`GatewayRecord.SharedGatewayToken`** — shared token fallback when no paired node token exists.
157+
3. **`GatewayRecord.BootstrapToken`** — one-time setup, limited scopes.
158+
4. **No credential** — caller logs and skips node client init.
159+
149160
**`InteractiveGatewayCredentialResolver`** resolves credentials for HTTP surfaces (chat URL `?token=` auth). It **prefers SharedGatewayToken** over DeviceToken because HTTP endpoints expect the shared token, not the per-device WebSocket token.
150161

151162
## Client instance lifecycle
@@ -179,7 +190,7 @@ When **another** device or node requests pairing, the gateway broadcasts `device
179190

180191
## SSH tunnel integration
181192

182-
`SshTunnelService` manages an SSH local port-forward process. `SshTunnelManager` wraps it behind `ISshTunnelManager` for the connection manager.
193+
`SshTunnelService` manages an SSH local port-forward process and implements `ISshTunnelManager` directly for the connection manager.
183194

184195
When a `GatewayRecord` has `SshTunnel` config, the connection manager starts the tunnel before connecting the WebSocket client to `ws://localhost:<localPort>`. The config stores the SSH daemon port (`sshPort`, default `22`) separately from the remote gateway port forwarded by `-L`.
185196

@@ -203,8 +214,9 @@ The `EnableMcpServer=true`, `EnableNodeMode=false` path creates a local-only `No
203214
Tray actions should never silently no-op on common pairing/configuration issues:
204215

205216
- Chat resolves credentials from the active registry record and per-gateway identity. If no usable credential exists, it opens Connection settings instead.
206-
- Canvas opens only when the Windows node is initialized and paired; otherwise it opens Connection settings.
217+
- Canvas opens only when the Windows node is initialized, paired, and the Canvas capability is enabled in settings; otherwise it opens Connection settings.
207218
- Quick Send uses the live operator client and surfaces scope/pairing errors from gateway calls.
219+
- `system.run` and `system.run.prepare` are gated by `NodeSystemRunEnabled` (default `true` for backward compatibility). When disabled, those commands are dropped from advertised capabilities and invocations are rejected.
208220

209221
## Legacy migration
210222

docs/MCP_MODE.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,12 @@ public bool EnableNodeMode { get; set; } // open WebSocket to gateway
100100
public bool EnableMcpServer { get; set; } // run local MCP HTTP server
101101
```
102102

103-
| `EnableNodeMode` | `EnableMcpServer` | Result |
103+
| `EnableNodeMode` | `EnableMcpServer` | Behavior |
104104
|---|---|---|
105-
| off | off | Operator-only (legacy default) |
106-
| off | on | **MCP server only, no gateway** |
107-
| on | off | Gateway node, no MCP |
108-
| on | on | Gateway node + MCP |
105+
| false | false | Operator-only (legacy default) |
106+
| false | true | **MCP server only, no gateway** |
107+
| true | false | Gateway node, no MCP |
108+
| true | true | Gateway node + MCP |
109109

110110
Settings UI exposes both toggles in the Advanced section, with the live MCP endpoint URL and current status (`Listening` / `Stopped — save and restart to start` / `Disabled`).
111111

docs/OPERATOR_NODE_CONCEPTS.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Operator and Node Concepts
2+
3+
OpenClaw Companion connects a Windows PC to an OpenClaw gateway in two separate
4+
roles. A new install can use both roles at once, but they have different jobs and
5+
different approval paths.
6+
7+
## Quick Glossary
8+
9+
| Term | Meaning |
10+
| --- | --- |
11+
| Gateway | The OpenClaw service that coordinates agents, channels, sessions, devices, and nodes. The Windows app talks to it over WebSocket. |
12+
| Local WSL gateway | A dedicated `OpenClawGateway` WSL distro installed by the Windows onboarding flow. It is app-owned and locked down rather than a general-purpose Ubuntu profile. |
13+
| Operator | The user-facing control role. The tray app uses the operator connection for Quick Send, chat, diagnostics, channel controls, setup, and approving pairing requests. |
14+
| Node | The controllable Windows machine role. When Node Mode is enabled, the tray app advertises Windows capabilities such as screenshots, canvas, camera, notifications, and approved command execution. |
15+
| Pairing | The gateway approval flow that turns a new device or node request into a trusted identity with a stored device token. |
16+
| Reapproval | A later approval request when a paired node asks for new or changed trust, such as command capability access. |
17+
| Allowlisted node capability | A node command the gateway is explicitly allowed to invoke, configured in the gateway `allowCommands` list. Windows-side settings and policies can still block the command. |
18+
19+
## How the Roles Work Together
20+
21+
The operator role is the control surface. It signs in to the gateway, sends chat
22+
messages, shows status, opens diagnostics, and approves device or node pairing
23+
requests when the gateway says approval is required.
24+
25+
The node role is the Windows capability surface. It tells the gateway which
26+
Windows-native tools are available, then waits for approved gateway calls. Node
27+
Mode does not mean every tool can run automatically. A capability has to be
28+
enabled in Windows settings, allowed by the gateway, and in some cases approved
29+
by a local Windows policy prompt.
30+
31+
A typical local setup uses this sequence:
32+
33+
1. OpenClaw Companion installs or connects to a gateway.
34+
2. The tray app connects as an operator so you can send messages and manage setup.
35+
3. If Node Mode is enabled, the same Windows app also connects as a node.
36+
4. The gateway asks for pairing approval before trusting the new device or node.
37+
5. After approval, the gateway can invoke only the node capabilities that are
38+
enabled locally and allowlisted by gateway policy.
39+
40+
## Local WSL Gateway Versus Existing Gateway
41+
42+
The default onboarding path installs a local WSL gateway for users who do not
43+
already have one. That gateway runs on the same Windows PC and is managed by the
44+
OpenClaw Companion setup flow.
45+
46+
Advanced setup is for users who already have a local, remote, or manually
47+
managed gateway. In that case, the Windows app still uses the same operator and
48+
node roles; only the gateway location and credentials are different.
49+
50+
## Pairing, Tokens, and Reapproval
51+
52+
Pairing is gateway-owned. Setup codes, bootstrap tokens, and shared gateway
53+
tokens can help the app connect for the first time, but a paired device token
54+
takes precedence after approval. This keeps long-lived operator and node
55+
identity scoped to the gateway record that issued it.
56+
57+
Some trust decisions are intentionally not automatic. Node command trust and
58+
capability reapproval stay pending until an operator explicitly approves them,
59+
so a new or changed node capability is visible before the gateway can use it.
60+
61+
## Capability Allowlist
62+
63+
Node Mode advertises available Windows commands, but the gateway decides which
64+
commands it may call through `gateway.nodes.allowCommands` in
65+
`~/.openclaw/openclaw.json`. Add exact command names such as `screen.snapshot`,
66+
`canvas.present`, or `system.run`; wildcard entries are not expanded by the
67+
gateway.
68+
69+
Privacy-sensitive commands, especially `screen.record`, `camera.snap`,
70+
`camera.clip`, `stt.transcribe`, `tts.speak`, and `system.run`, should only be
71+
allowlisted when you want the gateway to be able to request that behavior.
72+
Windows permissions, Node Mode toggles, and the local exec policy can still add
73+
stricter checks.
74+
75+
## Where to Go Next
76+
77+
- Follow [Installation and setup](SETUP.md) for first-run onboarding and
78+
troubleshooting.
79+
- See [Node Mode](../README.md#-node-mode-agent-control) for capability names
80+
and allowlist examples.
81+
- Read [Connection architecture](CONNECTION_ARCHITECTURE.md) for contributor
82+
details about token precedence, pairing, and connection lifecycle.

0 commit comments

Comments
 (0)