Skip to content

feat: add --headed to device boot - #565

Merged
gmegidish merged 5 commits into
mainfrom
feat/boot-headed
Nov 13, 2026
Merged

gmegidish merged 5 commits into
mainfrom
feat/boot-headed

Conversation

@mobile-kevin

@mobile-kevin mobile-kevin commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #536

What changed

mobilecli device boot takes a --headed flag, named as in Playwright. The JSON-RPC device.boot method takes an optional headed boolean.

  • Default is unchanged. Without the flag the device boots with no window, as before.
  • Android emulator: --headed leaves out -qt-hide-window.
  • iOS simulator: --headed shows the simulator's window after the boot, using the app that ships with the selected Xcode (xcode-select -p):
    • Xcode 26 and earlier: opens Simulator.app on the device.
    • Xcode 27, which has no Simulator.app: opens the device's window in Device Hub through devices://device/open?id=<udid>.

Out of scope

  • Showing the window of a device that is already running. device boot on a running device still returns "already running".
  • Remote devices ignore the flag.
  • No fallback when --headed is used on a host with no display. The emulator's own error is returned.

Things to know when reviewing

  • If the window cannot be shown (for example over SSH with no GUI session), boot --headed returns an error that says the simulator booted but its window could not be shown. The simulator stays booted.
  • On Xcode 27, quitting Device Hub shuts down the booted simulators. That is Device Hub's behaviour, not something this PR does.
  • SimulatorDevice.Boot now shares one bootstatus wait between the "already booting" and normal paths, so --headed applies to both. The only other difference is that the "already booting" error text now includes the UDID.
  • docs/openrpc.md was edited by hand to match docs/openrpc.json; make docs was not run.
  • CHANGELOG is not touched; it is left for the release PR.

Testing

  • go build ./..., go vet ./..., go test ./... -race pass. golangci-lint run --new-from-rev=origin/main reports 0 issues.
  • New unit tests: emulator arguments with and without headed, and headed in the boot request.
  • Live on macOS: Pixel_6 with --headed started without -qt-hide-window, and without the flag started with it. An iPhone 17 simulator booted with --headed on Xcode 26.0.1 and returned ok; the Simulator.app window was not confirmed by an automated check.
  • Xcode 27.1: the devices://device/open?id=<udid> URL was confirmed by hand to open the simulator's window, with Device Hub running and from quit. The final commit that uses it has not been run on Xcode 27 yet.
  • New unit tests for the choice between Simulator.app and Device Hub.

Summary by CodeRabbit

  • New Features
    • Boot emulators and simulators with a visible window using the new --headed option. Without it, booting remains windowless by default.
    • The boot option is also available through the device boot request.
  • Bug Fixes
    • Simulator boot now waits for an in-progress startup instead of issuing another boot command, and reports boot failures with the simulator’s identifier.

@coderabbitai

coderabbitai Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

  • Run on-demand review

This review includes 12 billable files and costs up to $3.00.

Or wait 24 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration

Commits

Reviewing files that changed from the base of the PR and between a7209f3 and 96ef907.

Files ignored due to path filters: 6

  • README.ja.md is excluded by !**/*.md
  • README.md is excluded by !**/*.md
  • README.zh-CN.md is excluded by !**/*.md
  • docs/openrpc.json is excluded by !docs/**
  • docs/openrpc.md is excluded by !**/*.md, !docs/**
  • skills/mobilecli/reference.md is excluded by !**/*.md
Files selected for processing: 12

  • cli/device.go
  • cli/root.go
  • commands/boot.go
  • commands/boot_test.go
  • devices/android.go
  • devices/android_boot_test.go
  • devices/common.go
  • devices/ios.go
  • devices/remote.go
  • devices/simulator.go
  • devices/simulator_window_test.go
  • server/server.go

No actionable comments were generated in the recent review.

Walkthrough

The device boot flow now accepts a --headed option. Android emulators show their window when enabled, and iOS simulators open Simulator.app. Boot requests default to windowless behavior.

Changes: Headed device boot

Layer / File(s) Summary
Boot option and request flow
devices/common.go, commands/boot.go, server/server.go, cli/device.go, cli/root.go, commands/boot_test.go, devices/ios.go, devices/remote.go
BootOptions carries the headed value through the device interface and boot request. The CLI registers --headed, and tests cover omitted and true JSON values. iOS and remote boot methods accept the updated signature.
Android emulator window control
devices/android.go, devices/android_boot_test.go
Android emulator arguments retain the AVD and network settings. The -qt-hide-window argument is included only when headed is false. Tests cover both window modes and AVD targeting.
iOS simulator boot and window control
devices/simulator.go
Simulator boot waits for boot status when already booting, updates state on success, and opens Simulator.app when headed is true. Boot errors include the simulator UDID.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant handleDeviceBoot
  participant BootCommand
  participant Device
  CLI->>handleDeviceBoot: send headed boot request
  handleDeviceBoot->>BootCommand: pass Headed in BootRequest
  BootCommand->>Device: call Boot with BootOptions
Loading

Suggested reviewers: gmegidish

Merge Risk: Minimal · previous review a7209

Adds an opt-in --headed flag to device boot. Default behavior is unchanged, and the change is mergeable. Whether Simulator.app opens correctly on hosts with several Xcode installations was not verified.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title "feat: add --headed to device boot" names the main change. The PR adds a --headed flag to mobilecli device boot, and the changeset implements it across the CLI, the JSON-RPC server, and the …
Linked Issues check Passed [#536] requests a --headed option for device boot. Android emulators must omit -qt-hide-window. iOS simulators must open Simulator.app.

Implementation at the reviewed head, per the whole-PR sum…
Out of Scope Changes check Passed The changes map to the #536 objective, or they support it:
- CLI flag, RPC parameter, and command help: direct implementation of the requested option.
- BootOptions and the Boot(opts BootOptions) …
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Full details: Title check

Explanation

The title "feat: add --headed to device boot" names the main change. The PR adds a --headed flag to mobilecli device boot, and the changeset implements it across the CLI, the JSON-RPC server, and the device backends (Android emulator args, iOS Simulator.app). The title is short, specific, and follows a conventional commit style. It omits the Android and iOS behavior, which is acceptable for a title.

Full details: Linked Issues check

Explanation

[#536] requests a --headed option for device boot. Android emulators must omit -qt-hide-window. iOS simulators must open Simulator.app.

Implementation at the reviewed head, per the whole-PR summary:

  • cli/device.go adds a --headed flag (default false) and passes it in commands.BootRequest.
  • commands/boot.go adds Headed bool to BootRequest and passes it to Device.Boot through devices.BootOptions.
  • server/server.go adds an optional headed field to DeviceBootParams and forwards it.
  • devices/android.go builds emulator arguments with emulatorBootArgs. It adds -qt-hide-window only when Headed is false. This meets the Android requirement.
  • devices/simulator.go opens Simulator.app for the device when opts.Headed is true. This meets the iOS requirement.
  • devices/ios.go and devices/remote.go accept BootOptions and ignore it. This keeps the default and remote behavior unchanged.

Tests:

  • devices/android_boot_test.go covers emulator arguments with and without headed.
  • commands/boot_test.go covers headed in the boot request.
  • No automated test covers the iOS Simulator.app path. The issue does not require one. The PR states the Simulator.app window was not confirmed by an automated check.

All coding requirements of #536 are implemented. No unmet coding requirement is visible.

Full details: Out of Scope Changes check

Explanation

The changes map to the #536 objective, or they support it:

  • CLI flag, RPC parameter, and command help: direct implementation of the requested option.
  • BootOptions and the Boot(opts BootOptions) signature changes across ControllableDevice, Android, iOS, remote, and simulator: needed to pass the flag to each device type.
  • SimulatorDevice.Boot shares one bootstatus wait between the "already booting" and normal paths: needed so --headed applies on both paths. The PR description discloses this.
  • The "already booting" error text now includes the UDID: a small, disclosed change in the same function. It does not alter the #536 behavior. It is minor and does not justify a FAIL.
  • Root command example for device boot --headed: documentation of the new flag.
  • Documentation changes (docs/openrpc.*, reference files) are excluded from this review. No verdict depends on them.

No demonstrated change is unrelated to #536.

Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between c7045fe and a7209f3.

Files ignored due to path filters: 6

  • README.ja.md is excluded by !**/*.md
  • README.md is excluded by !**/*.md
  • README.zh-CN.md is excluded by !**/*.md
  • docs/openrpc.json is excluded by !docs/**
  • docs/openrpc.md is excluded by !**/*.md, !docs/**
  • skills/mobilecli/reference.md is excluded by !**/*.md
Files selected for processing: 11

  • cli/device.go
  • cli/root.go
  • commands/boot.go
  • commands/boot_test.go
  • devices/android.go
  • devices/android_boot_test.go
  • devices/common.go
  • devices/ios.go
  • devices/remote.go
  • devices/simulator.go
  • server/server.go

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

@mobile-kevin
mobile-kevin marked this pull request as draft November 12, 2026 11:40
device boot keeps booting without a window by default. --headed (and
headed: true on the device.boot JSON-RPC method) leaves out
-qt-hide-window on Android emulators and opens Simulator.app on iOS
simulators.

Fixes #536
Xcode 27 ships DeviceHub.app instead of Simulator.app. The app is looked up
inside the selected Xcode, the same one simctl uses.
Device Hub opens on its last selected device. The devices://device/open URL
opens a window for the simulator that was booted.
@mobile-kevin
mobile-kevin marked this pull request as ready for review November 13, 2026 12:32
@gmegidish
gmegidish merged commit 9a8d744 into main Nov 13, 2026
15 checks passed
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.

Add --headed to device boot for emulators and simulators

2 participants