Skip to content

feat(windows): support remote host connection in standalone desktop app - #794

Open
jyuan-dev wants to merge 2 commits into
alphaXiv:mainfrom
jyuan-dev:feat/windows-standalone-remote-connection
Open

jyuan-dev wants to merge 2 commits into
alphaXiv:mainfrom
jyuan-dev:feat/windows-standalone-remote-connection

Conversation

@jyuan-dev

Copy link
Copy Markdown
Contributor

Closes #793

Summary

Enables the Windows standalone desktop app (OpenResearch.exe) to connect to a remote server running orx in the three-connection architecture (e.g. orx running on a local cluster/server while the Windows desktop app monitors and drives the session).

Key updates:

  • Windows Launcher argument forwarding: OpenResearch.exe now forwards arguments (std::env::args_os().skip(1)) to orx.exe app, enabling --remote <host>, --port, --model, and --no-agent via command line or desktop shortcuts.
  • Companion config & environment resolution: Supports companion OpenResearch.json / openresearch.json placed beside the executable, ORX_REMOTE / ORX_APP_REMOTE environment variables, and default_remote settings.
  • Independent instance mutex: Remote desktop sessions use a host-specific single-instance mutex (MUTEX_<clean_host>), allowing local and remote desktop windows to run simultaneously without conflict.
  • Desktop app lifecycle in remote gateway: In desktop app mode, up_remote::run keeps the gateway serving so the webview can display installation/update screens and responds to window close shutdown signals.
  • In-place webview navigation & custom SSH targets: Selecting or entering a remote host in desktop app mode navigates in-place within the desktop webview (window.location.href) instead of popping open the external system browser.
  • Relaxed host validation: Allows direct user@host connection strings and IP addresses in addition to SSH config aliases.
  • Documentation: Updated docs/windows.md with usage instructions for the three-connection scheme.

Test plan

  • Rust unit tests pass (cargo test --locked — 989 unit tests + integration test suites).
  • UI unit tests pass (node --test ui/tests/*.test.mjs — all 208 tests passing, including desktop in-place navigation and custom host tests).
  • Linters and formatters: cargo fmt --all --check, cargo fmt --manifest-path windows/launcher/Cargo.toml --check, and cargo clippy --all-targets -- -D warnings.
  • UI typecheck and style checks: pnpm --dir ui typecheck, node ui/scripts/check-i18n.mjs, and node ui/scripts/check-styles.mjs.
  • UI dist assets regenerated: pnpm --dir ui build.

Enable connecting to a remote server in the Windows standalone desktop
app (three-connection scheme).

- Forward CLI arguments in Windows launcher (OpenResearch.exe)
- Parse --remote, --port, --model, --no-agent in desktop app mode
- Support companion configuration (OpenResearch.json) and ORX_REMOTE
- Isolate remote desktop instances using host-specific single-instance mutex
- Support desktop app lifecycle in up_remote (serving gateway during install/update and handling shutdown signals)
- Navigate in-place within desktop webview and support custom SSH hosts in UI
- Update documentation and test suites
@greptile-apps

greptile-apps Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 3/5

[Medium impact] The changes affect the Windows desktop app and its remote SSH connection workflow.

Fix the Linux desktop build and add a way back to the local workspace before merging.

Findings

  1. P1 Linux desktop builds fail ▶
  2. P1 Remote page has no return ▶
  3. P2 Different hosts share one window ▶
  4. P2 Restart forgets the chosen model ▶
Fix with agent prompt
### Issue 1
src/commands/app.rs:265
`run()` now passes a remote host to `instance::claim()`, but the Linux implementation still takes no arguments. This prevents builds with `--features desktop` from compiling. Update the Linux signature and call together.

### Issue 2
ui/src/components/RemoteHostDialog.tsx:49
Opening a remote host now replaces the local desktop page, but the remote page has no way back. Disconnect only closes SSH and leaves the window on the remote setup screen. Users must close and reopen the app to reach local projects or choose another host. Preserve the local address and provide a return action.

### Issue 3
src/commands/app.rs:494-498
Replacing every punctuation mark with `_` gives different valid hosts the same mutex name. For example, `gpu-1` and `gpu_1` both become `gpu_1`. Launching the second host then focuses the first host's window and exits without connecting. Include a hash of the full target in the name.

### Issue 4
src/commands/app.rs:781
The newly supported `--model` argument is lost when a local Windows desktop app restarts after an update. The app passes it to `up::run()`, but the Windows restart still launches only `app`. Forward the original app arguments during restart so the chosen model remains in effect.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds remote connections to the standalone desktop app.

  • The Windows app can launch with a remote host and session settings.
  • The desktop window stays connected while its remote workspace starts.
  • The host picker can open custom destinations inside the desktop window.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Windows launcher] --> B[Parse app arguments]
  B --> C[Resolve remote host]
  C -->|Local| D[Local dashboard]
  C -->|Remote| E[SSH gateway]
  D --> F[Desktop webview]
  E --> F
  F -->|Choose remote host| E
  E --> G[Remote setup or workspace]
  G -->|Disconnect| H[Remote setup screen]
Loading

Reviews (1) · Last reviewed commit: "feat(windows): support remote host conne..." · Reviewed by Greptile

Comment thread src/commands/app.rs
// the claim (Linux relaunches by exec, which releases it).
crate::updates::await_replaced_parent();
match instance::claim() {
match instance::claim(effective_remote.as_deref()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Linux desktop builds fail

run() now passes a remote host to instance::claim(), but the Linux implementation still takes no arguments. This prevents builds with --features desktop from compiling. Update the Linux signature and call together.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/commands/app.rs
Line: 265

Comment:
**Linux desktop builds fail**

`run()` now passes a remote host to `instance::claim()`, but the Linux implementation still takes no arguments. This prevents builds with `--features desktop` from compiling. Update the Linux signature and call together.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment thread ui/src/components/RemoteHostDialog.tsx Outdated
locale: getLocale(),
}]);
if (remoteWindow) remoteWindow.location.replace(session.gatewayUrl);
else if (inDesktopApp) window.location.href = session.gatewayUrl;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Remote page has no return

Opening a remote host now replaces the local desktop page, but the remote page has no way back. Disconnect only closes SSH and leaves the window on the remote setup screen. Users must close and reopen the app to reach local projects or choose another host. Preserve the local address and provide a return action.

Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/components/RemoteHostDialog.tsx
Line: 49

Comment:
**Remote page has no return**

Opening a remote host now replaces the local desktop page, but the remote page has no way back. Disconnect only closes SSH and leaves the window on the remote setup screen. Users must close and reopen the app to reach local projects or choose another host. Preserve the local address and provide a return action.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment thread src/commands/app.rs Outdated
Comment on lines +494 to +498
let clean: String = r
.chars()
.map(|c| if c.is_alphanumeric() { c } else { '_' })
.collect();
(format!("{FOCUS_EVENT}_{clean}"), format!("{MUTEX}_{clean}"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Different hosts share one window

Replacing every punctuation mark with _ gives different valid hosts the same mutex name. For example, gpu-1 and gpu_1 both become gpu_1. Launching the second host then focuses the first host's window and exits without connecting. Include a hash of the full target in the name.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/commands/app.rs
Line: 494-498

Comment:
**Different hosts share one window**

Replacing every punctuation mark with `_` gives different valid hosts the same mutex name. For example, `gpu-1` and `gpu_1` both become `gpu_1`. Launching the second host then focuses the first host's window and exits without connecting. Include a hash of the full target in the name.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment thread src/commands/app.rs
// Dashboard server on background workers (we're inside main's runtime).
// Dashboard server / presentation gateway on background workers (we're inside main's runtime).
let remote_target = effective_remote.clone();
let app_model = app_args.model.clone();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Restart forgets the chosen model

The newly supported --model argument is lost when a local Windows desktop app restarts after an update. The app passes it to up::run(), but the Windows restart still launches only app. Forward the original app arguments during restart so the chosen model remains in effect.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/commands/app.rs
Line: 781

Comment:
**Restart forgets the chosen model**

The newly supported `--model` argument is lost when a local Windows desktop app restarts after an update. The app passes it to `up::run()`, but the Windows restart still launches only `app`. Forward the original app arguments during restart so the chosen model remains in effect.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

- Align Linux desktop instance::claim signature to accept remote host
- Include target token hash in instance mutex and socket names to avoid collision between distinct hosts
- Preserve command line arguments on Windows and Linux desktop app relaunch
- Preserve local workspace address when connecting to remote host in desktop app and provide return actions
- Add localization for return to local workspace across all supported languages
@jyuan-dev

Copy link
Copy Markdown
Contributor Author

All review feedback addressed in commit 378527a:

  1. Linux desktop builds: Updated instance::claim(remote: Option<&str>) and claim_paths(remote: Option<&str>) in src/commands/app.rs under Linux desktop mode to match the signature and incorporate the remote host token.
  2. Way back to local workspace:
    • Preserves local origin (local_origin query parameter and session storage) when navigating to a remote host in the standalone desktop app.
    • Added a "Return to local workspace" button on the remote setup, disconnected, connecting, updating, and gateway-unavailable screens (ui/src/RemoteRuntime.tsx).
    • Added a "Return to local workspace" action to the remote status popover menu (ui/src/components/RemoteStatus.tsx).
    • Localized remote_return_to_local across all 6 supported locales.
  3. Collision between different hosts:
    • Replaced plain punctuation replacement with host_target_token, appending a 16-hex-character SHA-256 hash of the full target (e.g. gpu_1_<hash>). Hosts like gpu-1 and gpu_1 now map to distinct mutex and socket names. Added unit test host_target_token_distinguishes_different_hosts_with_same_sanitized_name.
  4. Preserving arguments on desktop app restart:
    • Updated src/updates.rs on Windows to forward std::env::args_os().skip(1) (e.g. ["app", "--model", "..."]) instead of discarding all arguments with vec!["app"].
    • Also updated Linux app relaunch so AppImage and standalone binary both preserve trailing arguments on restart.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support remote host connection in Windows standalone desktop app

1 participant