Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1433349
feat(tray): add onboarding wizard updates (#241)
indierawk2k2 May 1, 2026
3b8793d
feat: winnode CLI for invoking node commands over local MCP (#250)
codemonkeychris May 1, 2026
70b8ee6
test: isolate tray onboarding settings
shanselman May 1, 2026
4207163
fix(security): catch all-wildcard allow patterns in exec approval pol…
github-actions[bot] May 1, 2026
dc640ee
fix(security): block dangerous stem+wildcard allow patterns in execAp…
github-actions[bot] May 1, 2026
61ef7d1
test: add SshTunnelCommandLine, ExecApprovalV2Result, and McpToolBrid…
github-actions[bot] May 1, 2026
72ffc78
refactor(tray): remove two unused tray menu helpers (~240 lines) (#251)
AlexAlves87 May 1, 2026
1773cc7
perf(mcp): eliminate LINQ and ToArray() allocations in McpToolBridge …
github-actions[bot] May 1, 2026
758c881
fix: McpHttpServer and tests for Linux HttpListener behavior (#238)
github-actions[bot] May 1, 2026
e0c4098
feat: add Windows node text-to-speech (#253)
RBrid May 1, 2026
24dfd6a
feat: enhance device.status with system health sections (#249)
RBrid May 1, 2026
5be08f4
Support stored device-token node startup
shanselman May 1, 2026
a794d5f
Honor paired node state during tray startup
shanselman May 1, 2026
4966186
feat: add structural validation for system.run approvals
AlexAlves87 May 1, 2026
871b959
Fix onboarding theme backgrounds
shanselman May 2, 2026
acf44e1
feat: unified Hub window with NavigationView, slim tray menu, and inl…
ranjeshj May 1, 2026
502b8a8
fix: settings validation, CSS sidebar hiding, toggle labels, and SSH …
ranjeshj May 1, 2026
e9d8bcb
feat: full native UI with 12 pages, config editor, dual connection, a…
ranjeshj May 2, 2026
7998a92
UX Round 2: Agent events, discovery, pairing, models, presence, menu …
ranjeshj May 2, 2026
59fed00
Restructure navigation: agents as hierarchical nav items under Gateway
ranjeshj May 2, 2026
0b48126
UX Round 3: Hearth redesign, hierarchical nav, command palette, agent…
ranjeshj May 3, 2026
f8f0482
feat(tray): add rich session tooltips and connected devices section
ranjeshj May 3, 2026
4b33948
Redesign session and device tray menu with rich compact cards
ranjeshj May 3, 2026
7e64ec0
UX Round 4: Chat popup, rich tray menu, schema config editor
ranjeshj May 3, 2026
98c92fb
UX Round 5: Connection dashboard, tray polish, review fixes
ranjeshj May 4, 2026
0e8815f
UX Round 6: Token bar ProgressBar, title bar search, MCP toggle
ranjeshj May 4, 2026
bf5985d
Fix session flyout to match device flyout style
ranjeshj May 4, 2026
2424ce5
UX Round 7: Nav restructure, App MCP, config editor, review fixes
ranjeshj May 4, 2026
5b455df
5-model adversarial review fixes + regression tests
ranjeshj May 4, 2026
87c8333
Tray menu: header redesign, dismiss fix, session reliability
ranjeshj May 4, 2026
fa78371
Connection UX: localhost probe, auth errors, token prompt, gateway sw…
ranjeshj May 4, 2026
3a01d2a
Prepare UX experiments branch for PR
RBrid May 5, 2026
3a4ddba
Fix MCP-only tray startup
RBrid May 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,6 @@ FodyWeavers.xsd
Output/
*.lscache
test_ws.py

# Local visual test output
visual-test-output/
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ If a command fails:
Notes:

- If a build/test is blocked by an environmental lock (for example running executable locking output assemblies), stop/close the locking process and rerun.
- Tray tests must isolate `SettingsManager` from real user settings. Do not use `new SettingsManager()` in tests unless the test intentionally reads `%APPDATA%\OpenClawTray\settings.json`; pass a temp settings directory or set `OPENCLAW_TRAY_DATA_DIR` before the test process starts.
- Do not claim completion without reporting validation results.
61 changes: 53 additions & 8 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ OpenClaw.Tray.Tests ──tests──▶ OpenClaw.Shared
|-----------|----------|---------|
| **Gateway Communication** | `OpenClaw.Shared/OpenClawGatewayClient.cs` | WebSocket client with protocol v3, reconnect/backoff logic |
| **Notification System** | `OpenClaw.Tray.WinUI/App.xaml.cs` | Event routing, toast notifications, classification |
| **WebView2 Integration** | `OpenClaw.Tray.WinUI/Windows/WebChatWindow.xaml.cs` | Embedded chat panel with lifecycle management |
| **WebView2 Integration** | `OpenClaw.Tray.WinUI/Windows/ChatWindow.xaml.cs` | Embedded chat panel with lifecycle management |
| **Tray Icon Management** | `OpenClaw.Tray.WinUI/Helpers/IconHelper.cs` | GDI handle management, dynamic icon generation |
| **Session Tracking** | `OpenClaw.Shared/OpenClawGatewayClient.cs` | Session state, activity tracking, polling |
| **Settings & Logging** | `OpenClaw.Tray.WinUI/Services/` | JSON settings persistence, file rotation logging |
Expand Down Expand Up @@ -285,7 +285,7 @@ Notifications are classified using two strategies:

### WebView2 Lifecycle

The `WebChatWindow` uses Microsoft Edge WebView2 for embedded web content:
The `ChatWindow` uses Microsoft Edge WebView2 for embedded web content:

**Initialization:**
1. WebView2 control created in XAML
Expand All @@ -299,7 +299,7 @@ Window Created → WebView2.EnsureCoreWebView2Async() → Navigate to Chat URL
```

**Key Design Decisions:**
- **Singleton pattern**: Only one WebChat window instance exists
- **Singleton pattern**: Only one chat window instance exists
- **Hidden instead of disposed**: Window is hidden when closed to preserve state
- **Separate user data folder**: Isolates cookies/storage from browser
- **Navigation guard**: Prevents accidental navigation away from chat
Expand Down Expand Up @@ -425,8 +425,8 @@ dotnet test --filter "FullyQualifiedName~AgentActivityTests"
```

**Test Coverage:**
- ✅ **478 tests** in `OpenClaw.Shared.Tests` — models, gateway client, exec approvals, capabilities, URL helpers, notification categorization, shell quoting
- ✅ **93 tests** in `OpenClaw.Tray.Tests` — menu display, menu positioning, settings round-trip, deep link parsing
- ✅ **1182 tests** in `OpenClaw.Shared.Tests` — models, gateway client, exec approvals, capabilities, URL helpers, notification categorization, shell quoting, MCP, device identity, and WinNode client coverage
- ✅ **388 tests** in `OpenClaw.Tray.Tests` — settings round-trip, deep link parsing, onboarding state, setup code decoder, gateway health/chat helpers, security validation, wizard step parsing, gateway discovery, localization validation
- ✅ All tests are pure unit tests (no network, no file system, no external dependencies)

See [tests/OpenClaw.Shared.Tests/README.md](tests/OpenClaw.Shared.Tests/README.md) for detailed test documentation.
Expand All @@ -441,7 +441,7 @@ You can test the UI and basic functionality without a running gateway:
3. Enter a dummy gateway URL (e.g., `ws://localhost:18789`)
4. The app will show "Disconnected" status but you can:
- Test the tray menu structure
- Open Settings dialog and configure preferences
- Open the Settings page and configure preferences
- Test auto-start functionality
- View logs

Expand Down Expand Up @@ -487,8 +487,8 @@ You can test the UI and basic functionality without a running gateway:
- Verify Windows toast notification appears (if enabled)
- Click toast → should open relevant UI

2. **Notification History**:
- Right-click tray → **Notification History**
2. **Activity / notification history**:
- Right-click tray → **Activity Stream** or **Notification History**
- Verify past notifications are listed
- Test filtering by category

Expand Down Expand Up @@ -747,6 +747,51 @@ gh run download <run-id> --repo shanselman/openclaw-windows-hub
- **Discussions**: [GitHub Discussions](https://github.com/shanselman/openclaw-windows-hub/discussions)
- **Documentation**: [OpenClaw Docs](https://docs.molt.bot)

## Developing & Testing the Onboarding Wizard

The onboarding wizard is a 6-screen flow built with OpenClaw's minimal FunctionalUI helper layer for declarative C# WinUI. The chat page uses a WebView2 overlay for visual consistency with the post-setup chat experience.

### Building

The WinUI project requires platform-specific build targets. Use the build script:

```bash
./build.ps1 -Project WinUI # Builds with correct -r win-x64 targets
```

Direct `dotnet build` without the script will fail with "WindowsAppSDKSelfContained requires a supported Windows architecture".

### Environment Variables

| Variable | Purpose |
|----------|---------|
| `OPENCLAW_FORCE_ONBOARDING=1` | Show onboarding wizard even if a token already exists |
| `OPENCLAW_SKIP_UPDATE_CHECK=1` | Skip the update dialog (useful during testing) |
| `OPENCLAW_LANGUAGE=fr-fr` | Override UI language (validated: en-us, fr-fr, nl-nl, zh-cn, zh-tw) |
| `OPENCLAW_GATEWAY_PORT=19001` | Override default gateway port for local dev |
| `OPENCLAW_VISUAL_TEST=1` | Enable automatic screenshot capture on page transitions |
| `OPENCLAW_VISUAL_TEST_DIR=path` | Output directory for visual test screenshots |

### Testing the Wizard Locally

1. Start a local gateway (e.g., in WSL): `cd ~/openclaw && npx openclaw gateway`
2. Set env vars:
```powershell
$env:OPENCLAW_FORCE_ONBOARDING = "1"
$env:OPENCLAW_SKIP_UPDATE_CHECK = "1"
```
3. Build and run: `./build.ps1 -Project WinUI` then launch the exe
4. Navigate through all 6 screens to verify

### Architecture

- **FunctionalUI**: `src/OpenClawTray.FunctionalUI/` — Minimal declarative WinUI helper layer used by onboarding
- **Pages**: `src/OpenClaw.Tray.WinUI/Onboarding/Pages/` — Functional UI components for each wizard screen
- **Services**: `src/OpenClaw.Tray.WinUI/Onboarding/Services/` — State management, setup code decoder, permission checker, health check, input validation
- **Widgets**: `src/OpenClaw.Tray.WinUI/Onboarding/Widgets/` — Shared UI components (cards, step indicators, feature rows)
- **Window**: `src/OpenClaw.Tray.WinUI/Onboarding/OnboardingWindow.cs` — Host window with WebView2 overlay for chat
- **Helpers**: `src/OpenClaw.Tray.WinUI/Helpers/GatewayChatHelper.cs` — Shared WebView2 chat URL builder

---

*Made with 🦞 love by Scott Hanselman and the OpenClaw community*
73 changes: 43 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,14 @@ Modern Windows 11-style system tray companion that connects to your local OpenCl
- 🌐 **Web Chat** - Embedded chat window with WebView2
- 📊 **Live Status** - Real-time sessions, channels, and usage display
- 🧭 **Command Center** - Dense gateway, channel, usage, node, pairing, and allowlist diagnostics from one window
- ⚡ **Activity Stream** - Dedicated flyout for live session, usage, node, and notification events
- ⚡ **Activity Stream** - Command Center page for live session, usage, node, and notification events
- 🔔 **Toast Notifications** - Clickable Windows notifications with [smart categorization](docs/NOTIFICATION_CATEGORIZATION.md)
- 📡 **Channel Control** - Start/stop Telegram & WhatsApp from the menu
- 🖥️ **Node Observability** - Node inventory with online/offline state and copyable summary
- ⏱ **Cron Jobs** - Quick access to scheduled tasks
- 🚀 **Auto-start** - Launch with Windows
- ⚙️ **Settings** - Full configuration dialog
- 🎯 **First-run experience** - Welcome dialog guides new users
- ⚙️ **Settings** - Full configuration page
- 🎯 **First-run onboarding** — 6-screen setup wizard (connection, permissions, chat, configuration)

#### Quick Send scope requirement

Expand All @@ -123,7 +123,7 @@ If Quick Send fails with `pairing required` / `NOT_PAIRED`, that is a **device a

### Menu Sections
- **Status** - Gateway connection status with click-to-view details
- **Command Center** - Status detail window with diagnostics, channel health, usage, sessions, nodes, and copyable repair commands
- **Command Center** - Hub with diagnostics, channel health, usage, sessions, nodes, and copyable repair commands
- **Sessions** - Active agent sessions with preview and per-session controls
- **Usage** - Provider/cost summary with quick jump to activity details
- **Channels** - Telegram/WhatsApp status with toggle control
Expand Down Expand Up @@ -164,7 +164,7 @@ These features are available in Windows but not in the Mac app:
| Channel control | Start/stop Telegram & WhatsApp |
| Modern flyout menu | Windows 11-style with dark/light mode |
| Deep links | `openclaw://` URL scheme with IPC |
| First-run welcome | Guided onboarding for new users |
| First-run onboarding | 6-screen guided setup wizard (Welcome → Connection → Wizard → Permissions → Chat → Ready) |
| PowerToys integration | Command Palette extension |

### 🔌 Node Mode (Agent Control)
Expand All @@ -179,6 +179,9 @@ When Node Mode is enabled in Settings, your Windows PC becomes a **node** that t
| **Camera** | `camera.list`, `camera.snap`, `camera.clip` | Enumerate cameras and capture still photos or short video clips |
| **Location** | `location.get` | Return Windows geolocation when permission is available |
| **Device** | `device.info`, `device.status` | Return Windows host/app metadata and lightweight status |
| **Text-to-speech** | `tts.speak` | Speak text aloud through Windows speech synthesis, or ElevenLabs when configured |

Packaged installs declare camera, microphone, and location capabilities. Windows may ask for consent the first time a node capability uses one of those protected resources.

#### Node Setup

Expand All @@ -205,23 +208,24 @@ When Node Mode is enabled in Settings, your Windows PC becomes a **node** that t
"canvas.hide",
"canvas.navigate",
"canvas.eval",
"canvas.snapshot",
"canvas.a2ui.push",
"canvas.a2ui.pushJSONL",
"canvas.a2ui.reset",
"screen.snapshot",
"camera.list",
"camera.snap",
"camera.clip",
"location.get",
"device.info",
"device.status"
"canvas.snapshot",
"canvas.a2ui.push",
"canvas.a2ui.pushJSONL",
"canvas.a2ui.reset",
"screen.snapshot",
"camera.list",
"camera.snap",
"camera.clip",
"location.get",
"device.info",
"device.status",
"tts.speak"
]
}
}
}
}
}
```
> ⚠️ **Important**: The gateway has a server-side allowlist. Commands must be listed explicitly - wildcards like `canvas.*` don't work! Privacy-sensitive commands such as `screen.record` should only be added to `allowCommands` when you explicitly want to allow them.
> ⚠️ **Important**: The gateway has a server-side allowlist. Commands must be listed explicitly - wildcards like `canvas.*` don't work! Privacy-sensitive commands such as `screen.record` and agent-driven audio playback via `tts.speak` should only be added to `allowCommands` when you explicitly want to allow them.

5. **Test it** from your Mac/gateway:
```bash
Expand Down Expand Up @@ -249,6 +253,9 @@ When Node Mode is enabled in Settings, your Windows PC becomes a **node** that t
# Take a photo (NV12/MediaCapture fallback)
openclaw nodes invoke --node <id> --command camera.snap --params '{"deviceId":"<device-id>","format":"jpeg","quality":80}'

# Speak text aloud on the Windows node (requires TTS enabled in Settings and tts.speak allowed on the gateway)
openclaw nodes invoke --node <id> --command tts.speak --params '{"text":"Hello from OpenClaw","provider":"windows"}'

# Execute a command on the Windows node
openclaw nodes invoke --node <id> --command system.run --params '{"command":"Get-Process | Select -First 5","shell":"powershell","timeoutMs":10000}'

Expand Down Expand Up @@ -294,12 +301,12 @@ OpenClaw registers the `openclaw://` URL scheme for automation and integration:

| Link | Description |
|------|-------------|
| `openclaw://settings` | Open Settings dialog |
| `openclaw://settings` | Open the Settings page |
| `openclaw://setup` | Open Setup Wizard |
| `openclaw://chat` | Open Web Chat window |
| `openclaw://chat` | Open the Chat page |
| `openclaw://commandcenter` | Open Command Center diagnostics |
| `openclaw://activity` | Open Activity Stream |
| `openclaw://history` | Open Notification History |
| `openclaw://activity` | Open the Activity page |
| `openclaw://history` | Open the Activity page filtered to notification history |
| `openclaw://dashboard` | Open Dashboard in browser |
| `openclaw://dashboard/sessions` | Open specific dashboard page |
| `openclaw://dashboard/channels` | Open Channels dashboard page |
Expand Down Expand Up @@ -336,15 +343,15 @@ PowerToys Command Palette extension for quick OpenClaw access.
- **📡 Dashboard: Channels** - Open the channel configuration dashboard
- **🧩 Dashboard: Skills** - Open the skills dashboard
- **⏱️ Dashboard: Cron** - Open the scheduled jobs dashboard
- **💬 Web Chat** - Open the embedded Web Chat window
- **💬 Web Chat** - Open the embedded Chat page
- **📝 Quick Send** - Open the Quick Send dialog to compose a message
- **🧭 Setup Wizard** - Open pairing/setup
- **🧭 Command Center** - Open diagnostics and support actions
- **🔄 Run Health Check** - Refresh connection health
- **⬇️ Check for Updates** - Run a manual GitHub Releases update check
- **⚡ Activity Stream** - Open recent activity
- **📋 Notification History** - Open notification history
- **⚙️ Settings** - Open the OpenClaw Tray Settings dialog
- **📋 Notification History** - Open notification history in the Activity page
- **⚙️ Settings** - Open the OpenClaw Tray Settings page
- **📄 Open Log File / 📁 Logs / 🗂️ Config / 🧪 Diagnostics** - Open support files and folders
- **📋 Copy Support Context** - Copy redacted Command Center metadata
- **🧰 Copy Debug Bundle** - Copy combined support, port, capability, node, channel, and activity diagnostics
Expand Down Expand Up @@ -402,10 +409,16 @@ Default gateway: `ws://localhost:18789`

### First Run

On first run without a token, Molty displays a welcome dialog that:
1. Explains what's needed to get started
2. Links to [documentation](https://docs.molt.bot/web/dashboard) for token setup
3. Opens Settings to configure the connection
On first run, Molty launches a guided onboarding wizard that walks you through setup:

1. **Welcome** — introduces OpenClaw and starts the setup flow
2. **Connection** — choose Local gateway, Remote gateway, or configure later. Paste a setup code or enter gateway URL and token manually. Tests the connection with Ed25519 device authentication.
3. **Wizard** — gateway-driven configuration steps (AI provider selection, personality setup, communication channels). Steps are defined by your gateway.
4. **Permissions** — reviews Windows system permissions (notifications, camera, microphone, screen capture, location) and links to system settings to grant them.
5. **Chat** — meet your agent in a live chat powered by the gateway's web UI.
6. **Ready** — summary of available features, option to launch at startup, and a Finish button.

For detailed setup instructions, see [docs/SETUP.md](docs/SETUP.md). For the full onboarding architecture, see [docs/ONBOARDING_WIZARD.md](docs/ONBOARDING_WIZARD.md).

## License

Expand Down
5 changes: 3 additions & 2 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#>

param(
[ValidateSet("All", "Tray", "WinUI", "Shared", "CommandPalette", "Cli")]
[ValidateSet("All", "Tray", "WinUI", "Shared", "CommandPalette", "Cli", "WinNodeCli")]
[string]$Project = "All",

[ValidateSet("Debug", "Release")]
Expand Down Expand Up @@ -188,12 +188,13 @@ function Build-Project($name, $path, $useRid = $false) {
$projects = @{
"Shared" = @{ Path = "src/OpenClaw.Shared/OpenClaw.Shared.csproj"; UseRid = $false }
"Cli" = @{ Path = "src/OpenClaw.Cli/OpenClaw.Cli.csproj"; UseRid = $false }
"WinNodeCli" = @{ Path = "src/OpenClaw.WinNode.Cli/OpenClaw.WinNode.Cli.csproj"; UseRid = $false }
"Tray" = @{ Path = "src/OpenClaw.Tray.WinUI/OpenClaw.Tray.WinUI.csproj"; UseRid = $true }
"WinUI" = @{ Path = "src/OpenClaw.Tray.WinUI/OpenClaw.Tray.WinUI.csproj"; UseRid = $true }
"CommandPalette" = @{ Path = "src/OpenClaw.CommandPalette/OpenClaw.CommandPalette.csproj"; UseRid = $false }
}

$toBuild = if ($Project -eq "All") { @("Shared", "Cli", "WinUI") } else { @($Project) }
$toBuild = if ($Project -eq "All") { @("Shared", "Cli", "WinNodeCli", "WinUI") } else { @($Project) }

# Always build Shared first if building other projects
if ($Project -ne "Shared" -and $Project -ne "All" -and $toBuild -notcontains "Shared") {
Expand Down
Loading