Skip to content

[docs]: sync docs branch with main - #3151

Merged
seanmcguire12 merged 57 commits into
docs-productionfrom
sync-with-main
Oct 8, 2026
Merged

seanmcguire12 merged 57 commits into
docs-productionfrom
sync-with-main

Conversation

@seanmcguire12

@seanmcguire12 seanmcguire12 commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

why

  • to carry all changes from main into docs branch

Summary by cubic

Carries all changes from main into the docs branch so the docs tree matches the latest SDK releases, eval harness updates, and recent documentation additions (cookbooks, CLI agent guides, and new reference pages). This is a plain branch sync with no source changes of its own.

Written for commit 72c306d. Summary will update on new commits.

View guided diff Turn on auto-fix

shrey150 and others added 30 commits September 24, 2026 15:51
## What's the issue?

Browse can fail to connect to a healthy local Chrome because it trusts
an old browser connection URL saved in the profile's
`DevToolsActivePort` file. The existing check only confirms that
something is listening on the cached port; it does not confirm that the
saved browser target still exists.

For example, the file points to
`ws://127.0.0.1:9222/devtools/browser/old-id`, while the running Chrome
exposes `/devtools/browser/new-id`. Browse selects `old-id`, and the
connection fails with a 404 or connection reset.

This PR checks the cached target against Chrome's live `/json/version`
response. If they disagree, Browse discards the stale candidate and uses
its existing live-endpoint fallback. It compares URL paths so
`localhost` versus `127.0.0.1` does not invalidate a matching target,
and probes each port only once per discovery call.

## When does it happen?

1. A Chrome instance leaves a `DevToolsActivePort` file behind after
exiting.
2. A later browser instance uses the same debugging port, but has a
different browser target ID. An old profile file can therefore point to
a port now owned by another instance.
3. Browse discovers that stale file while attaching to a local browser,
such as through `browse open --auto-connect` or the discovery used by
`browse doctor`.

The port is reachable, so the old check accepts the file even though its
target is gone. A restart alone is not sufficient to trigger this: the
stale file must remain visible and its port must be reused.

## Why is it important?

Local browser attachment fails even though Chrome is running and its
debugging endpoint works. Users and agents cannot reliably reuse that
browser session, and diagnostics can select a dead endpoint. Validating
the browser target prevents leftover profile state from making a working
browser look broken.

This is a reproduced connection-correctness bug; we have not established
how frequently users encounter it.

## How was it verified?

Verification on September 23, 2026, for head `b96dea6`:

- **Real Chromium:** created an isolated stale profile file pointing at
a live browser's port, then ran both discovery APIs before and after the
fix. Main `fbcdf6169` selected the stale target and failed with 404 /
connection reset. The patch selected the live target, completed both
WebSocket upgrades with HTTP 101, and successfully called
`Browser.getVersion` (`Chrome/153.0.8010.12`). This was a Linux Chromium
smoke test; the temporary browser and profile were cleaned up.
- **401 CLI tests passed across 29 files**, including six regressions
covering stale and fresh caches, host spelling, fallback discovery,
probe deduplication, and no live browser.
- **Build and lint passed**, including formatting, ESLint, and
TypeScript checks.

The diff contains the discovery fix, its regression tests, and a Browse
patch changeset. The PR targets `main`.
# why
SDK changes must include documentation, but merging those docs into
`main` should not publish unreleased APIs to the public site

## what changed
- Add Mintlify previews for docs PRs targeting `main` and a persistent
preview updated by docs pushes to `main`. Report the URL and wait for
deployment success.
- Run docs reference tests and Mintlify validation independently of SDK
path filters, including on docs-only PRs and production backports.
- Include Go SDK source in the docs test cache inputs.
- Add explicit `main`-only guards to SDK publishing jobs, including the
reusable Python publisher.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Separates docs previews from production publishing so unreleased API
docs aren't published to the public site.

- Adds Mintlify previews for docs PRs targeting `main` and persistent
previews for docs pushes to `main`, reporting the URL and waiting for
deployment success.
- Runs docs reference tests and Mintlify validation on every PR,
including docs-only PRs and backports.
- Includes Go SDK source in the docs test cache inputs.
- Adds `main`-only guards to SDK publishing jobs.

<sup>Written for commit 6fd167a.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3042?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. -->
# why
- clean up copy & test the editorial docs change workflow


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Cleans up the introduction copy by removing redundant phrasing and tests
the editorial docs change workflow.

<sup>Written for commit aff9504.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3048?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. -->
Mirrored from external contributor PR #2738 after approval by
@miguelg719.

Original author: @abhinavkr26104
Original PR: #2738
Approved source head SHA: `e77c269fcc7ab33d2b76f213f26da62b77b1e826`

@abhinavkr26104, please continue any follow-up discussion on this
mirrored PR. When the external PR gets new commits, this same internal
PR will be marked stale until the latest external commit is approved and
refreshed here.

## Original description
# why

The v4 init schema supplied `https://example.com/v1/traces` whenever
callers omitted telemetry. The extension treated that placeholder as an
intentional OTLP destination, creating guaranteed-failing background
exports and possible shutdown delays for otherwise default Stagehand
instances.

Fixes #2732

# what changed

- Make `stagehand.init` telemetry optional instead of injecting a
placeholder endpoint.
- Leave extension tracing inert when no telemetry configuration is
supplied while preserving explicit OTLP export behavior.
- Regenerate Python and Go protocol models and the embedded Go extension
bundle.
- Keep Go's existing value-style public telemetry option while omitting
its zero value from the wire.
- Document that telemetry export is disabled by default and add
protocol/runtime/SDK regression coverage.
- Add patch Changesets for the extension and SDKs.

# test plan

- Protocol unit suite: 26 files passed, 359 tests passed.
- Extension unit suite: 45 files passed, 334 tests passed, 10 existing
TODOs.
- Focused TypeScript SDK create tests passed, including omitted and
explicit telemetry.
- Python focused tests: 200 passed, 1 skipped; generated-model
freshness, Ruff format, and Ruff lint checks passed.
- Full Python suite attempted: 455 passed, 2 skipped; only the two
pre-existing Windows path assertions tracked by #2733 failed.
- Go SDK suite excluding the intentionally separate examples package
passed.
- Protocol type-check and extension production build passed.
- Targeted Oxfmt, Oxlint, Changesets validation, and `git diff --check`
passed.
- The full JavaScript unit run was attempted; unrelated
Windows/environment failures remain in SDK path assertions,
package-manager spawning, and file metadata handling.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Makes telemetry export opt-in so omitted telemetry no longer injects a
placeholder endpoint that caused guaranteed-failing exports and shutdown
delays. `stagehand.init` no longer defaults to
`https://example.com/v1/traces`; omitting telemetry leaves tracing
inert, while explicit telemetry keeps OTLP export.

- Protocol: `stagehand.init.telemetry` is now optional with no default;
schema, integrity, and wire-casing tests updated.
- Extension: `createStagehandTracing.configure` accepts `undefined` and
skips runtime creation; flush/shutdown become no-ops when telemetry is
absent.
- SDKs: TypeScript omits `telemetry` from the wire when unset; Go's
`StagehandInitParams.Telemetry` is now `*TelemetryConfig` and omits the
zero value via `optionalTelemetry`, while `CreateOptions.Telemetry`
stays value-style; Python marks `telemetry` as `Optional` with the
placeholder default removed.
- Release: Patch changesets added for the five affected packages.

**Migration**
- No action needed; placeholder export errors and shutdown delays
disappear.
- Set `telemetry.traces.endpoint` to an OTLP collector (ending in
`/v1/traces`) with required headers to enable export.
- Go: pass `nil` to omit telemetry or set a non-empty endpoint/headers
to enable; direct `StagehandInitParams` construction now requires
`*TelemetryConfig`.

<sup>Written for commit fecc5a6.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3045?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. -->

<!-- external-contributor-pr:owned source-pr=2738
source-sha=e77c269fcc7ab33d2b76f213f26da62b77b1e826 claimer=miguelg719
-->

---------

Co-authored-by: Abhinav Kumar Singh <abhinav.kr.singh.2610@gmail.com>
Co-authored-by: miguel <miguelg71921@gmail.com>
Co-authored-by: Miguel <36487034+miguelg719@users.noreply.github.com>
thanks @mikhail-koviazin for the contribution here!

## why

The composed-tree XPath parser evaluates `text()` and `.` through the
same helper, `element.textContent`. In XPath these are not the same
thing: `.` is the string-value of the element, so it covers the whole
subtree, while `text()` is the node-set of the element's **direct child
text nodes**.

This parser is not a rare path. It takes over whenever the document
contains a shadow root anywhere, so a single unrelated web component on
the page changes what a locator matches, silently and with no error.

Measured against `document.evaluate()` on a build of `main`
(`a73da68b`), fixture served over http. The only difference between a
run that matches native and a run that does not is one unrelated
`attachShadow()` call elsewhere in the same document:

| XPath | `document.evaluate()` | Stagehand |
| --- | --- | --- |
| `//button[text()='Save']` | 1 | 2 |
| `//div[text()='a']` | 1 | 0 |
| `//div[contains(text(),'b')]` | 0 | 1 |
| `//div[@id='split'][text()='y']` | 1 | 0 |
| `//div[@id='split'][contains(text(),'y')]` | 0 | 1 | |
`//div[@id='split'][normalize-space(text())='x']` | 1 | 0 | |
`//button[.='Save']` | 2 | 2 (control: `.` is already correct) |

Fixture: `<button id="wrapped"><span>Save</span></button>` before
`<button id="direct">Save</button>`, plus `<div
id="mixed">a<span>b</span></div>` and `<div id="split">x<br/>y</div>`.

The count is not the worst part. The button whose label sits inside a
`<span>` comes first in document order, so `//button[text()='Save']`
returns it first and `.first().click()` clicks the wrong button. Nothing
throws, nothing logs, and the run continues on the wrong element. The
other direction is a silent zero on markup as ordinary as
`a<span>b</span>`.

## what changed

`text()` now reads its own node-set, and `.` keeps exactly the meaning
it has today:

- `text()='v'` is true when **any** direct child text node equals `v`.
Comparing a node-set to a string is existential in XPath.
- `contains(text(),'v')` and `normalize-space(text())='v'` read the
string-value of the **first** node, because both functions take a
string, so the node-set collapses.
- `.='v'`, `contains(.,'v')` and `normalize-space(.)='v'` keep reading
the string-value of the element, unchanged.

Mechanically, in `packages/extension/dom/locatorScripts/xpathParser.ts`:
the three patterns that accepted `(?:text\(\)|\.)` now capture which
token they matched, and `textEquals` / `textContains` carry a `source:
"self" | "text"` field that `evaluatePredicate` reads. The field is
optional and absent means `self`, so predicates constructed anywhere
else keep their current behavior. `and`, `or` and `not` carry it through
without changes.

## test plan

`packages/extension/tests/xpath-text-predicates.test.ts` (new, unit):
the parser keeps `text()` and `.` apart for `=`, `contains()` and
`normalize-space()`, and carries the source through `or` and `not`.

`packages/sdk-ts/tests/integration/locatorXPathTextPredicates.test.ts`
(new, integration): the table above against real Chrome. It has to be
served over http, since `data:` URLs stay on the native engine and never
reach this parser at all. Registered in `scripts/test-integration.ts`
next to the other locator groups.

Both are red on `main` and green with the change. On `main` the
wrong-button case fails with `expected 2 to be 1` and the silent-zero
case with `expected +0 to be 1`.

Context: #1679 consolidated the parser copies and #1683 taught this one
`text()`, `contains()` and `normalize-space()`. This is the same layer,
one step further in.


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes the composed-tree XPath parser so `text()` reads only direct child
text nodes. Previously it read `element.textContent` (same as `.`),
causing diverging matches and wrong clicks on pages with any shadow
root.

- Old: `text()` behaved like `.`. New: `text()` evaluates direct child
text nodes; `.` still reads the element's subtree string-value. This
aligns with `document.evaluate()`.
- If a locator relied on `text()` to match nested text, use `.` instead.
- `text()='v'` is existential across child text nodes;
`contains(text(),'v')` and `normalize-space(text())='v'` collapse to the
first text node.
- Adds unit and integration tests; integration runs over http and is
registered in `scripts/test-integration.ts`.

<sup>Written for commit 482e0a9.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3052?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. -->

---------

Co-authored-by: Mikhail Koviazin <mikhail.koviazin@gmail.com>
# why

Add the extension-side PDF implementation separately from exposing a new
SDK operation, so capture behavior can be reviewed on its own.

This is **PR1 of 2**. Follow-up #3030 adds the public protocol/RPC
registration, TypeScript/Python/Go SDK wiring, generated models,
documentation, release notes, and final extension archive.

# what changed

- Add internal Understudy `Page.pdf()` using native CDP request/response
types; keep the result base64-encoded for the later transport layer.
- Share the existing capture queue with screenshots, including a
configurable 30-second deadline, late-response recovery, and prevention
of expired queued work.
- Preserve the original timeout in a typed recovery error and its safe
diagnostic message.
- Add focused capture tests for serialization, failures, timeouts,
queued expiry, and independent pages.
- Refresh only the embedded extension snapshot required by the
repository's artifact-drift check. PR2 regenerates it again when the
public wiring lands.

No PDF RPC is registered here. No public SDK methods, protocol schemas,
generated models, or documentation are changed.

# test plan

- `pnpm check`: **36 tasks passed**.
- Extension, SDK, protocol, documentation, parity, and discovery
regressions: **975 passed** across 102 files (10 existing TODOs).
- Local Chromium screenshot integration: **7 passed**.
- Go SDK tests and generated-model/archive consistency checks passed.
- Python generated-model consistency check passed.
- Formatting and `git diff --check` passed.
# why

Expose PDF rendering through the existing Stagehand SDK conventions
after the internal extension implementation is in place.

This is **PR2 of 2**, stacked directly on #3034
(`amel/pdf-render-extension`). Merge the parent first and follow the
repository's stacked-PR handoff rules when moving this PR to `main`.

# what changed

- Register the `page.pdf` protocol operation and connect the extension
router, controller, and runtime to the internal implementation from
#3034. Replace its temporary native-CDP signature with the canonical
protocol types.
- Add TypeScript and Python `page.pdf()` and Go `Page.PDF()`, returning
PDF bytes. TypeScript and Python optionally write a local file using
their existing screenshot conventions.
- Add typed print options and matching SDK response deadlines: 30
seconds for capture by default, with `timeout: 0` disabling the
deadline. Preserve error causes and include computed timeout durations
in diagnostics.
- Regenerate the protocol document, Python and Go models, and the final
embedded extension ZIP. Keep the public API documentation and release
changeset with the SDK exposure.
- Add wire/tracing, SDK, file-output, and local Chrome integration
coverage. Fix integration-test discovery and validate its mapping
against repository files.

The capture implementation and recovery tests are reviewed in #3034, not
repeated in this diff. The complete stack's Git tree is identical to the
previously reviewed implementation at `2b416e172`; this split changes
review boundaries, not behavior.

# test plan

- Complete-stack local Chromium PDF and screenshot integration: **9
passed**. Verify PDF bytes and file equality, page count, CSS
dimensions, tags, page ranges, and captures after a rejected print.
- Extension, TypeScript SDK, protocol, reference documentation, SDK
parity, and integration discovery: **989 passed** across 102 files (10
existing TODOs).
- `pnpm check`: **36 tasks passed**. Generated Go extension matches the
final extension build; `git diff --check` passes.
- The identical final tree was also verified with **235 Python tests**,
Ruff/type checks, Go SDK tests, `go vet`, and generated-artifact checks.
- Parent #3034 was independently verified with **975 regressions**, **7
screenshot integration tests**, all **36 repository checks**, and
Go/Python generated-artifact checks.
## Summary

Make the integrations overview a general directory for connecting
Stagehand to agents, frameworks, and application workflows. Organize the
overview and sidebar into Agent Frameworks, CLI Agents, and Automations.

- Add dedicated overviews for Agent Frameworks and CLI Agents. Cover
framework connections separately from MCP adapter setup for coding
agents, with Pi documented as a native extension.
- Update navigation and security links, and replace the removed MCP
best-practices entry with the CLI Agents guide.
- Add Stripe under Automations, documenting the Checkout sample from
stripe-samples/webmcp#5, its setup, WebMCP flow,
and final Pay click.
- Pin the Stripe sample commit while the upstream PR is open and explain
its spending limit and result-handling limitations.

## Validation

- `mint validate`
- `mint broken-links --check-anchors --check-redirects --check-snippets`
- `mint a11y --skip-contrast`
- Formatting check for `docs.json` and `git diff --check`

All passed using Node.js 24. Checkout was not executed; the Stripe guide
was verified against the upstream sample source.

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
# why
- example.com changed, this broke some smoke tests in our ci
# what changed
- swapped it to a hosted eval site that is similar to example.com


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes failing CI smoke tests by replacing `https://example.com` with a
hosted eval site that mirrors example.com across the Go, Python, and
TypeScript SDK examples and the TypeScript Browserbase smoke test.

<sup>Written for commit dfd525e.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3069?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. -->
# why

* Before Browserbase had secrets support, `functions init` would install
a playwright template. But now we support secrets so we can update the
starter template to showcase Stagehand.
* There were some rough edges around the `functions publish` command
related to pnpm 11. Added a few updates so that the functions CLI works
out of the box.

# what changed

# test plan

It works if nothing in this path errors:
1. [in stagehand repo] `pnpm build && cd packages/cli`
2. `alias browse-dev="node $HOME/[your dev
path]/stagehand/packages/cli/bin/run.js"` to set a local version of the
`browse` cli called `browse-dev`
3. `cd [your dev path, _not_ in stagehand repo] && browse-dev functions
init branch-test && cd branch-test`
4. `browse-dev cloud extensions upload
node_modules/@browserbasehq/stagehand/dist/assets/stagehand-extension.zip`
and then replace `your-extension-id` in `index.ts`
5. `browse-dev cloud secrets create BROWSERBASE_API_KEY --env
BROWSERBASE_API_KEY` to store your secret API key for use in the
deployed function
6. `browse-dev functions dev index.ts`
7. (in a new terminal) `curl -X POST
http://127.0.0.1:14113/v1/functions/my-function/invoke -H 'Content-Type:
application/json' --data '{}'` to make sure it works locally
8. `npm_config_min_release_age=0 browse-dev functions publish index.ts`
9. `browse-dev functions secrets attach <functionId> <secretId>`
10. `browse-dev functions invoke <functionId>` to make sure you got the
same result as (7) above
11. Success!



<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Swaps the Playwright starter in `functions init` for a Stagehand one,
and fixes `functions init` and `functions publish` on pnpm 11 and
private npm registries.

- Local dev now sends an empty `secrets` object to invocations, matching
production, so the starter's `context.secrets.BROWSERBASE_API_KEY`
lookup needs no null check and falls back to
`process.env.BROWSERBASE_API_KEY`.
- `functions init` installs `@browserbasehq/stagehand` instead of
`playwright-core`, pins zod to Stagehand's version so schemas pass type
checks, and writes a Stagehand starter that extracts Hacker News top
stories through the Model Gateway.
- The starter connects with `browserbase.connect` into
`Stagehand.create` and expects you to upload the Stagehand extension and
paste its ID into `index.ts`.
- `functions init` writes `pnpm-workspace.yaml` so pnpm 11 allows
esbuild's build script, and its next steps use `browse` commands.
- `functions publish` builds `package-lock.json` from the uploaded files
(so local `file:` dependencies resolve), omits registry-resolved URLs
for private registries, checks for an existing lockfile, and prints npm
output when generation fails.

<sup>Written for commit b630e73.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3055?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. -->
# why

* The release of Function Secrets enables us to support Stagehand
deployments on Browserbase. This PR showcases that in the new deployment
guide

# what changed

# test plan

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Updates the Stagehand deployment guide to recommend Browserbase
Functions with encrypted project secrets as the primary deployment path
instead of Vercel.

- Adds setup, extension upload, Function development, local testing,
publishing, secret attachment, invocation, and troubleshooting steps.
- Uses the Model Gateway in the example, so no model provider setup is
needed.
- Moves the Vercel guide under "Other deployment options" and adds a
Features section.
- Clarifies the introduction's description of Stagehand's control
layers.

<sup>Written for commit 83c9e20.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3056?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. -->
Release Browse independently of the Stagehand SDKs. Merging this PR
publishes the CLI from the merged commit.

## 0.11.1

### Patch Changes

- [#3055](#3055)
[`8308d8d`](8308d8d)
Thanks [@akeimach](https://github.com/akeimach)! - `functions init` now
scaffolds a Stagehand project. It installs `@browserbasehq/stagehand`
instead of `playwright-core`, installs the zod version that Stagehand
uses, and writes a Stagehand starter function.

- [#3055](#3055)
[`8308d8d`](8308d8d)
Thanks [@akeimach](https://github.com/akeimach)! - Fix Functions builds
that failed because of how `functions publish` generated
`package-lock.json` or how `functions init` set up pnpm:

- `functions publish` now generates `package-lock.json` without registry
URLs, so private npm registries work.
- `functions publish` now resolves local `file:` dependencies by
building `package-lock.json` from the uploaded files rather than just
`package.json`.
- `functions publish` now prints npm's error output when it can't
generate `package-lock.json`.
- `functions init` now writes a `pnpm-workspace.yaml` that allows the
esbuild build script, required by pnpm 11+.

- [#2542](#2542)
[`514970e`](514970e)
Thanks [@shrey150](https://github.com/shrey150)! - Fix local browser
discovery (`--auto-connect`, `browse doctor`) trusting a stale cached
debugging port after a different Chrome process later reuses that same
port.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
# why

Fixing a prose issue surfaced in another PR, and while in there, added
clarity about the functions starter code and what could be replaced

# what changed

* Updates docs prose from "we recommend" to "Browserbase recommends"
* Specifies which node version
* Adds a note about the template code and what must stay vs be replaced

# test plan


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes prose in the deployment guide and clarifies that the Functions
template is starter code you replace.

- Changes "we recommend" to "Browserbase recommends" and specifies
Node.js 22.18 or later.
- Explains that the template contains a starter Function to replace, and
notes to keep the `defineFn` call and update the function name
consistently.

<sup>Written for commit 1f6ff65.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3077?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. -->
# why
Three links in the v3 docs are broken, and two Go code samples were
rewritten into links, so they no longer show valid Go.

# what changed
- `v3/sdk/go.mdx`: restore `param.Override[T](value)` and
`param.Override[stagehand.FooParams](12)`. Both had been turned into
links to non-existent files (`stagehand-go/blob/main/value` and `/12`).
The restored text matches the stagehand-go README.
- `v3/sdk/java.mdx`: the OkHttp logging interceptor link pointed at
`square/okhttp/tree/master`. That repo's default branch is `main`, and
`master` no longer resolves.
- `v3/basics/evals.mdx`: `evals.config.json` moved to
`packages/evals/evals.config.json`. The link used the old top-level
path.

# test plan
Checked each new target on GitHub (`packages/evals/evals.config.json` on
main, `okhttp-logging-interceptor` on okhttp main) and compared the Go
snippets against the stagehand-go README. Docs-only change, no Changeset
needed per CONTRIBUTING.md.


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes three broken links in the v3 docs.

- Go: the `param.Override[T](value)` and
`param.Override[stagehand.FooParams](12)` code samples were accidentally
converted into links to non-existent files and are now back to valid Go.
- Java: the OkHttp logging interceptor link now uses `main` instead of
`master`.
- Evals: the `evals.config.json` link now points to
`packages/evals/evals.config.json`.

<sup>Written for commit c427fb1.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3076?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. -->
# why
a `locator` action needs one timeout covering all of its downstream code
(eg, checking frame readiness, finding the element, & taking the
action). if setup uses three seconds of a five-second timeout, the
action should have two seconds left

this pr adds the shared timeout helper. later PRs will connect it to
locator methods & add public timeout options.

# what changed
- added `locatorOperation.ts` to track the time remaining for one call.
`runLocatorOperation()` creates it once & all nested steps share it
  - passing `0` disables the timeout
- added `run()` to check the deadline before starting a step & stop
waiting when time runs out. the error names the operation & the step
that was still waiting.
- added `delay()` so pauses between steps use the same timeout.
- added `cleanup()` to attempt cleanup after a timeout, with a
one-second limit on waiting. cleanup errors do not replace the original
error.
- added an optional callback to release temporary resources that arrive
too late to use. commands already sent to the browser may still finish

# test plan
added tests in `locatorOperation.test.ts` that control time & hold
responses open
to verify:
- nested steps keep the original deadline after success or failure, &
timing out one call does not stop another.
- zero disables the timeout, changing the system clock does not change
the time remaining, & invalid timeout or delay values are rejected.
- an expired call cannot start another step. a late response or error
cannot resume the action.
- resources arriving after timeout are released once; resources returned
in time remain available to the caller.
- delays stop at the deadline. long timeouts & delays are not shortened
by the underlying timer's size limit.
- timers & listeners are removed after success, failure, or timeout.
timeout errors identify a step that is still waiting.
- cleanup failures preserve the original error, & stalled cleanup
neither delays the timeout response nor waits longer than its one-second
allowance

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a shared locator operation context so a single timeout spans all
steps of a locator action (frame checks, element lookup, and the action
itself), replacing separate per-step deadlines.

- `runLocatorOperation()` creates the context once and nested steps
share its remaining budget; passing `0` disables the timeout.
- `run()` checks the deadline before each step, `delay()` pauses within
the same budget, and cleanup of late resources is attempted for one
second after expiry.
- Expiry stops waiting and may release late-arriving resources, but the
timeout error always wins, even if a late command rejects.

<sup>Written for commit 5800073.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3013?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. -->
# why
resolving a the node/object ID that a `locator` points to can involve
crossing iframes, waiting for browser helpers, & looking up the element.
these steps need to share the caller's deadline so each frame or retry
cannot restart the timeout.

this pr connects that deadline to node/object ID resolution. the next PR
in this stack will connect `locator` actions & reads to these helpers.
public parameters for setting timeouts will come in a later PR.

### note:
this PR also renames `LocatorOperation` to `Progress` for clarity

# what changed
- renamed `locatorOperation.ts` to `progress.ts`, `LocatorOperation` to
`Progress`, & `runLocatorOperation()` to `runWithProgress()` because it
will be used by callers beyond locators.
- passed the same optional progress through frame traversal, element
lookup, & browser helper readiness. callers without progress keep their
existing behavior for now.
- made readiness waits, retries, & browser commands use the remaining
time. readiness can exceed the old fixed limits when the caller allows
it. passing in `0` disables the deadline.
- preserved timeout errors through retries, fallback setup, & cleanup.
closed connection or session errors stop resolution, while frame
movement & temporary browser context loss can still recover before
expiry.
- released temporary browser references after timeout, including late
results. callers waiting for shared helper setup have independent
deadlines.

# test plan
added tests in `locatorResolution.test.ts` using controlled time &
browser responses to verify:
- multiple frame hops share one budget, & polling stops when it expires.
- readiness can finish beyond the old limits with a longer or disabled
timeout.
- short readiness attempts fit the remaining time & detect a frame's new
session.
- stalled commands time out; late responses cannot resume resolution &
temporary references are released. listeners & timers are removed after
expiry.
- one caller timing out does not cancel shared helper setup for another
caller.
- errors or cleanup finishing after the deadline produce a timeout, even
before the timeout timer fires. ordinary lookup failures retain their
existing behavior before expiry.
- closed connections & sessions surface their errors. recovery from a
changed session or missing browser context works only while the call is
still active.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a shared deadline to `locator` resolution so iframe hops, readiness
waits, and element lookup all share the caller's timeout instead of each
restarting it. Also fixes locator failures when entering still-loading
iframes and correctly resolves XPaths that end at an iframe element.

**What changed**
- Renames `LocatorOperation` to `Progress` and `runLocatorOperation()`
to `runWithProgress()`; callers beyond locators now use it, and a
temporary `runLocatorStep()` adapter lets callers without `Progress`
keep current behavior.
- Threads an optional `Progress` through frame traversal and element
lookup; `0` disables the deadline.
- Readiness waits and browser commands use remaining time; timeout
errors survive retries, fallback setup, and cleanup, while closed
connection or session errors stop resolution immediately.
- Releases temporary browser references after expiry, including late
results and earlier element matches replaced by a later lookup.
- Recovered contexts and frame restarts are honored only while the call
is active.

**Bug fixes**
- Waits for the locator world when a deep XPath crosses a loading iframe
instead of failing on a missing execution context.
- Keeps a trailing `iframe[n]` in the parent frame as the target element
instead of descending into the child document.

<sup>Written for commit 0f263bc.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3023?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. -->
# why
pr #3023 made locator resolution respect the caller's deadline. the
action or read that follows also needs to use the remaining time.
otherwise, a stalled browser command can keep the call waiting after its
timeout.

# what changed
- passed the same progress through direct, deep, & frame-scoped locator
methods, from finding the target through executing the action/read.
- bounded browser commands for `click()`, `hover()`, `selectOption()`,
`scrollTo()`, `sendClickEvent()`, `centroid()`, `backendNodeId()`,
counts, & element reads.
  - counts also pass progress through their separate selector helpers
- preserved timeout & closed connection/session errors in catches that
previously ignored errors or returned zero. ordinary lookup failures
keep their existing handling.
- used bounded cleanup for temporary browser references. cleanup
failures cannot replace the action's error, & cleanup crossing the
deadline cannot turn the call into success.
- kept click events in their existing order, without waiting for each
response before sending the next event. expiry prevents further
dispatch.

### note: 
progress remains optional during migration. fill, typing, highlighting,
& uploads come in a subsequent PR

# test plan
added tests in `locatorActions.test.ts` using shared setup, controlled
time, & held browser responses to verify:
- delegates, actions, reads, & counting helpers receive the same
progress.
- time spent resolving the target leaves only the remaining budget for
execution.
- stalled commands reject at the deadline; late responses cannot resume
actions. an already-expired call sends no action commands.
- click events retain their order & are sent before earlier responses
arrive. dispatch stops if the deadline passes during the sequence.
- timeout & closure errors propagate through scrolling & counting. valid
empty reads still return false, zero, or an empty string.
- cleanup failures preserve the action error, cleanup crossing the
deadline reports a timeout, & stalled cleanup cannot hold the outer
caller past expiry.
- timing out one call leaves a concurrent unlimited call on the same
locator free to finish.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Makes locator actions and reads respect the caller's timeout so a
stalled browser command can no longer hold a call past its deadline.

- Threads the same progress through direct, deep, and frame-scoped
locator methods, from target resolution through execution.
- Bounds browser commands for click, hover, selectOption, scrollTo,
sendClickEvent, centroid, backendNodeId, count, and element reads;
counts also pass progress through their selector helpers.
- Preserves timeout and closed connection/session errors in catches that
previously ignored them or returned zero.
- Bounds cleanup of temporary browser references so cleanup failures
can't replace the action's error, and cleanup crossing the deadline
can't turn the call into success; cleanup is no longer awaited when an
action is expiring.
- Keeps click events in their existing order without waiting for each
response; expiry stops further dispatch.
- Progress remains optional during migration; fill, typing,
highlighting, and uploads come in a later PR.

<sup>Written for commit e4cef1d.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3024?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. -->
)

# why
`fill()`, `type()`, `highlight()`, & `setInputFiles()` perform multiple
steps within one call. those steps need to share the caller's deadline,
including typing fallbacks, intentional delays, & file preparation.
otherwise, they can continue sending browser commands after the call
times out

# what changed
- passed the progress object downstream through `fill()`, `type()`,
`highlight()`, `setInputFiles()`, & their existing delegates
- made both fill fallbacks reuse the original deadline. timeout or
closed connection/session errors prevent fallback to typing. each
browser reference is released once, including when an early release
stalls.
- bounded text preparation & keyboard commands. typing delays use the
remaining budget & stop on expiry.
- bounded highlight setup, drawing, duration, & refresh waits.
successful `durationMs: 0` calls still leave the highlight visible.
timeout or failure triggers removal, including another removal attempt
if a draw finishes late.
- combined overlay removal & reference release into one bounded cleanup
wait. cleanup failures cannot replace the action error.
- included file normalization & encoding in the budget, with another
check before injection. synchronous encoding can finish after expiry,
but cannot trigger an upload afterward. clearing a file input follows
the same path.

# test plan
extended `locatorActions.test.ts` using shared setup, controlled time, &
held browser responses to verify:
- delegates & nested calls receive the same progress; both fill
fallbacks get only the remaining time & stop on expiry or closure.
- prepared fill inserts text or clears the field correctly, & stalled
early cleanup does not release the same reference twice.
- typing stops during a delay or stalled keyboard command without
sending more characters. unlimited typing can finish.
- highlight duration consumes the budget; zero-duration highlights
remain visible on success. ordinary refresh failures can recover, while
closure stops refreshes.
- late highlight draws are removed. stalled cleanup does not add
sequential waits, & cleanup failures preserve the original error.
- expiry during normalization or encoding prevents file injection.
stalled normalization cannot resume the upload after timeout.
- upload injection respects finite & unlimited budgets; file contents &
metadata are preserved, & an empty file list still clears the input.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes `fill()`, `type()`, `highlight()`, and `setInputFiles()` so every
step in a multi-step call shares the caller's deadline, preventing
browser commands from being sent after the call has timed out.

- Both `fill()` fallbacks reuse the original deadline; timeout or closed
connection errors stop fallback to typing.
- Typing delays use the remaining budget, and highlight refresh waits
and duration consumption are bounded.
- Zero-duration highlights stay visible on success; timeout or failure
triggers removal, including a retry if a draw finishes late.
- File normalization and encoding count against the budget, with a check
before injection; clearing a file input follows the same path.
- After a failed or timed-out action, cleanup runs without blocking the
caller and cannot replace the original error, even when cleanup itself
stalls.
- Extended `locatorActions.test.ts` with controlled time and held
browser responses to cover each deadline path.

<sup>Written for commit 013a3f3.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3026?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. -->
# why
this PR adds the `timeout` param to the protocol, & exposes it publicly
in ts. the default timeout is 20 seconds

# what changed
- added optional timeout settings to all 17 terminal locator methods,
including reads. typescript callers can use `click({ timeout: 5000 })`,
`fill("hello", { timeout: 5000 })`, or `count({ timeout: 0 })`.
- started one deadline before frame resolution & passed it through the
whole call. frame readiness, element lookup, typing delays, highlight
duration, & extension-side upload preparation all share that budget.
- aligned typescript response waits with the execution timeout plus
delivery grace. zero disables that response deadline too. long timeouts
avoid the JS timer limit, & timeout errors retain their name & message.
- made the compatibility facade pass its remaining budget to native
locator calls, including zero, instead of dropping timeout options

# test plan
- `locator-timeouts.test.ts` checks every registered locator method
accepts zero & positive timeouts, rejects invalid values, preserves
omission, & keeps existing options working. timeout settings stay
separate from locator identity.
- `runtime-locator-timeouts.test.ts` uses controlled time to verify
every entry point starts its deadline before resolution, applies the
default or override, rejects stalled work, & leaves zero unlimited.
- wrapper, rpc, & package tests cover option forwarding, the public
options type, response deadlines & delivery grace, long timers, &
timeout error details. facade tests check remaining-budget forwarding
for ordinary & frame locators.
- `iframeLocatorReadiness.test.ts` runs against real chrome with
same-process frames & frames in a separate process. it verifies nested
frame readiness & typing share one budget, explicit timeouts can exceed
the old readiness cap, zero waits successfully, & loading a frame after
expiry does not cause a late click.
- `locatorActions.test.ts` exercises highlight & upload cleanup through
the runtime: stalled cleanup preserves an earlier action error & does
not delay timeout rejection.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a `timeout` option to all terminal locator methods across the
protocol and the TypeScript, Python, and Go SDKs, and updates the v4
docs. The default is 20 seconds, and `{ timeout: 0 }` disables the
deadline.

**What changed**
- One deadline starts before frame resolution and covers frame
readiness, element lookup, typing delays, highlight duration, and upload
preparation; SDK file reading and request delivery happen before that
budget starts.
- Each SDK sets its RPC response deadline to the execution timeout plus
a delivery grace, with `0` disabling it; long timeouts work around
per-language timer limits.
- The Playwright compatibility facade forwards its remaining budget to
native locator calls, including zero.
- Go's `SetInputFiles` now takes a file-input slice, and Python rejects
non-finite timeout values.
- Timeout errors retain the `TimeoutError` name and message.

<sup>Written for commit 0d7d1ec.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3033?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. -->
…#3081)

# why
`screenshot()` timeouts could stop the caller waiting while downstream
functions (eg, preparation & mask lookup) continued without a shared
deadline. `pdf()` also used separate timeout handling. this PR makes
both `screenshot()` & `pdf()` use the `progress` tracker.
# what changed
- used shared progress for screenshots & pdfs, starting before queueing.
nested calls reuse their parent's remaining time.
- passed screenshot progress through preparation, mask lookup, tab
activation, & capture. mask lookup & its paint delay consume the same
budget.
- the timeout/deadline are checked before starting further browser
commands, including when the timeout timer has not fired yet.
already-issued commands can still finish.
- the page is kept unavailable until pending work & restoration finish.
stalled preparation or cleanup does not block other tabs; activation &
capture remain serialized across the browser.
- registered restoration before setup starts & released all resolved
mask nodes, including nodes skipped after expiry. cleanup cannot replace
an earlier capture error.
- preserved defaults: screenshots are unlimited, pdfs use 30 seconds, &
zero disables either timeout

# test plan
- `screenshotUtils.test.ts` checks that queued requests cannot start
after expiry, stalled browser commands cannot trigger later steps, &
captures stay blocked until recovery finishes. it also checks that
stalled page setup or cleanup leaves other tabs usable.
- `pdf.test.ts` checks shared queue ordering, time spent queueing
counting toward the deadline, inherited deadlines, defaults, & zero.
late print or screenshot responses cannot release the page before
pending work finishes.
- added preparation tests in `pdf.test.ts` for mask lookup consuming the
screenshot budget, late mask measurements being restored, skipped nodes
being released, & cleanup preserving the original capture error. further
tests prevent animation changes or style insertion after expiry,
including before the timer fires.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Makes `screenshot()` and `pdf()` use the shared `progress` tracker so
their deadline applies across every downstream step, nested calls
inherit the parent's remaining budget, and a timed-out capture can no
longer leave scheduled work running or free the page early.

- The deadline is checked before each browser command, including before
the timeout timer fires; commands already issued still finish.
- Late CDP responses, stalled setup, and stalled cleanup keep the page
lock held, blocking subsequent captures while leaving other tabs usable.
- Mask lookup and its paint delay consume the same budget as the capture
itself, and all resolved mask nodes are released even when skipped after
expiry.
- Cleanup cannot overwrite an earlier capture error.
- Defaults preserved: screenshots are unlimited, pdfs use 30 seconds,
and zero disables either timeout.

<sup>Written for commit ad86581.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3081?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. -->
## Summary
- Move the observability documentation change out of #3045.
- Document that omitting telemetry disables export and remove the
placeholder-endpoint TODO.

Stacked on #3045; this PR contains only the documentation change. Merge
after #3045.

## Validation
- git diff --check passes.
- Verified #3045 no longer changes packages/docs.
- Verified the combined branches reproduce the original tree exactly.
- No runtime tests run for this docs-only split.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Documents opt-in telemetry behavior in the observability config docs:
omitting the `telemetry` option now disables export, and the outdated
placeholder-endpoint TODO comment is removed.

<sup>Written for commit 13b02f1.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3054?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. -->
…3067)

See browserbase/stagehand-website#199

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
# why
`page.snapshot()` had no timeout param, nor did some of its internal
helpers. the helpers that it calls are also called by other functions in
the codebase that require timeout handling. this PR wires the `progress`
object through the shared downstream helpers, and also exposes a user
facing `timeout` param in `page.snapshot()`

# what changed
- added a snapshot timeout in milliseconds to typescript, python, & go.
omission or `0` keeps snapshots unlimited.
- made one deadline cover frame readiness, element lookup, document &
accessibility tree reads, & frame traversal
- allowed internal snapshot calls to reuse a caller's remaining time &
timeout error instead of starting a new budget.
- stopped retries, fallback reads, & further frame traversal after
expiry. temporary element references are released, including those
returned after timeout. already-issued browser commands can still
finish.
- updated sdk response waits to allow the requested timeout plus
delivery grace, with no response deadline for unlimited snapshots

# test plan
- `capture.test.ts` checks public & inherited deadlines, unlimited
snapshots, expiry preventing further reads or fallback, & cleanup of
ignored elements.
- `domTree.test.ts` & `a11yTree.test.ts` check that expired reads cannot
retry or fall back, including when the deadline timer has not fired yet.
- `focusSelectors.test.ts` checks that both selector lookup paths
release element references returned after timeout. focused accessibility
tests also check reference cleanup after successful reads.
- protocol & sdk tests cover omitted, zero, positive, & invalid
timeouts, option forwarding in all three sdks, & response waits. the
typescript package test checks that the published snapshot options
include the new field.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds an optional `timeout` param to `page.snapshot()` so callers can
bound the entire snapshot operation. Omitted timeouts now default to 20
seconds instead of running unlimited.

- Exposes `timeout` in the TypeScript, Python, and Go SDKs; passing `0`
keeps snapshots unlimited.
- Uses one deadline for frame readiness, element lookup,
DOM/accessibility tree reads, and frame traversal, and lets snapshots
reuse the caller's remaining time instead of starting a new budget.
- Stops retries, fallback reads (including focus-scope and
ignore-locator fallback), and further frame traversal after expiry,
releasing temporary element references even when they return after the
timeout.
- SDK response waits now add delivery grace to the requested timeout and
skip the deadline entirely for unlimited snapshots.

<sup>Written for commit 4054cdb.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3083?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. -->
Browse 0.10.0 uploaded successfully in [the Release
workflow](https://github.com/browserbase/stagehand/actions/runs/35798682312/job/106985029323),
but the following tag step saw a temporary npm 404 and returned
`unpublished`. The job finished green without pushing the release tag.

Push the validated local tag that Changesets creates after a successful
upload without requiring immediate registry visibility. When no local
tag exists, retain the registry check and original version-bump commit
guard for recovery.

Validation: reproduced the failure with a real HTTP server returning 404
and a bare Git remote, then verified the fix; all 67 release tests,
tooling typecheck, targeted lint/format, and diff checks pass. The diff
changes only the helper and its existing regression test.

The current `browse@0.10.0` tag has been repaired separately to the
exact commit verified in npm provenance. No npm upload or package
version change is part of this PR.


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes the release workflow so an existing local Browse tag is pushed
without waiting for npm registry reads to converge. Previously a
temporary 404 from npm during propagation made the tag step return
`unpublished`, finishing green without creating the release tag. When no
local tag exists, the registry check and the version-bump-commit guard
still run as before.

<sup>Written for commit 345a953.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3015?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. -->
…2821)

# why

Eve agents need an installable Browserbase extension with persistent
browser state and predictable cleanup. This adds the native Stagehand V4
integration as `@browserbasehq/eve` 0.2.

# what changed

- Add `browserbase__run`, `browserbase__snapshot`, and
`browserbase__screenshot` through Eve's native extension API.
- Share one Browserbase session across calls, recover unhealthy
sessions, and release owned resources on explicit close. The next call
can start a fresh session.
- Bundle the shared browser facade, including the cleanup hook and
sanitized errors used by Eve's session owner, and add package build,
release, and Changeset configuration.
- Support Eve 0.68.x, resolve environment credentials when the browser
starts, and inherit Browserbase proxy defaults unless explicitly
overridden.

The [build
script](https://github.com/browserbase/stagehand/blob/ab25295e96476ee3c13c19a8e936348491da0e04/packages/integrations/eve/scripts/stage-facade.mjs)
copies four shared Core files byte-for-byte into Eve's generated,
gitignored source directory. `runtime.ts`, `contract.ts`, and
`redact.ts` are unchanged from the PR base. `tools.ts` adds the host
cleanup hook and error handling; the Eve tool wrappers adapt the
existing Stagehand example.

The [previous implementation in
browserbase/integrations](https://github.com/browserbase/integrations/tree/b7bc81c6fd4e089ab0c0df2b82529b200739e458/packages/eve-browserbase)
already uses Stagehand V4. This PR keeps its npm package identity but
changes the tool API and session lifecycle; none of the 17 tracked Eve
package files is byte-identical to that implementation. The main
implementation review areas are session ownership/recovery, the shared
cleanup/error changes, and packaging/release wiring. Eve's built-in
`web_search` and `web_fetch` remain available;
[#2822](#2822) adds
optional Browserbase replacements. The separate MCP lifecycle change is
in [#3078](#3078); this
native extension does not depend on it. Documentation is in
[#3079](#3079). Merge that
PR before publishing 0.2 so the npm package includes the updated README.

# test plan

Checked after the `main` update at
[`ab25295e9`](ab25295).

Refreshed against current `main`, preserving upstream dependencies and
Eve’s named catalog. The URL-matching test now resolves Playwright Core
through its declared Playwright dependency, so the new examples’ MCP
dependency cannot change which version it tests.

| Command / flow | Observed output | Coverage |
| --- | --- | --- |
| Shared facade build, typecheck and unit tests; Pi
build/typecheck/tests | 136 facade tests and 3 Pi tests passed | Shared
hook/error changes and existing native consumer |
| `CHROME_PATH=<Chrome binary> pnpm --filter
@browserbasehq/stagehand-integrations test:browser` | 6 tests passed |
Browser compatibility against local fixtures |
| Eve package typecheck and `test:unit` | Typecheck passed; 39 tests
passed | Native session ownership, credentials and tool behavior |
| Fresh tarball, strict `publint`, external Eve 0.68.0 consumer | All
passed; `eve build` passed with `BROWSERBASE_API_KEY` unset |
Installable package and credential-free builds |
| Installed SDK and browser extension compared with fresh local build |
Byte-identical; Eve resolves the same SDK | Smoke tests cover the SDK
and browser extension from this branch |
| Packed lifecycle probe and real `eve eval --strict --skip-report
--timeout 300000` | 8/8 gates passed; persistent state, error recovery,
snapshot-ID navigation, 193,444-byte PNG and close/reopen passed |
Native tools with real Browserbase sessions on public Example
Domain/IANA pages |
| Independent session audit | All 5 sessions `COMPLETED`, including the
preliminary harness run; no fallback release needed | Owned-session
cleanup |
Adds [Amel Bajramovic](https://github.com/bosniankicks) to the
contributors list in the README Acknowledgements section.
…2893)

Bounds capture and RPC/batch waits. Two consecutive capture deadlines
are recoverable; a third latches terminal session loss, while a
successful tool call resets the counter. Late completion cannot
overwrite newer snapshot IDs.

Terminal loss rejects queued calls without dispatch. Actions are never
automatically replayed. Regressions cover bounded timeout inputs, late
completion, counter reset, screenshot transport and first-loss handling.

`experimentalBatch` keeps its single `timeout` option (the callback
deadline the browser-side executor enforces). The client bounds the
whole round trip at `timeout` plus a 15-second batch grace
(`CALLBACK_BATCH_CLIENT_GRACE_MS`), because the executor's timeout is
cooperative and can be reported late. A batch that gets no response by
then rejects with `StagehandBatchTimeoutError`; RPC response deadlines
throw `RPCResponseTimeoutError`. Earlier revisions also exposed that
local deadline as a `clientTimeoutMs` option. Nothing passed it, so it
is removed; the default it produced is unchanged.

The facade now calls `page.snapshot()` with `timeout: 0`. Snapshot
gained a 20-second default on main, which fired before the facade's
120-second capture deadline, so a slow snapshot failed as an ordinary
tool error and never counted toward terminal session loss.

Preserves provider/session/age/timeout diagnostics through the host,
checks screenshot byte limits before decoding, and isolates failures in
diagnostic observers. The typed RPC timeout error lives in a focused
public module, keeping internal RPC helpers outside the SDK public-field
contract.

Validation: 120 focused tests and 47 SDK AST/release guards,
SDK/core/eval typechecks, SDK build/publint, and merged
ownership/capture regression checks. At `b14e4ec95`: 345 SDK unit tests
and 156 facade unit tests pass, with SDK and facade typechecks and the
format check clean.

Stack base: `main`. Review this PR relative to its immediate
predecessor.

Reviewer entry points:

-
[`packages/integrations/core/src/facade/tools.ts`](https://github.com/browserbase/stagehand/blob/b14e4ec95e40a44fb9c0ec87383b060a10d4fab6/packages/integrations/core/src/facade/tools.ts)
-
[`packages/sdk-ts/src/batch.ts`](https://github.com/browserbase/stagehand/blob/b14e4ec95e40a44fb9c0ec87383b060a10d4fab6/packages/sdk-ts/src/batch.ts)
-
[`packages/integrations/core/tests/facade-tools.test.ts`](https://github.com/browserbase/stagehand/blob/b14e4ec95e40a44fb9c0ec87383b060a10d4fab6/packages/integrations/core/tests/facade-tools.test.ts)


The CLI startup fix is now included in the parent (#2892), so this PR
focuses on capture/RPC deadlines and recovery. Current main is
incorporated, preserving both the timeout exports and the
runtime-compatibility exports.


Readiness: CI is running on `b14e4ec95e`; it last passed on `65d9c911b7`
([run](https://github.com/browserbase/stagehand/actions/runs/36969426716)).
The one cubic comment (snapshot timeout) is fixed and resolved. Human
review status is unchanged.










Current open stack: #2893 → #2894 → #2902 → #2903 → #2889 → #2904 →
#2905 → #2906 → #2907.
miguelg719 and others added 22 commits October 4, 2026 00:44
Adds Claude native browser use through the shared CUA bridge and
canonical facade. Native tool instructions remain separate from internal
mount instructions, and the shared autonomy policy is injected once
through the native system channel. Includes package, build, and CI
registration.

Retains thinking, tool-result blocks, usage presence, and screenshot
evidence. API history can discard older screenshots without mutating
verification events. Unmatched calls carry a missing-result failure
instead of appearing successful. Diagnostic logs contain tool
name/status/duration; original tool inputs stay in session evidence, and
abort diagnostics are sanitized.

Tab operations use the canonical visible context and readonly
`page.pageId`. Keeper pages cannot enter tab inventory or be
selected/closed; legitimate visible blank pages remain available.
Explicit `tab_id` actions refresh active identity before executing. A
first reference action without cached tab state adds one inventory call
to obtain real IDs. Typed canonical session-loss errors or runner-owned
telemetry stop execution; page error text alone cannot impersonate
browser loss.

Drag uses the SDK `dragAndDrop` primitive. Separate held-button down/up
gestures and modifier clicks receive actionable unsupported errors;
complete drag and ordinary clicks are supported. Partial toolset
configuration preserves member defaults, literal Space is accepted,
`find` text is capped, and transcript clipping preserves surrogate
pairs.

Validation: **72 tests pass across 8 files**, including **55 Claude SDK
tests**, native eval/runner/mount tests, and the compiled facade/MCP
fixture. Tests execute generated snippets through actual canonical
`StagehandFacadeTools` and SDK `Page`/`BrowserContext` objects over
in-memory RPC. Claude SDK and full eval typechecks, matching core/Claude
SDK builds, and scoped formatting pass. Generated test artifacts under
dist/.turbo/node_modules leave the task cache inputs and hash unchanged.
Provider responses are scripted; these checks do not establish live
browser gestures, model performance, or disconnect recovery.

Stack base: `evals/consolidation-15-shared-cua-bridge`. Review this PR
relative to its immediate predecessor.

Reviewer entry points:

-
[`packages/integrations/claude-cua-sdk/src/executor.ts`](https://github.com/browserbase/stagehand/blob/ac0acaffa0d3f05f94d4eef6b8c57a9898b52f73/packages/integrations/claude-cua-sdk/src/executor.ts)
-
[`packages/integrations/claude-cua-sdk/src/session.ts`](https://github.com/browserbase/stagehand/blob/ac0acaffa0d3f05f94d4eef6b8c57a9898b52f73/packages/integrations/claude-cua-sdk/src/session.ts)
-
[`packages/evals/framework/claudeCuaRunner.ts`](https://github.com/browserbase/stagehand/blob/ac0acaffa0d3f05f94d4eef6b8c57a9898b52f73/packages/evals/framework/claudeCuaRunner.ts)






Review fixes: Refresh visible tabs after coordinate and ref actions so
popups appear in the same tool result while keeper tabs stay hidden.
Missing page IDs now raise a typed facade error. Diagnostic tests assert
member names, success status, and duration alongside secret redaction.
Updated tests cover the real SDK/facade and MCP boundaries; all three
review threads are resolved after passing CI.






Current open stack: #2893 → #2894 → #2902 → #2903 → #2889 → #2904 →
#2905 → #2906 → #2907.
Adds Gemini native computer use through the same CUA bridge and
canonical facade. System instructions and cancellation use the SDK
configuration; normalized coordinates map to browser coordinates.
Includes package, build, CI registration, and the shared harness guide.

Stores the actual model-visible tool response and screenshot against its
call ID, with optional fields for older records and no duplicate
per-action captures. Confirmed runner-owned browser loss or a typed core
facade loss is terminal; arbitrary error text, including agent-marked
errors, remains recoverable. Missing, blocked, truncated, and malformed
provider responses fail as SDK errors, and partial tool calls from those
responses are not executed. Every function-call batch is validated
before any member executes. Arbitrary model/resource identifiers are
passed to the provider, with only the optional `google/` alias removed.

Drag uses the existing SDK `dragAndDrop` primitive. Hotkey arrays
execute as one chord, wait honors the requested seconds, and the current
scroll action uses its documented default while retaining the legacy
action's default.

Budgets use `EVAL_GEMINI_CUA_MAX_TURNS`. Explicit empty answers remain
empty, unfinished calls remain failed, and the last model-visible image
is retained when terminal capture is unavailable. That fallback is the
last captured frame, not a fresh terminal screenshot. Transcript
clipping preserves Unicode pairs.

Validation: 72 Gemini SDK/eval tests across seven files pass, including
scripted terminal-response cases and generated executor code exercised
against the actual SDK Page and RPC schemas over an in-memory transport.
The earlier combined Claude/Gemini/shared suite, including the compiled
facade/MCP fixture, passed 101 tests across 14 files before this Gemini
follow-up. Gemini SDK and full eval typechecks and the Gemini SDK build
pass; parent propagation and final combined validation are separate
checks. These are local contract checks; live provider performance and
semantic judge compatibility remain separate gates.

Stack base: `evals/consolidation-16-claude-cua`. Review this PR relative
to its immediate predecessor.

Reviewer entry points:

-
[`packages/integrations/gemini-cua-sdk/src/executor.ts`](https://github.com/browserbase/stagehand/blob/edc3c35f46976a8321d20cabbebd496027d99073/packages/integrations/gemini-cua-sdk/src/executor.ts)
-
[`packages/integrations/gemini-cua-sdk/src/session.ts`](https://github.com/browserbase/stagehand/blob/edc3c35f46976a8321d20cabbebd496027d99073/packages/integrations/gemini-cua-sdk/src/session.ts)
-
[`packages/evals/framework/harnesses/geminiCuaAdapter.ts`](https://github.com/browserbase/stagehand/blob/edc3c35f46976a8321d20cabbebd496027d99073/packages/evals/framework/harnesses/geminiCuaAdapter.ts)








Current open stack: #2893 → #2894 → #2902 → #2903 → #2889 → #2904 →
#2905 → #2906 → #2907.
## Stack

Top-of-stack child of #2906 (`evals/consolidation-17-gemini-cua`).
Review against that immediate parent, not `main`.

## Summary

Port the remaining focused Codex/Stagehand facade hardening from the
experimental
Codex worktree without replacing the consolidation stack's newer shared
runtime.

- Add opt-in facade JSONL tool logging: request/session IDs, actual
arguments/code,
paired starts/ends, timing, errors, bounded result previews and browser
readiness.
Never write logs to MCP stdout; redact known credentials and omit image
payloads.
- Escape Unicode line separators in text tool results, addressing the
stream
  parsing failure observed in the Hostelworld benchmark traces.
- Share isolated HOME/CODEX_HOME creation between the SDK example and
evals;
do not inherit operator plugins/config/thread context. Preserve
file-based auth.
- Abort unexpected MCP servers, await observation capture, and match
evidence by
tool-call ID so unrelated calls/missing final captures do not shift
screenshots.
- Add optional bounded SDK failure artifacts and keep binary payloads
out of
  telemetry without mutating original events.
- Document the difference between Codex event logs and facade server
logs, privacy
  limitations, authentication, and runnable logging commands.

This remains the existing Codex SDK harness with the Stagehand facade,
not a new
native OpenAI computer-use adapter. Preserve the parent's terminal
session-loss
semantics, shared facade API, HardBench dataset, verifier and usage
contracts.
The older experimental `state`/`nodeRepl`/`reset` surface and reconnect
implementation
are not copied wholesale into the newer shared runtime. The original
dirty
worktree remains untouched.

## Validation

- 220 focused tests pass across 23 files (core facade, Codex SDK, eval
adapters).
- 2 standalone Codex example tests pass.
- Built stdio regression verifies the JSONL file is created and contains
paired
  request IDs and error results while the MCP client remains responsive.
- Integration packages and eval ESM/CLI builds; core/Codex/example/evals
typechecks.
- Targeted lint: no errors; warnings remain in existing patterns and
diagnostic
  stringification. `git diff --check` passes.
- No paid model or HardBenchmark rerun; no benchmark score improvement
claimed.

## Operational notes

Logging remains opt-in. Logs/error artifacts may contain sensitive
model/page
content despite best-effort redaction and must be reviewed before
sharing.
Unexpected-server detection aborts observed calls; it is not a security
sandbox.
Keychain-only login is not copied into isolated profiles.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Hardens Codex facade runs with isolated `HOME`/`CODEX_HOME` profiles,
opt-in tool logging, and evidence keyed to tool-call IDs so unmatched or
unrelated calls no longer misplace screenshots.

**New Features**
- Adds opt-in JSONL facade tool logging with request/session IDs,
arguments, timing, errors, and bounded result previews; logs go only to
file or stderr, never MCP stdout, with known credentials redacted and
image payloads omitted.
- Saves bounded SDK failure artifacts to
`STAGEHAND_CODEX_DIAGNOSTICS_DIR` or `EVAL_CODEX_DIAGNOSTICS_DIR`; a
failed diagnostic write never masks the original SDK failure.
- Shares isolated `HOME`/`CODEX_HOME` creation between the SDK example
and evals via a common helper in
`@browserbasehq/stagehand-integrations-codex-sdk`; only file-based
`auth.json` is copied, never plugins, config, stray `CODEX_*` env, or
inherited thread context, and the example now runs in a temporary
working directory and warns Codex to use only the mounted browser tools.

**Bug Fixes**
- Matches probe evidence by tool-call ID so missing final captures no
longer shift screenshots onto the wrong step.
- Aborts on unexpected MCP servers (detection only, not a sandbox).
- Escapes Unicode line separators in text tool results, fixing the
stream parsing failure seen in Hostelworld traces.

<sup>Written for commit bdc69f2.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/2907?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. -->

Current open stack: #2893 → #2894 → #2902 → #2903 → #2889 → #2904 →
#2905 → #2906 → #2907.
…3084)

Two fetches of the stagehand page found no Classifiers section, which
would make the package invisible to every classifier-based browse and
filter on `PyPI: Topic :: Internet :: WWW/HTTP :: Browsers`, `Topic ::
Scientific/Engineering :: Artificial Intelligence`, `Intended Audience
:: Developers`, Development Status, `Typing :: Typed`.

Keywords are also thin (ai, browser, automation, web-scraping, testing),
missing agent, browser-agent, computer-use, playwright, headless. And
there are three PyPI identities in play: stagehand, the stale
stagehand-py, and the now-archived stagehand-python repo. A developer
searching PyPI for "stagehand" gets ambiguous results. Add a deprecation
pointer on stagehand-py.

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
# why
this PR wires the `progress` tracker into `act()`, `extract()`,
`observe()`. before this PR, `act()`, `observe()`, & `extract()` had
their own timeout tracking mechanism, which only checked remaining time
between between major IO steps. a stalled snapshot, model request, or
browser action could keep the call waiting past its timeout. nested work
also did not share the caller's remaining time.

# what changed
- gave each call one shared deadline across snapshots, cache reads &
writes, model requests, & browser work. each step gets only the time
left.
- carried act's deadline through page settling, supplied actions, cached
replay, two-step actions, & self-healing. extract's optional screenshot
& second model request share its deadline too.
- made expiry reject with the caller's timeout error & prevent later
steps. late model or cache responses cannot start another action or
request. browser commands & model requests already sent may still
finish.
- cleaned up settling listeners, temporary element references, & pressed
inputs when interrupted. kept snapshot scope fallback within the same
budget.
- kept the existing defaults: omitted timeouts & `0` remain unlimited.
- removed the unused timeout guard

# test plan
- `service-progress.test.ts` checks expiry during snapshots, cache work,
& model calls for all three services. it verifies that nested work uses
the remaining budget, omitted/zero timeouts stay unlimited, & late
responses cannot resume work. act cases cover cached replay,
self-healing, two-step actions, interrupted fill/drag/key presses, &
settling cleanup. extract cases cover screenshots, image encoding, & its
second model request.
- `serviceTimeouts.test.ts` uses a local browser, a controlled iframe
response, & controlled model responses. it checks that readiness expiry
prevents inference, full-page fallback does not restart the timeout, &
late responses cannot cause clicks or a second extraction request. it
also verifies that act can use the full-page fallback while time remains
& that an expired supplied action stays stopped after its iframe loads.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Gives `act()`, `extract()`, and `observe()` a shared `progress` deadline
so timeouts apply across snapshots, cache reads/writes, model requests,
and browser actions. Before, each service checked remaining time only
between major steps, so stalled work could outlive its timeout and
nested work never shared the caller's budget.

- One deadline now covers all work in a call; nested steps inherit the
caller's remaining time.
- Expiry rejects with the caller's timeout error and blocks any later
steps, though already-sent browser commands and model requests may still
finish.
- Interruption cleans up settling listeners and temporary element
references, releases held keys and a pressed mouse button exactly once
(the mouse at its last dispatched position) when a drag expires mid-way,
and drops held cache keys.
- Omitted or `0` timeouts remain unlimited; the unused `timeoutGuard`
helper is removed.
- Added unit and integration coverage for expiry during each step,
budget inheritance, late responses, and cleanup.

<sup>Written for commit f9753f8.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3109?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. -->
Mirrored from external contributor PR #2789 after approval by
@charlypoly.

Original author: @antonvishal
Original PR: #2789
Approved source head SHA: `5d32c83ec49a1d1dfb1ce40d42a74593196635bc`

@antonvishal, please continue any follow-up discussion on this mirrored
PR. When the external PR gets new commits, this same internal PR will be
marked stale until the latest external commit is approved and refreshed
here.

## Original description
## Why

Humans and coding agents need browser workflows they can understand,
reuse, and combine into new jobs.

These cookbooks are meant to be building blocks.

## What

- Add matching runnable projects under `packages/cookbooks`.
- Keep the docs focused on the workflow and make each example easy for
both humans and agents to understand and adapt.
- Support TypeScript, Python, and Go for the core browser workflows.

## Follow-ups

- [ ] Simplify the clone/sparse-checkout setup into a one-command start
- [ ] Add more cookbooks by combining existing patterns into new
workflows

<img width="3008" height="1656" alt="BetterShot_2026-10-03-21-28-28"
src="https://github.com/user-attachments/assets/5a9d7d59-4fdf-4fa6-a755-3378fbdab194"
/>

<!-- external-contributor-pr:owned source-pr=2789
source-sha=5d32c83ec49a1d1dfb1ce40d42a74593196635bc claimer=charlypoly
-->

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a Cookbooks tab to the docs with five runnable browser workflow
examples (persisted login, paginated catalog export, files to bucket,
form submission approval, and an AI SDK research agent), each with an
agent prompt, setup instructions, and source code. Reorganizes the
existing example projects under `packages/examples/showcase` so
cookbooks get their own directory, and updates the `justfile`,
`.gitignore`, and code ownership accordingly. The new `just cookbook`
command runs any cookbook from the repo root.

**Migration**
- `just cookbook` runs cookbooks that previously lived under
`packages/examples`; the old `just cookbook <slug>` path for showcase
scripts is now `just showcase-script`.
- `.env` files for showcase examples now live in
`packages/examples/showcase/.env` instead of `packages/examples/.env`.
- The `saas-pricing-monitor` example script was removed as part of the
showcase reorg; its workflow still exists under the showcase directory.

<sup>Written for commit 40562dc.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3116?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. -->

---------

Co-authored-by: Vishal Anton <vishalanton@appexert.com>
Co-authored-by: VIshal Anton <166398166+antonvishal@users.noreply.github.com>
Co-authored-by: Charly Poly <charly@browserbase.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
# Summary

Add a Claude Toolset integration guide to the Stagehand v4 docs.

# Why

Developers need setup instructions for connecting Claude to local Chrome
or Browserbase through the published Stagehand Claude SDK packages.

# What changed

- Add TypeScript and Python installation, browser-task examples, session
cleanup, Browserbase configuration, and domain-filtering limitations.
- Link the guide from navigation and integration overviews,
distinguishing its native toolset from the shared MCP tool contract.

# Testing (if applicable)

- `npx --yes mint@4.2.788 validate`: passed.
- `npx --yes mint@4.2.788 broken-links --check-anchors --check-redirects
--check-snippets`: passed.
- `npx --yes mint@4.2.788 a11y --skip-contrast`: passed.
- Python snippet syntax and `git diff --check`: passed.
- Live Claude execution and published package exports have not been
verified; the registry releases were placeholders when checked.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a Claude Toolset integration guide to the Stagehand v4 docs,
covering setup for the published `stagehand-claude-sdk` packages in
TypeScript and Python.

- Documents installation, local Chrome and Browserbase launch modes,
domain restrictions, and session cleanup.
- Links the guide from navigation and both integration overviews,
clarifying that Claude Toolset uses a native browser toolset rather than
the shared MCP tool contract.

<sup>Written for commit 82243b2.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3122?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>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3122?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3122&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
# why
- there is no golang sdk that applies here, so we can ignore the test
that checks for a golang tab
# what changed
- omitted the cua toolset page form sdk reference test


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adjusts the SDK reference test so the Claude CUA toolset page no longer
requires a Go snippet, since that toolset has no Go SDK.

- Adds per-page language requirements so pages can support a subset of
the standard TypeScript, Python, and Go set.
- Updates the test to fail only when a page misses a language it
actually supports.

<sup>Written for commit 61e8e79.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3134?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="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3134?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3134&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# what changed
- updated Python dependencies in the CrewAI integration, DeepAgents
runner and examples, and Python SDK development environment
- bumped CrewAI, crewai-tools, crewai-cli, and crewai-core from
`1.15.14` to `1.15.24`
- raised the CrewAI and crewai-tools minimums to `1.15.24`, which
requires PyJWT `>=2.15.0`
- updated ChromaDB `1.1.1` -> `1.5.9` and removed backoff and posthog
transitively
- updated PyJWT `2.13.0` -> `2.15.0` in CrewAI and the DeepAgents
runner/local example; added `pyjwt>=2.15.0,<3` to the two DeepAgents
manifests
- updated urllib3 `2.7.0` -> `2.8.0` and declared `urllib3>=2.8.0,<3` in
CrewAI and all three DeepAgents environments
- bumped LangGraph `1.2.10/1.2.11` -> `1.2.14` in the DeepAgents runner,
local example, and managed example
- declared `langgraph>=1.2.14,<1.3`, which requires the patched
langgraph-sdk `>=0.4.6,<0.5.0`
  - updated langgraph-sdk `0.4.2/0.4.3` -> `0.4.6`
- updated CrewAI's multidict `6.7.1` -> `6.9.1` and OAuthlib `3.3.1` ->
`4.0.0`, with explicit minimums and major-version upper bounds
- bumped the Python SDK's pytest development pin `9.0.2` -> `9.0.3`
- declared security minimums in project dependencies so independent
resolutions enforce them; no new dependency overrides were needed

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Bumps transitive Python dependencies across the CrewAI integration,
DeepAgents runner and examples, and the Python SDK development
environment to pick up security fixes.

- CrewAI, `crewai-tools`, `crewai-cli`, and `crewai-core` move from
`1.15.14` to `1.15.24`, raising the CrewAI minimums and requiring PyJWT
`>=2.15.0`.
- ChromaDB bumps `1.1.1` → `1.5.9`, dropping `backoff` and `posthog`
from the dependency graph.
- PyJWT (`2.13.0` → `2.15.0`) and urllib3 (`2.7.0` → `2.8.0`) get
explicit minimums in CrewAI and the DeepAgents manifests so independent
resolutions enforce them; no new overrides were needed.
- LangGraph (`1.2.10`/`1.2.11` → `1.2.14`) and `langgraph-sdk`
(`0.4.2`/`0.4.3` → `0.4.6`) update across the DeepAgents environments,
with `langgraph>=1.2.14,<1.3` declared to pull in the sdk authorization
fix.
- multidict (`6.7.1` → `6.9.1`) and OAuthlib (`3.3.1` → `4.0.0`) update
in CrewAI with minimums and major-version upper bounds.
- pytest dev pin bumps `9.0.2` → `9.0.3` in the Python SDK.

<sup>Written for commit 814eecf.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3133?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="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3133?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3133&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
Mirrored from external contributor PR #3105 after approval by
@miguelg719.

Original author: @alanagoyal
Original PR: #3105
Approved source head SHA: `b48795840bce28f4c26f48b35183bb035a1ea519`

@alanagoyal, please continue any follow-up discussion on this mirrored
PR. When the external PR gets new commits, this same internal PR will be
marked stale until the latest external commit is approved and refreshed
here.

## Original description
# why

this is a first step toward #2841. today, turning a bug report into a
pinned fixture takes a manually built mirror. this adds a small recorder
so a page state can be saved locally and used in an `extract()` or
`observe()` regression.

# what changed

- added `fixture:record` in `packages/evals`: pass a url, output
directory, and optional playwright setup script
- saves `index.html` plus a manifest with the source url, capture time,
viewport, and limitations
- preserves computed styles, resolved links, and current form state;
removes scripts and remote assets and adds a restrictive csp
- rejects frames/open shadow dom and refuses to overwrite an existing
fixture
- documented capture, replay, refresh, and content review

before: reproduce against the live site or build a mirror by hand.
after: run setup to reach the relevant state, record it, and write an
assertion against the saved page.

this is scoped to static observations. it doesn't replay application
behavior, generate assertions, or migrate the old live-site tasks
mentioned in the issue, which aren't on current v4 main.

proposed follow ups:

1. migrate a few representative current evals to recorded fixtures
2. add a reusable bug-report-to-fixture-and-regression-test workflow

# test plan

- recorder/browser tests cover form state, visibility, links, blocked
resource loads, output protection, unsupported content, and the cli
setup workflow
- added a real stagehand extraction test using a reduced reproduction of
#2624, with a deterministic model adapter and no api keys
- added dom-sensitive validation through real `stagehand.observe()`
calls: source and fixture prompts match, hidden controls stay hidden,
the dynamic accessible name and edited form state survive, and the
returned xpath resolves to the intended button
- replay disables the original page and stylesheet; a negative control
removes captured visibility and confirms that stagehand sees the leaked
hidden control and the validation rejects the lossy fixture
- confirmed both source and recorded pages fail when the historical
schema-key bug is restored, then pass with the upstream fix; their
extraction prompts also match after normalizing element ids

the schema check validates one historical transport regression; the
synthetic checkout checks dom fidelity for the supported patterns above.
neither claims general site fidelity or model reasoning quality.

local checks:

- `just install`, `just build`, `just fmt`, `just check`, and `just
test` passed
- all 10 recorder/extraction/observation browser tests passed separately
- 1,031 eval unit tests, 750 python tests (1 existing skip), and the go
sdk/generator suites passed
- an existing sdk browser smoke test hit its 10-second timeout during
concurrent runs; it passed in isolation, then all typescript tasks
passed with `--concurrency=1` and the final `just test` passed using
those cached results. no timeout or assertion changes

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a static observation task recorder in `packages/evals` so
`extract()` and `observe()` regressions can run against a saved local
page instead of the live site.

- `task:record` takes a URL, output directory, and optional Playwright
setup script, then writes `index.html` plus a manifest with source URL,
capture time, viewport, and limitations.
- Preserves computed styles, resolved links, and current form state;
strips scripts and remote assets and adds a restrictive CSP.
- Rejects frames and open shadow DOM; refuses to overwrite existing
tasks.
- Adds a real Stagehand extraction regression for the #2624 schema-key
bug using a deterministic model adapter, plus an `observe()` fidelity
test on a synthetic checkout page showing edited state, accessible
names, and CSS-hidden controls survive replay.
- Includes a negative control that detects loss of captured visibility
styles, and recording tests covering form state, visibility, links,
blocked resources, output protection, and CLI setup.

<sup>Written for commit 503c421.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3106?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>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3106?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3106&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

<!-- external-contributor-pr:owned source-pr=3105
source-sha=b48795840bce28f4c26f48b35183bb035a1ea519 claimer=miguelg719
-->

---------

Co-authored-by: alanagoyal <alanaan@gmail.com>
Co-authored-by: miguel <miguelg71921@gmail.com>
# why

Sibling to #2933. That PR lets callers inject a `Browserbase` SDK
instance. This PR takes the alternative approach: Stagehand keeps
building the Browserbase client, and callers pass the client's HTTP
settings instead.

- One `apiKey` authenticates both Browserbase and the Stagehand runtime.
An injected client could carry a different key.
- Stagehand controls the SDK version and how the client is built. A
hand-made or mismatched-version instance can't break calls like
`extensions.delete` that depend on SDK-specific options.
- Python can offer the same option, which #3119 does. The shared fields
(`timeout`, `max_retries`, `default_headers`, `default_query`) exist in
both SDKs.

The options are nested under `clientOptions` rather than flattened,
because `browserbase.launch()` passes unknown keys through to
`SessionCreateParams`, which already has a `timeout` field (the session
timeout in seconds).

# what changed

- `clientOptions?: BrowserbaseClientOptions` on `browserbase.launch()`
and `browserbase.connect()`. The type is `Pick<ClientOptions, "timeout"
| "maxRetries" | "defaultHeaders" | "defaultQuery" | "fetch">`,
validated by a strict schema. `apiKey` and `baseURL` are rejected inside
it. `BrowserbaseClientOptions` is exported.
- In the cross-language parity test,
`BrowserbaseConnectOptions.client_options` is temporarily exempt for
Python, until the stacked #3119 removes the exemption, and pending for
Go. Go talks to Browserbase over its own `net/http` client rather than
the official SDK.
- Adds docs (`configuration/browser.mdx`, TypeScript only for now) and a
minor changeset for `@browserbasehq/stagehand`.

# test plan

- [x] `tsc --noEmit`, oxfmt, oxlint; sdk-ts unit tests and
`rules/ast-grep` parity tests (31 files, 407 tests)
- [x] One test builds a real `@browserbasehq/sdk` client with a spy
`fetch` and checks that the request URL, `defaultQuery`,
`defaultHeaders` and API key are applied
- [x] Published-tarball consumer type fixture uses
`BrowserbaseClientOptions`
- [ ] No live Browserbase session was launched
)

# why

Stacked on #3119 (Python), which is stacked on #3118 (TypeScript). Those
PRs add Browserbase client options to `browserbase.launch()` /
`browserbase.connect()` in TS and Python. This PR adds the Go
equivalent, so the three SDKs are at parity again and the parity test no
longer needs a Go exemption.

# what changed

- New `BrowserbaseClientOptions` struct, set as `ClientOptions
*BrowserbaseClientOptions` on both `BrowserbaseLaunchOptions` and
`BrowserbaseConnectOptions`:
- `Timeout time.Duration`: applies to each attempt; 0 keeps the 60s
default.
  - `MaxRetries *int`: nil keeps the default of 2.
- `DefaultHeaders map[string]string`, `DefaultQuery map[string]string`.
  - `HTTPClient *http.Client`: owned by the caller and never modified.
- Go talks to Browserbase over its own `net/http` client, so the
internal options it already had (HTTP client, max retries) are now
exposed, plus headers and query.
- The timeout is applied per attempt through the request context, both
for the default client and for a client the caller passes in, and it
also covers reading the response body. The default client no longer sets
`http.Client.Timeout` itself. If an attempt times out, only requests
that are safe to resend (retrieve, release, delete) are retried, each
with a new deadline. Creates fail immediately.
- Negative `Timeout` or `MaxRetries`, invalid header names, and header
values containing control characters are rejected before any request is
sent.
- `ClientOptions` is never sent in the session-create body; a test
checks the body contents.
- Removes `pendingGoBrowserFields` from the cross-language parity test.
- Docs: the client-options section is a TypeScript / Python / Go tab
group again.
- Adds a minor changeset for `@browserbasehq/stagehand-go`. This PR is
the only change in the stack that releases Go.

# header precedence

Same rule as TS and Python: `DefaultHeaders` override Stagehand's own
headers on conflict, including `X-BB-API-Key` and `User-Agent`. Both
Browserbase SDKs apply caller default headers last; this was checked in
their source (`@browserbasehq/sdk` `index.js` `defaultHeaders`, and the
Python `_base_client`). Go still rejects invalid header names or values
before sending.

# test plan

- [x] `go vet`; gofmt (prints nothing); `go test -race` on every package
except examples; generator `--check`; `scripts/check-examples.sh`
- [x] New `browserbase_client_options_test.go` uses `httptest` servers
to cover:
- options reaching requests, and later changes to the caller's maps
having no effect;
- default headers and query on POST and GET, with caller defaults
overriding Stagehand's headers (mutation-checked);
  - `MaxRetries` set to 0 and 1, and the default;
- the per-attempt timeout, including a retry getting a new deadline and
the deadline covering the response body;
  - a caller `HTTPClient` being used and left unmodified;
- invalid options failing with zero requests reaching the server, on
both launch and connect;
  - full launch and connect through the real factory.
- [x] Mutation-checked: with the per-attempt deadline removed, the
timeout test fails in about 5s with a clear message.
- [x] `rules/ast-grep` parity tests (Go exemption removed), docs tests,
the TS suite, oxfmt, oxlint, `check-changesets`
- [ ] Plain `go test ./...` fails only because
`packages/sdk-go/examples` doesn't build as a single package; that was
already the case. CI and the justfile exclude `/examples`.
- [ ] No live Browserbase session was launched
## Summary
- Replace the externally hosted DeepWiki badge with a repository-local
SVG.
- Use a static Ask DeepWiki badge styled to match the README badges;
keep the DeepWiki destination unchanged.
- Set explicit dimensions to match the neighboring 32px badges.

## Why
The external badge endpoint returns HTTP 429 with a Vercel challenge,
consistent with the broken image in the README. Hosting the badge
locally removes that external dependency.

## Validation
- git diff --check passed.
- SVG XML parsing passed.
- Verified the README references the local asset and preserves the
DeepWiki destination.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Replaces the externally hosted DeepWiki badge in the README with a
repository-local SVG at `media/deepwiki.svg`, since the hosted endpoint
returns HTTP 429 with a Vercel challenge that broke the image. The new
badge is styled to match the neighboring 32px badges, keeps the same
DeepWiki destination, and passes `git diff --check` and SVG XML parsing.

<sup>Written for commit c143ac1.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3136?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="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3136?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3136&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Disables Browserbase proxies in CI eval runs so tests use direct browser
connections instead of proxied ones.

<sup>Written for commit acd3b5b.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3143?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="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3143?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3143&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
GitHub Pages has been unreliable for the eval sites, so they now also
deploy to Vercel at `https://stagehand-eval-sites.vercel.app/`. This PR
swaps the host. Paths are unchanged:

```
https://browserbase.github.io/stagehand-eval-sites/sites/<name>/…
https://stagehand-eval-sites.vercel.app/sites/<name>/…
```

**What changed (76 files)**
- Every `browserbase.github.io/stagehand-eval-sites/` URL across evals
tasks, sdk-ts tests, the TS/Python/Go examples and the docs is now the
Vercel URL. `git grep 'github\.io/stagehand-eval-sites'` matches only
`get_url.ts`.
- `packages/evals/core/tasks/page-info/get_url.ts` stored the host as an
escaped regex. Its allowlist now accepts both hosts.
- oxfmt reflowed lines where the shorter URL now fits on one line. Apart
from `get_url.ts`, each file matches `main` once the host is normalized
and whitespace and commas are ignored.

**Verified against the Vercel host**
- All 114 files under `sites/` are byte-identical to Pages (sha256) with
matching content types.
- All 83 site directories redirect from `/sites/x` to `/sites/x/`, as on
Pages.
- All 59 referenced URLs return 200, and repo files outside `sites/` are
not served.
- In Browserbase sessions, the final URL, title, visible text length and
out-of-process iframe count match Pages for every page tested. The OOPIF
fixtures, whose child frames stay on `seanmcguire12.github.io`, still
produce a separate-process iframe target; the same-origin iframe
fixtures still don't.

**Related:** browserbase/stagehand-eval-sites#80 (Vercel config) and
browserbase/stagehand-eval-sites#81 (self-links made relative, so the
`ionwave` URL assertion holds on either host).

GitHub Pages stays up, so older commits and published examples keep
working. To roll back, revert this PR.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Points eval sites at Vercel instead of GitHub Pages because Pages has
been unreliable. The host changes from
`https://browserbase.github.io/stagehand-eval-sites/` to
`https://stagehand-eval-sites.vercel.app/`; paths under `sites/` are
unchanged.

**Details**
- Updates every eval-sites URL across evals tasks, sdk-ts/Go/Python
examples and tests, and docs.
- `get_url.ts` now accepts both the old and new hosts, and lines are
reflowed where the shorter URL fits.
- Verified the Vercel host serves byte-identical files with matching
content types, redirects, and 200s for all referenced URLs.
- GitHub Pages stays up, so rollback is just reverting this PR.

<sup>Written for commit 0f51333.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3141?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="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3141?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3141&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

**Merge order:** browserbase/stagehand-eval-sites#81 must be merged and
live on Vercel before this PR. `act/ionwave` clicks a link on that page
and asserts the Vercel URL. Without #81, the link still points to GitHub
Pages and the eval fails on every model.
#3140)

# why
- `localBrowser.connect()` currently loads the bundled extension even
when Stagehand is already installed
- the `extensionId` param was also opaque (often confused with the
browserbase extension ID), & users should not need to know what the
extension ID is to connect to a browser

# what changed
- discover the installed Stagehand extension before loading the bundle
in TypeScript, Python, & Go
- load the bundled extension **on local connect only** when none is
installed or discovery is unsupported
- keep disabled, ambiguous, & incompatible installations as errors
- deprecate and ignore extension IDs on local & Browserbase connect;
supplied IDs no longer select an extension or bypass discovery
- keep Browserbase launch's uploaded-extension ID supported
- defer Python bundle lookup & Go extraction until fallback loading,
with Go cleanup on failure & shutdown

# test plan
- `cdpClient.test.ts`, `test_cdp_client.py`, & `cdp_client_test.go` use
fake CDP responses to verify installed extensions are reused, missing
extensions trigger loading, & unsupported discovery falls back only for
local connections. disabled, ambiguous, malformed, & permission-error
responses fail without loading.
- factory tests in all three SDKs now check supplied & empty connect IDs
are ignored and never forwarded to CDP. Browserbase connect always
selects discovery, while launch keeps its uploaded-extension ID & client
options.
- Python tests verify bundle lookup is deferred & cancellation during
discovery or loading closes the connection. Go tests verify extraction
happens only on fallback, its directory stays available during
initialization, & cleanup runs once on close, initialization failure, or
cancellation.
- connection tests verify discovered IDs select the correct worker &
incompatible runtimes fail without loading a replacement. loading
failures propagate without retrying, & cancellation prevents further
loading work.
- `localExtensionDiscovery.test.ts` runs against real Chrome with &
without Stagehand already installed. it connects with an ignored ID,
opens a page through Stagehand, & checks that the browser has exactly
one Stagehand installation, preserving the existing installation's ID
when reusing it


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Local connects now discover an installed Stagehand extension before
falling back to the bundled one, and the `extensionId` parameter on
connect calls is deprecated and ignored across all SDKs.

- Reuses the installed extension in local and Browserbase connections,
falling back to loading the bundled extension only for local connects
when none is installed or discovery is unsupported.
- Disabled, ambiguous, malformed, and permission-error extension
inventories fail without loading a fallback.
- `localBrowser.connect()` and `browserbase.connect()` ignore extension
IDs, including empty strings, and always discover; Browserbase launch
keeps its uploaded-extension ID.
- TypeScript connect options accept the ignored `extensionId` at the
type level, so code can pass `undefined` or an empty string without
compiler errors.
- Python and Go defer bundle lookup/extraction until fallback loading,
with Go cleanup on failure and shutdown.
- Users no longer need to know the extension ID to connect.

<sup>Written for commit 1891573.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3140?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="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3140?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3140&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
- unspecified type was causing TS to infer it incorrectly
# what changed
- specified the correct type


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes a TypeScript type inference issue in the docs SDK reference test
by explicitly typing the `sdkSlugs` set as `Set<string>`.

<sup>Written for commit 71688c1.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3145?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="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3145?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3145&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# what changed
- added docs for `onToolsAdded()` & `onToolsRemoved()` hooks
- also updated the docs test to remove these events from ignored list


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds reference documentation for the `onToolsAdded` and `onToolsRemoved`
hooks for TypeScript, Python, and Go, and removes the docs test
exception that previously skipped coverage for these hooks.

- Documents the subscription lifecycle, tool identity rules, and
callback signatures for `page.onToolsAdded()` and
`page.onToolsRemoved()`.
- Updates the WebMCP reference page to link to the new `onToolsAdded()`
docs.
- Removes `page/on-tools-added` and `page/on-tools-removed` from the
unreleased reference methods set so the SDK surface test now requires
these headings on every language page.

<sup>Written for commit a692e4d.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3148?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="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3148?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3148&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
`waitForSelector()` did not include frame resolution or locator world
readiness in its timeout. time spent preparing or retrying the browser
wait was not deducted from its timeout. the browser helper also turned
zero into a fresh 30-second wait, & could keep watching the page after
the caller timed out.

# what changed
- gave selector waits one shared deadline across frame resolution,
locator-world readiness, & the element wait. internal calls reuse their
parent's remaining time without taking ownership of its progress.
- calculated the browser timeout immediately before dispatch, including
retries after a lost execution context. expired calls cannot start
another wait.
- kept the 30-second default & made explicit `0` unlimited throughout
the wait.
- gave each browser wait a disposable handle. completion, timeout, &
failure release its observers, timers, DOM-ready listener, & remote
reference. handles returned after expiry are cleaned up too; concurrent
waits stay independent.
- bounded cleanup & kept it in the original context. cleanup failure
cannot replace the operation's error or trigger a new locator-world
lookup.
- fixed observer setup before the document root exists & prevented
queued callbacks from installing observers after settlement

# test plan
- `understudy/waitForSelector.test.ts` checks the default, finite, &
unlimited deadlines, inherited progress ownership, & time consumed by
resolution, readiness, & context recovery. it also covers expiry before
dispatch, late installation & results, failed or stalled cleanup,
session closure, & separate handles for concurrent waits.
- `tests/wait-for-selector.test.ts` checks all four element states,
finite expiry, unlimited waits beyond 30 seconds, & cleanup happening
once. cases cover early DOM readiness, queued callbacks after
settlement, shadow-root scanning, partial installation failure, &
disposing one wait while another continues.
- the local-browser `waitForSelector.test.ts` adds a held iframe
response followed by delayed element creation. it checks that both
phases share a finite budget & that unlimited or longer waits succeed.
existing cases retain coverage for css, xpath, iframe hops, visibility,
& open/closed shadow roots; short state & timeout tests use HTTP
fixtures so data-page setup does not consume their budget.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes `waitForSelector()` so frame resolution, locator-world readiness,
and the element wait share one timeout, and `timeout: 0` now means
unlimited instead of a fresh 30-second wait.

**Bug Fixes**
- Frame resolution and locator-world readiness time now counts against
the same deadline as the element wait.
- Expired calls cannot start a new wait; retries after a lost execution
context recalculate the remaining budget.
- `timeout: 0` is unlimited while the default remains 30 seconds, and
the Go, Python, and TypeScript SDK RPC clients now skip their response
deadline when a selector wait passes an explicit `0`.
- Waits dispose observers, timers, and the remote handle on failure or
timeout; on success only the handle is released, and cleanup failure
cannot mask the operation's error.

<sup>Written for commit bcd7eeb.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3146?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="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3146?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3146&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @browserbasehq/eve@0.2.0

### Minor Changes

- [#2821](#2821)
[`a237c77`](a237c77)
Thanks [@shrey150](https://github.com/shrey150)! - Replace the Eve
extension's browser and web tools with Stagehand V4 `run`, `snapshot`,
and `screenshot`.

### Patch Changes

- [#3115](#3115)
[`7abca76`](7abca76)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - update the
Eve peer dependency to ^0.71.2 to use upstream security fixes. Requires
Eve 0.71.2 or later within the 0.71.x release line.

- Updated dependencies
[[`34edfa3`](34edfa3),
[`a837acf`](a837acf),
[`4da1a21`](4da1a21),
[`5802f59`](5802f59),
[`819db28`](819db28),
[`0210688`](0210688),
[`666b6fa`](666b6fa),
[`f3543d3`](f3543d3),
[`f2060a6`](f2060a6),
[`1562d35`](1562d35),
[`7d8dcef`](7d8dcef),
[`476658b`](476658b),
[`70f4e91`](70f4e91)]:
  - @browserbasehq/stagehand@4.2.0
## @browserbasehq/stagehand@4.2.0

### Minor Changes

- [#3030](#3030)
[`34edfa3`](34edfa3)
Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Export
browser pages as PDF bytes in TypeScript, Python, and Go, with
configurable print settings and timeouts, and optional local file saving
in TypeScript and Python.

- [#3118](#3118)
[`a837acf`](a837acf)
Thanks [@miguelg719](https://github.com/miguelg719)! - Add
`clientOptions` to `browserbase.launch()` and `browserbase.connect()`.
Thanks to [@pr1m8](https://github.com/pr1m8) for the original proposal
that motivated this feature.

- [#3083](#3083)
[`666b6fa`](666b6fa)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - expose a
timeout option for page.snapshot() across all sdks, defaulting to 20
seconds.
set it to 0 for unlimited execution. one budget covers the whole
snapshot capture.

- [#3140](#3140)
[`f2060a6`](f2060a6)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! -
automatically discover Stagehand extensions when connecting to browsers.
deprecate & ignore extension IDs passed into .connect().

- [#2916](#2916)
[`476658b`](476658b)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add page
level hooks for webmcp tools added and webmcp tools removed events.

### Patch Changes

- [#3045](#3045)
[`4da1a21`](4da1a21)
Thanks [@github-actions](https://github.com/apps/github-actions)! - Keep
telemetry disabled unless an OTLP traces endpoint is explicitly
configured.

- [#2893](#2893)
[`5802f59`](5802f59)
Thanks [@miguelg719](https://github.com/miguelg719)! - Bound
experimental batch and RPC deadlines so callers can stop waiting without
replaying actions or accepting late capture state.

- [#2894](#2894)
[`819db28`](819db28)
Thanks [@miguelg719](https://github.com/miguelg719)! - Add configurable
bounded CDP heartbeats and sanitized disconnect diagnostics with cleanup
on shutdown.

- [#2892](#2892)
[`0210688`](0210688)
Thanks [@miguelg719](https://github.com/miguelg719)! - Release a newly
created Browserbase session when initial attachment fails, and support
upload retries

- [#2978](#2978)
[`f3543d3`](f3543d3)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Fix locator
failures when entering loading iframes, and correctly target iframe
elements when an XPath ends at the iframe.

- [#3033](#3033)
[`1562d35`](1562d35)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
per-call locator timeouts across TypeScript, Python, & Go. one timeout
covers frame readiness, element lookup, & execution, including typing
delays & highlight duration. the default is 20 seconds. setting timeout
to 0 disables it.

- [#3146](#3146)
[`7d8dcef`](7d8dcef)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Make
selector waits include frame readiness in their timeout, support
unlimited waits with `timeout: 0`, and clean up observers when the wait
ends.

- [#3052](#3052)
[`70f4e91`](70f4e91)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Match
native XPath semantics for `text()` predicates when a shadow root routes
locators through the composed-tree parser
## @browserbasehq/stagehand-extension@1.1.0

### Minor Changes

- [#3030](#3030)
[`34edfa3`](34edfa3)
Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Export
browser pages as PDF bytes in TypeScript, Python, and Go, with
configurable print settings and timeouts, and optional local file saving
in TypeScript and Python.

- [#3083](#3083)
[`666b6fa`](666b6fa)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - expose a
timeout option for page.snapshot() across all sdks, defaulting to 20
seconds.
set it to 0 for unlimited execution. one budget covers the whole
snapshot capture.

- [#2916](#2916)
[`476658b`](476658b)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add page
level hooks for webmcp tools added and webmcp tools removed events.

### Patch Changes

- [#3045](#3045)
[`4da1a21`](4da1a21)
Thanks [@github-actions](https://github.com/apps/github-actions)! - Keep
telemetry disabled unless an OTLP traces endpoint is explicitly
configured.

- [#2896](#2896)
[`7919934`](7919934)
Thanks [@miguelg719](https://github.com/miguelg719)! - Snapshot
references remain valid across same-origin and out-of-process frame
captures

- [#2978](#2978)
[`f3543d3`](f3543d3)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Fix locator
failures when entering loading iframes, and correctly target iframe
elements when an XPath ends at the iframe.

- [#3033](#3033)
[`1562d35`](1562d35)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
per-call locator timeouts across TypeScript, Python, & Go. one timeout
covers frame readiness, element lookup, & execution, including typing
delays & highlight duration. the default is 20 seconds. setting timeout
to 0 disables it.

- [#3146](#3146)
[`7d8dcef`](7d8dcef)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Make
selector waits include frame readiness in their timeout, support
unlimited waits with `timeout: 0`, and clean up observers when the wait
ends.

- [#3052](#3052)
[`70f4e91`](70f4e91)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Match
native XPath semantics for `text()` predicates when a shadow root routes
locators through the composed-tree parser
## @browserbasehq/stagehand-protocol@2.1.0

### Minor Changes

- [#3030](#3030)
[`34edfa3`](34edfa3)
Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Export
browser pages as PDF bytes in TypeScript, Python, and Go, with
configurable print settings and timeouts, and optional local file saving
in TypeScript and Python.

- [#3083](#3083)
[`666b6fa`](666b6fa)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - expose a
timeout option for page.snapshot() across all sdks, defaulting to 20
seconds.
set it to 0 for unlimited execution. one budget covers the whole
snapshot capture.

- [#2916](#2916)
[`476658b`](476658b)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add page
level hooks for webmcp tools added and webmcp tools removed events.

### Patch Changes

- [#3045](#3045)
[`4da1a21`](4da1a21)
Thanks [@github-actions](https://github.com/apps/github-actions)! - Keep
telemetry disabled unless an OTLP traces endpoint is explicitly
configured.

- [#3033](#3033)
[`1562d35`](1562d35)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
per-call locator timeouts across TypeScript, Python, & Go. one timeout
covers frame readiness, element lookup, & execution, including typing
delays & highlight duration. the default is 20 seconds. setting timeout
to 0 disables it.
## @browserbasehq/stagehand-go@4.2.0

### Minor Changes

- [#3030](#3030)
[`34edfa3`](34edfa3)
Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Export
browser pages as PDF bytes in TypeScript, Python, and Go, with
configurable print settings and timeouts, and optional local file saving
in TypeScript and Python.

- [#3123](#3123)
[`100e201`](100e201)
Thanks [@miguelg719](https://github.com/miguelg719)! - Add
`ClientOptions` to `LaunchBrowserbase` and `ConnectBrowserbase`.

- [#3083](#3083)
[`666b6fa`](666b6fa)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - expose a
timeout option for page.snapshot() across all sdks, defaulting to 20
seconds.
set it to 0 for unlimited execution. one budget covers the whole
snapshot capture.

- [#3140](#3140)
[`f2060a6`](f2060a6)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! -
automatically discover Stagehand extensions when connecting to browsers.
deprecate & ignore extension IDs passed into .connect().

- [#2916](#2916)
[`476658b`](476658b)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add page
level hooks for webmcp tools added and webmcp tools removed events.

### Patch Changes

- [#3045](#3045)
[`4da1a21`](4da1a21)
Thanks [@github-actions](https://github.com/apps/github-actions)! - Keep
telemetry disabled unless an OTLP traces endpoint is explicitly
configured.

- [#2896](#2896)
[`7919934`](7919934)
Thanks [@miguelg719](https://github.com/miguelg719)! - Snapshot
references remain valid across same-origin and out-of-process frame
captures

- [#2978](#2978)
[`f3543d3`](f3543d3)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Fix locator
failures when entering loading iframes, and correctly target iframe
elements when an XPath ends at the iframe.

- [#3033](#3033)
[`1562d35`](1562d35)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
per-call locator timeouts across TypeScript, Python, & Go. one timeout
covers frame readiness, element lookup, & execution, including typing
delays & highlight duration. the default is 20 seconds. setting timeout
to 0 disables it.

- [#3146](#3146)
[`7d8dcef`](7d8dcef)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Make
selector waits include frame readiness in their timeout, support
unlimited waits with `timeout: 0`, and clean up observers when the wait
ends.

- [#3052](#3052)
[`70f4e91`](70f4e91)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Match
native XPath semantics for `text()` predicates when a shadow root routes
locators through the composed-tree parser
## @browserbasehq/stagehand-python@4.2.0

### Minor Changes

- [#3030](#3030)
[`34edfa3`](34edfa3)
Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Export
browser pages as PDF bytes in TypeScript, Python, and Go, with
configurable print settings and timeouts, and optional local file saving
in TypeScript and Python.

- [#3118](#3118)
[`a837acf`](a837acf)
Thanks [@miguelg719](https://github.com/miguelg719)! - Add
`client_options` to `browserbase.launch()` and `browserbase.connect()`.

- [#3083](#3083)
[`666b6fa`](666b6fa)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - expose a
timeout option for page.snapshot() across all sdks, defaulting to 20
seconds.
set it to 0 for unlimited execution. one budget covers the whole
snapshot capture.

- [#3140](#3140)
[`f2060a6`](f2060a6)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! -
automatically discover Stagehand extensions when connecting to browsers.
deprecate & ignore extension IDs passed into .connect().

- [#2916](#2916)
[`476658b`](476658b)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add page
level hooks for webmcp tools added and webmcp tools removed events.

### Patch Changes

- [#3045](#3045)
[`4da1a21`](4da1a21)
Thanks [@github-actions](https://github.com/apps/github-actions)! - Keep
telemetry disabled unless an OTLP traces endpoint is explicitly
configured.

- [#2978](#2978)
[`f3543d3`](f3543d3)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Fix locator
failures when entering loading iframes, and correctly target iframe
elements when an XPath ends at the iframe.

- [#3033](#3033)
[`1562d35`](1562d35)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
per-call locator timeouts across TypeScript, Python, & Go. one timeout
covers frame readiness, element lookup, & execution, including typing
delays & highlight duration. the default is 20 seconds. setting timeout
to 0 disables it.

- [#3146](#3146)
[`7d8dcef`](7d8dcef)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Make
selector waits include frame readiness in their timeout, support
unlimited waits with `timeout: 0`, and clean up observers when the wait
ends.

- [#3052](#3052)
[`70f4e91`](70f4e91)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Match
native XPath semantics for `text()` predicates when a shadow root routes
locators through the composed-tree parser
## @browserbasehq/stagehand-examples@0.0.1

### Patch Changes

- Updated dependencies
[[`34edfa3`](34edfa3),
[`a837acf`](a837acf),
[`4da1a21`](4da1a21),
[`5802f59`](5802f59),
[`819db28`](819db28),
[`0210688`](0210688),
[`666b6fa`](666b6fa),
[`f3543d3`](f3543d3),
[`f2060a6`](f2060a6),
[`1562d35`](1562d35),
[`7d8dcef`](7d8dcef),
[`476658b`](476658b),
[`70f4e91`](70f4e91)]:
  - @browserbasehq/stagehand@4.2.0
  - @browserbasehq/stagehand-integrations@4.0.4
## @browserbasehq/stagehand-integrations-claude-agent-sdk@4.0.3

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4
##
@browserbasehq/stagehand-integrations-example-claude-code-facade@4.0.4

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4
  - @browserbasehq/stagehand-integrations-claude-agent-sdk@4.0.3
## @browserbasehq/stagehand-integrations-claude-cua-sdk@4.0.2

### Patch Changes

- Updated dependencies
[[`34edfa3`](34edfa3),
[`a837acf`](a837acf),
[`4da1a21`](4da1a21),
[`5802f59`](5802f59),
[`819db28`](819db28),
[`0210688`](0210688),
[`666b6fa`](666b6fa),
[`f3543d3`](f3543d3),
[`f2060a6`](f2060a6),
[`1562d35`](1562d35),
[`7d8dcef`](7d8dcef),
[`476658b`](476658b),
[`70f4e91`](70f4e91)]:
  - @browserbasehq/stagehand@4.2.0
  - @browserbasehq/stagehand-integrations@4.0.4
## @browserbasehq/stagehand-integrations-example-codex-facade@4.0.4

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4
  - @browserbasehq/stagehand-integrations-codex-sdk@4.0.3
## @browserbasehq/stagehand-integrations-codex-sdk@4.0.3

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4
## @browserbasehq/stagehand-integrations@4.0.4

### Patch Changes

- Updated dependencies
[[`34edfa3`](34edfa3),
[`a837acf`](a837acf),
[`4da1a21`](4da1a21),
[`5802f59`](5802f59),
[`819db28`](819db28),
[`0210688`](0210688),
[`666b6fa`](666b6fa),
[`f3543d3`](f3543d3),
[`f2060a6`](f2060a6),
[`1562d35`](1562d35),
[`7d8dcef`](7d8dcef),
[`476658b`](476658b),
[`70f4e91`](70f4e91)]:
  - @browserbasehq/stagehand@4.2.0
## @browserbasehq/stagehand-integrations-example-cursor-facade@4.0.2

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4
  - @browserbasehq/stagehand-integrations-cursor-sdk@4.0.3
## @browserbasehq/stagehand-integrations-cursor-sdk@4.0.3

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4
## @browserbasehq/stagehand-integrations-deepagents-sdk@4.0.3

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4
## @browserbasehq/stagehand-integrations-eve-sdk@4.0.3

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4
## @browserbasehq/stagehand-integrations-fx-sdk@4.0.3

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4
## @browserbasehq/stagehand-integrations-gemini-cua-sdk@4.0.2

### Patch Changes

- Updated dependencies
[[`34edfa3`](34edfa3),
[`a837acf`](a837acf),
[`4da1a21`](4da1a21),
[`5802f59`](5802f59),
[`819db28`](819db28),
[`0210688`](0210688),
[`666b6fa`](666b6fa),
[`f3543d3`](f3543d3),
[`f2060a6`](f2060a6),
[`1562d35`](1562d35),
[`7d8dcef`](7d8dcef),
[`476658b`](476658b),
[`70f4e91`](70f4e91)]:
  - @browserbasehq/stagehand@4.2.0
  - @browserbasehq/stagehand-integrations@4.0.4
## @browserbasehq/stagehand-integrations-example-mastra-facade@4.0.4

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4
## @browserbasehq/stagehand-integrations-mastra-sdk@4.0.3

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4
## @browserbasehq/stagehand-integrations-example-pi-facade@4.0.4

### Patch Changes

- Updated dependencies
[[`34edfa3`](34edfa3),
[`a837acf`](a837acf),
[`4da1a21`](4da1a21),
[`5802f59`](5802f59),
[`819db28`](819db28),
[`0210688`](0210688),
[`666b6fa`](666b6fa),
[`f3543d3`](f3543d3),
[`f2060a6`](f2060a6),
[`1562d35`](1562d35),
[`7d8dcef`](7d8dcef),
[`476658b`](476658b),
[`70f4e91`](70f4e91)]:
  - @browserbasehq/stagehand@4.2.0
  - @browserbasehq/stagehand-integrations@4.0.4
## @browserbasehq/stagehand-integrations-pi-sdk@4.0.3

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4
## @browserbasehq/stagehand-integrations-example-vercel-ai-facade@4.0.4

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.4

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Miguel <36487034+miguelg719@users.noreply.github.com>
# Conflicts:
#	packages/docs/docs.json
#	packages/docs/v4/integrations/cli-agents/overview.mdx
#	packages/docs/v4/integrations/overview.mdx
@seanmcguire12
seanmcguire12 requested a review from a team as a code owner October 8, 2026 21:51
@changeset-bot

changeset-bot Bot commented Oct 8, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 72c306d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@mintlify

mintlify Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
stagehand 🟢 Ready View Preview Oct 8, 2026, 9:51 PM

💡 Tip: Enable Automations to automatically generate PRs for you.

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​ffmpeg-static@​5.3.091100878570
Updatedpypi/​crewai-tools@​1.15.14 ⏵ 1.15.2472 +1100100100100
Addednpm/​@​ai-sdk/​openai@​4.0.73731009498100
Updatednpm/​@​earendil-works/​pi-coding-agent@​0.84.2 ⏵ 1.0.276 +101009998 +2100
Updatednpm/​vitest@​4.1.9 ⏵ 4.1.1198 +1100 +279 +199 +2100
Updatednpm/​ai@​7.0.77 ⏵ 7.0.12279 -1910010099100
Updatednpm/​eve@​0.29.4 ⏵ 0.71.299100100 +198 +180
Addednpm/​@​types/​node@​24.13.61001008196100
Addednpm/​@​types/​node@​24.19.11001008196100
Addednpm/​tsx@​4.23.151001008193100
Addednpm/​@​cursor/​sdk@​1.0.369910083100100
Addedgolang/​github.com/​browserbase/​stagehand/​packages/​sdk-go/​v4@​v4.1.084100100100100
Updatednpm/​sharp@​0.34.5 ⏵ 0.35.497 +585 +15100 +194100
Addednpm/​@​aws-sdk/​lib-storage@​3.1145.01001008598100
Updatedpypi/​crewai@​1.15.14 ⏵ 1.15.2487 -3100100100100
Updatedpypi/​pytest@​9.0.2 ⏵ 9.0.387 +1100 +2100100100
Updatedpypi/​langgraph@​1.2.11 ⏵ 1.2.1489 +1100100100100
Updatednpm/​smol-toml@​1.7.0 ⏵ 1.7.110099 +1610090 +3100
Addednpm/​@​clack/​prompts@​1.8.110010010095100
Addednpm/​files-sdk@​2.6.09710010096100
Addednpm/​@​browserbasehq/​sdk@​2.21.09710010097100
Updatedpypi/​urllib3@​2.7.0 ⏵ 2.8.097100 +23100100100
Addednpm/​@​aws-sdk/​s3-presigned-post@​3.1145.010010010098100
Addednpm/​@​aws-sdk/​s3-request-presigner@​3.1145.010010010098100
Addednpm/​@​aws-sdk/​client-s3@​3.1145.010010010098100
Updatednpm/​langsmith@​0.5.26 ⏵ 0.6.398 +1100 +16100 +199100
Addedpypi/​stagehand@​4.1.098100100100100
Updatednpm/​ai@​7.0.77 ⏵ 7.0.1129910010099100
Addedpypi/​python-dotenv@​1.2.499100100100100
Addednpm/​@​playwright/​mcp@​0.0.8210010010099100
Updatednpm/​@​openai/​codex-sdk@​0.147.0 ⏵ 0.153.4100 +26100100 +1100 +1100
Addedpypi/​browserbase@​1.20.0100100100100100
See 5 more rows in the dashboard

View full report

@seanmcguire12
seanmcguire12 merged commit 0a4cfac into docs-production Oct 8, 2026
61 checks passed
@seanmcguire12
seanmcguire12 deleted the sync-with-main branch October 8, 2026 21:56

This branch was successfully deployed

1 active deployment
staging - packages/docs — 72c306d2 Deployed Oct 8, 2026 by mintlify[bot]
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.

8 participants