10 KiB
Gateway Dev Runbook
This runbook covers the XWorkmate.svc.plus client when it connects to the managed bridge / remote gateway path for pairing approval and release verification.
Local gateway / loopback is no longer an app-facing runtime mode for account sync, bridge startup, or task dialog send flow.
Scope
- UI repo:
/Users/shenlan/workspaces/cloud-neutral-toolkit/XWorkmate.svc.plus - Gateway repo:
/Users/shenlan/workspaces/cloud-neutral-toolkit/openclaw.svc.plus - macOS reference implementation:
/Users/shenlan/workspaces/cloud-neutral-toolkit/openclaw.svc.plus/apps/macos/Sources/OpenClaw/GatewayEndpointStore.swift/Users/shenlan/workspaces/cloud-neutral-toolkit/openclaw.svc.plus/apps/macos/Sources/OpenClaw/GatewayRemoteConfig.swift/Users/shenlan/workspaces/cloud-neutral-toolkit/openclaw.svc.plus/apps/macos/Sources/OpenClaw/DevicePairingApprovalPrompter.swift
Security Boundary
.envis development prefill only. It must not become the persisted source of truth and must not auto-connect the gateway.- Shared tokens and passwords are user-entered auth inputs. Never hardcode them in Dart, native code, tests, or scripts.
- Long-lived secrets belong in secure storage. XWorkmate also keeps a file-backed fallback for device identity and operator device token so release builds keep a stable paired identity.
- The app-facing bridge / gateway path is remote-only and must use TLS, for example
wss://openclaw.svc.plus:443. - Loopback endpoints must not be revived as runtime truth sources for account sync or task dialog startup.
Endpoint Matrix
- XWorkmate direct remote gateway auth:
wss://openclaw.svc.plus:443
- OpenClaw operator control page for pairing approval:
Do not enter loopback / local console URLs into the XWorkmate gateway dialog. The current app-level gateway connection is remote-only wss://.
Config Sources
- Development prefill file:
/Users/shenlan/workspaces/cloud-neutral-toolkit/XWorkmate.svc.plus/.env
- Persisted settings snapshot:
~/Library/Containers/plus.svc.xworkmate/Data/Library/Preferences/plus.svc.xworkmate.plist- key:
flutter.xworkmate.settings.snapshot
- File-backed stable device identity fallback:
~/Library/Containers/plus.svc.xworkmate/Data/Library/Application Support/plus.svc.xworkmate/xworkmate/gateway-auth/gateway-device-identity.json
- File-backed operator device token fallback:
~/Library/Containers/plus.svc.xworkmate/Data/Library/Application Support/plus.svc.xworkmate/xworkmate/gateway-auth/gateway-device-token.<deviceId>.operator.txt
Expected Remote Pairing Flow
- Open
设置 -> 集成 -> Gateway. - Choose
远程. - Enter host
openclaw.svc.plus, port443, TLS on. - Enter a valid shared token.
- Click
连接. - First successful auth should return
NOT_PAIRED: pairing required. - Open https://openclaw.svc.plus/nodes and approve the pending
XWorkmate Macdevice. - Return to XWorkmate and reconnect.
- The second connect should succeed and the gateway should return an operator
deviceToken. - Later reconnects should reuse the same
deviceIdand move todevice-tokenauth instead of creating a fresh pairing request.
Root Cause Analysis: Repeating pairing required
Symptom
- Remote shared-token auth reached the gateway, but remote connect repeatedly ended with
NOT_PAIRED: pairing required. - The operator page showed one
PendingXWorkmate Macentry and one olderPairedXWorkmate Macentry at the same time.
Evidence Pattern
Pending.deviceId != Paired.deviceId- Reconnecting from the same installed app generated a fresh pending request instead of reusing the already paired device.
- This proves the failure was not “approval missing” alone. The client was presenting a different device identity on later remote connects.
Why This Happened
OpenClaw pairing is keyed to the device identity:
device.iddevice.publicKey- signed device-auth payload
- pinned client metadata such as platform and device family
If the client does not persist and reload the same identity, the gateway must treat the connect as a new device and request pairing again.
The problematic path in XWorkmate was:
- Remote connect created or loaded a device identity.
- The identity and operator device token relied on secure storage only.
- In the installed app path, that persistence was not stable enough for repeated remote reconnect debugging.
- The next remote connect surfaced a different
deviceId, so the gateway created another pending pairing request.
Fix Strategy
Align XWorkmate with the OpenClaw macOS reference:
- Keep shared token and password in secure storage.
- Keep a stable file-backed fallback for:
- device identity
- operator device token
- Prefer secure storage on read, but hydrate from the fallback file when secure storage does not produce the identity/token.
- Show the current
deviceIdin the pairing-required UI so the operator can match it against the control page immediately.
Code Locations
- XWorkmate stable device identity and device token fallback:
/Users/shenlan/workspaces/cloud-neutral-toolkit/XWorkmate.svc.plus/lib/runtime/secure_config_store.dart
- XWorkmate local device identity model:
/Users/shenlan/workspaces/cloud-neutral-toolkit/XWorkmate.svc.plus/lib/runtime/runtime_models.dart
- XWorkmate pairing diagnostics banner:
/Users/shenlan/workspaces/cloud-neutral-toolkit/XWorkmate.svc.plus/lib/widgets/gateway_connect_dialog.dart
- OpenClaw macOS reference:
/Users/shenlan/workspaces/cloud-neutral-toolkit/openclaw.svc.plus/apps/macos/Sources/OpenClaw/GatewayEndpointStore.swift/Users/shenlan/workspaces/cloud-neutral-toolkit/openclaw.svc.plus/apps/shared/OpenClawKit/Sources/OpenClawKit/DeviceIdentity.swift
Fix Validation
After the fix:
- The app keeps a stable local
deviceId. - The first remote shared-token connect may still need one approval if the previously paired record belongs to an older rotating identity.
- After that approval, reconnect must reuse the same
deviceId. - The operator page should stop accumulating a new
Pendingrequest for each reconnect.
Pairing Loop Diagnosis
The critical check is whether Pending and Paired show the same deviceId.
- Healthy:
Pendingappears once on first shared-token connect.- After approval, reconnect succeeds.
- The same
deviceIdbecomesPaired.
- Broken:
Pendingkeeps showing a newdeviceId.Pairedalready contains an olderdeviceId.- XWorkmate reconnects as a different device each time and loops on
pairing required.
Fast Diagnosis Steps
- In XWorkmate, open the gateway dialog and read the error banner.
- Note the
当前设备 IDshown under pairing-required guidance. - In https://openclaw.svc.plus/nodes, compare that ID against:
PendingPaired
- If the IDs differ, the client is not reusing a stable local identity.
Local Reset For A Broken Pairing Loop
Run these steps only when the device ID keeps changing or the stored operator token is clearly stale:
rm -f "$HOME/Library/Containers/plus.svc.xworkmate/Data/Library/Application Support/plus.svc.xworkmate/xworkmate/gateway-auth/gateway-device-identity.json"
rm -f "$HOME/Library/Containers/plus.svc.xworkmate/Data/Library/Application Support/plus.svc.xworkmate/xworkmate/gateway-auth/gateway-device-token."*.operator.txt
Then:
- Remove stale paired
XWorkmate Macentries from the operator page if they are no longer valid. - Reopen XWorkmate.
- Connect with the shared token once.
- Approve the single new pending request.
- Reconnect and verify the same
deviceIdnow appears inPaired.
Common Error Meanings
AUTH_TOKEN_MISSING- The active handshake did not carry a shared token or device token.
- Check the current form input first, then stored secure refs.
CONNECT_CHALLENGE_TIMEOUT- Usually an invalid
ws/wssendpoint, reverse proxy mismatch, or malformed stored host value. - Confirm the final gateway target is
openclaw.svc.plus:443for remote mode.
- Usually an invalid
PAIRING_REQUIRED- Shared token auth succeeded, but the current device is not yet paired, or the gateway is treating the connect as a metadata or scope upgrade.
AUTH_DEVICE_TOKEN_MISMATCH- Local operator device token is stale or revoked.
- Clear the stored device token and reconnect once with the shared token.
Runtime Debugging
- XWorkmate UI:
设置 -> 运行日志- Check
connect,auth,socket, andpairingentries.
- macOS preferences snapshot:
defaults read "$HOME/Library/Containers/plus.svc.xworkmate/Data/Library/Preferences/plus.svc.xworkmate.plist"
- OpenClaw operator state:
- OpenClaw CLI on gateway host:
openclaw devices list
Do not paste real tokens into issues, commits, or logs.
Development Validation
Baseline checks:
flutter analyze
flutter test
macOS integration tests must run serially:
pkill -f '/build/macos/Build/Products/Debug/XWorkmate.app/Contents/MacOS/XWorkmate' || true
flutter test integration_test/desktop_navigation_flow_test.dart -d macos
pkill -f '/build/macos/Build/Products/Debug/XWorkmate.app/Contents/MacOS/XWorkmate' || true
flutter test integration_test/desktop_settings_flow_test.dart -d macos
Build and install:
flutter build macos
flutter build ios --simulator
make install-mac
If a device-run test hangs instead of failing with an assertion, record it as manual follow-up.
Manual Acceptance
- Verify remote mode can connect through
wss://openclaw.svc.plus:443. - Verify first remote connect creates one pending pairing request.
- Approve that request from https://openclaw.svc.plus/nodes.
- Reconnect and verify the same
deviceIdis now listed underPaired. - Restart the app and verify remote reconnect does not create a fresh pending request.