Skip to content

[Bug] Desktop app hangs on macOS due to interactive shell flag (-i) in sidecar spawn #15050

@kilhyeonjun

Description

@kilhyeonjun

Description

The OpenCode Desktop app (Tauri-based) gets stuck on the "Starting server..." loading screen on macOS. The root cause is the -i (interactive) flag used when spawning the sidecar CLI process.

Root Cause

In packages/desktop/src-tauri/src/lib.rs (around line 134-145), the sidecar is spawned via:

app.shell().command(&shell)
  .args(["-il", "-c", &format!("\"{}\" serve --port={}", sidecar.display(), port)])

The -i flag forces interactive mode, which causes zsh to:

  1. Load ~/.zshrc (oh-my-zsh, themes, plugins)
  2. Initialize ZLE (Zsh Line Editor) hooks
  3. Set up prompt rendering, syntax highlighting, autosuggestions

Since the desktop app has no TTY (it's a GUI process), ZLE-dependent plugins like zsh-syntax-highlighting and zsh-autosuggestions hang indefinitely during initialization — they expect terminal I/O that doesn't exist.

Reproduction

# This works (non-interactive):
zsh -c "/Applications/OpenCode.app/Contents/MacOS/opencode-cli debug config"

# This works (login only, no interactive):
zsh -lc "/Applications/OpenCode.app/Contents/MacOS/opencode-cli debug config"

# This HANGS (interactive + login):
zsh -il -c "/Applications/OpenCode.app/Contents/MacOS/opencode-cli debug config"

Environment

  • OS: macOS Sequoia (Apple Silicon)
  • OpenCode Desktop: v1.2.13
  • Shell: /bin/zsh with oh-my-zsh + zsh-syntax-highlighting + zsh-autosuggestions (extremely common setup)
  • Theme: agnoster

Desktop App Logs (failing)

INFO opencode_lib: Initializing app
INFO opencode_lib: Main and loading windows created
INFO opencode_lib: Setting up server connection
INFO opencode_lib::cli: CLI is up to date, skipping sync
← Stops here. Never reaches "Attempting server connection"

Suggested Fix

Change the shell invocation from -il to -lc:

// Before (hangs when user has ZLE plugins):
.args(["-il", "-c", &format!("\"{}\" serve --port={}", sidecar.display(), port)])

// After (login shell for PATH, but no interactive mode):
.args(["-lc", &format!("\"{}\" serve --port={}", sidecar.display(), port)])

The -l (login) flag is sufficient to load ~/.zprofile for PATH setup (Homebrew, nvm, etc.). The -i flag is unnecessary for a non-interactive subprocess and actively harmful in a no-TTY environment.

Related Issues

Workaround

Users can add TTY guards to their ~/.zshrc to prevent blocking in non-TTY environments:

# Before oh-my-zsh theme/plugin setup:
if [[ -t 0 ]]; then
  plugins=(git zsh-syntax-highlighting zsh-autosuggestions)
else
  plugins=(git)
fi

But this is a workaround — the app should not require users to modify their shell configuration.

Metadata

Metadata

Assignees

Labels

webRelates to opencode on web / desktop

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions