# why
this PR addresses parity gaps in local launch behaviour:
- the TypeScript and Go SDKs already waited for a newly launched Chrome
process to expose a usable CDP endpoint, detected early process exit, &
cleaned up owned resources when launch failed.
- the Python SDK returned immediately after spawning Chrome & had
narrower executable discovery, profile setup, cancellation, &
process-tree shutdown behavior
Go & Python also accepted an explicit debugging port without first
proving it was available. that could let launch continue toward a
browser endpoint the SDK did not own
# what changed
- added a default Chrome flag fixture & made all three SDK test suites
compare their local flag lists against it
- added cross SDK contract coverage for launch argument ordering,
`about:blank`, viewport behavior, & profile ownership
- refactored the Python local launcher into focused validation,
executable discovery, profile, readiness, & shutdown helpers
- aligned Python Chrome discovery with TypeScript & Go:
- explicit executable then `CHROME_PATH` then platform candidates
- Chrome Canary, Stable, Beta, & Chromium on macOS
- Canary & Stable across the standard Windows roots
- the shared Chrome & Chromium executable order on Linux
- validate Python launch options & explicit executables before creating
a profile or spawning Chrome
- create caller-provided Python profile directories recursively while
preserving caller ownership
- wait for a successful `/json/version` response with a non-empty
`webSocketDebuggerUrl` before a Python launch resolves
- race Python readiness against browser exit & initialization
cancellation, then terminate the owned process & remove its temporary
profile when launch does not complete
- added explicit loopback port availability checks to the Python & Go
launchers before profile creation or process spawn
- return a focused occupied-port error instead of adopting or continuing
toward an existing browser, while preserving other socket failures
- aligned Python shutdown with the TypeScript & Go launchers:
- automatically disable the Chromium sandbox for Linux root
- terminate Unix process groups with graceful then forced signals
- terminate Windows process trees with `taskkill /T` then `/F`
- share one close task across concurrent callers
- continue profile cleanup after shutdown failures & preserve combined
errors
# test plan
- [x] Verify all three SDKs use the same static default Chrome flags,
argument ordering, starting URL, viewport behavior, & profile ownership
contract.
- [x] Verify Python option validation, explicit executable precedence,
`CHROME_PATH`, complete platform discovery order, unsupported platforms,
& caller profile creation.
- [x] Verify Python waits for a valid CDP version response, rejects
malformed readiness responses, detects early browser exit, & cleans up
after spawn failure or cancellation.
- [x] Verify Python & Go automatic port selection, occupied
explicit-port rejection before resource creation, & preservation of
non-occupancy socket errors.
- [x] Verify Python Linux-root sandbox behavior, Unix graceful & forced
process-group termination, Windows tree termination, already-exited
processes, concurrent close, & combined cleanup errors
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Closes local browser-launching parity gaps across the Python, Go, and
TypeScript SDKs. Python previously returned after spawning Chrome and
could leave failed launches behind; it now waits for a usable CDP
endpoint, while Python and Go reject occupied debugging ports and all
SDKs treat empty profile paths as omitted.
**Bug Fixes**
- Python validates launch options, executable paths, and explicit ports
before creating profiles or spawning Chrome; explicit ports must be
between 1 and 65535.
- Python Chrome discovery now follows the same precedence and platform
candidate order as Go and TypeScript.
- Caller-owned Python profiles are created recursively and preserved,
while SDK-owned temporary profiles are removed after failures,
cancellation, or close.
- Python disables the Chromium sandbox for Linux root and shuts down
process groups or Windows process trees with graceful-then-forced
termination.
- Concurrent Python closes share one cleanup task, and shutdown
continues profile cleanup while reporting combined errors.
- Go checks loopback port availability before profile creation and
preserves non-occupancy socket errors.
**Tests**
- Shared fixtures and cross-SDK contract tests cover default flags,
argument ordering, startup URL, viewport behavior, port handling, and
profile ownership.
<sup>Written for commit a7bccfa92f8f445d6ffcd8d6a143915faefdffac.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/2864?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->