Description
In local mode, with_options() / copy() reuses the existing HTTP client but constructs a new SeaServerManager. A request made through the derived client therefore launches a second local Stagehand server instead of reusing the original one.
This is especially problematic for the documented one-shot pattern client.with_options(...).sessions.start(...): the temporary derived client has no finalizer that closes its SEA manager, so its child process can remain alive until interpreter exit.
Reproduction
from stagehand import Stagehand
client = Stagehand(
server=local,
model_api_key=test,
_local_stagehand_binary_path=/path/to/stagehand-binary,
)
derived = client.with_options(max_retries=3)
print(client._client is derived._client) # True
print(client._sea_server is derived._sea_server) # False
# Each of these can start a different SEA child process.
client.sessions.start(model_name=openai/gpt-5-nano, browser={type: local})
derived.sessions.start(model_name=openai/gpt-5-nano, browser={type: local})
Code references
src/stagehand/_client.py:258 and src/stagehand/_client.py:549: sync/async copy()
src/stagehand/_client.py:316 and src/stagehand/_client.py:607: local settings are copied, but not manager ownership
src/stagehand/_custom/sea_server.py:317: every local client construction creates a new SeaServerManager
Expected behavior
A derived client with unchanged local-server configuration should reuse the same managed SEA process (with safe shared ownership), or its independently created process should have deterministic lifecycle cleanup.
Actual behavior
The HTTP connection pool is shared, but the local server manager is not. Derived clients can launch duplicate processes and temporary derived clients can orphan them.
Why this matters
with_options() is the documented per-request configuration mechanism. Repeated use in local mode can consume ports, memory, and browser processes, and requests that appear to target one local server can be split across multiple servers.
Prior-art check
I searched open/closed issues and PRs for local-mode cloning, with_options, and SEA process reuse and found no existing report. PR #335 addresses blocking async process management, not manager sharing across cloned clients.
Description
In local mode,
with_options()/copy()reuses the existing HTTP client but constructs a newSeaServerManager. A request made through the derived client therefore launches a second local Stagehand server instead of reusing the original one.This is especially problematic for the documented one-shot pattern
client.with_options(...).sessions.start(...): the temporary derived client has no finalizer that closes its SEA manager, so its child process can remain alive until interpreter exit.Reproduction
Code references
src/stagehand/_client.py:258andsrc/stagehand/_client.py:549: sync/asynccopy()src/stagehand/_client.py:316andsrc/stagehand/_client.py:607: local settings are copied, but not manager ownershipsrc/stagehand/_custom/sea_server.py:317: every local client construction creates a newSeaServerManagerExpected behavior
A derived client with unchanged local-server configuration should reuse the same managed SEA process (with safe shared ownership), or its independently created process should have deterministic lifecycle cleanup.
Actual behavior
The HTTP connection pool is shared, but the local server manager is not. Derived clients can launch duplicate processes and temporary derived clients can orphan them.
Why this matters
with_options()is the documented per-request configuration mechanism. Repeated use in local mode can consume ports, memory, and browser processes, and requests that appear to target one local server can be split across multiple servers.Prior-art check
I searched open/closed issues and PRs for local-mode cloning,
with_options, and SEA process reuse and found no existing report. PR #335 addresses blocking async process management, not manager sharing across cloned clients.