Skip to content

Commit 9ff03e4

Browse files
release: 0.2.0 (#258)
* feat(api): manual updates * codegen metadata * docs: prominently feature MCP server setup in root SDK readmes * feat: Added optional param to force empty object * release: 0.2.0 * Added x-language and minimal agent example * lint fix * Added full example + updated readme * Added local binary logic * Added empty body logic for /end endpoint * lint fix * Added bundling logic for wheels * lint fix --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: monadoid <sam.finton@gmail.com>
1 parent 1996efe commit 9ff03e4

29 files changed

+1470
-58
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
BROWSERBASE_API_KEY=bb_live_your_api_key_here
2+
BROWSERBASE_PROJECT_ID=your-bb-project-uuid-here
3+
MODEL_API_KEY=sk-proj-your-llm-api-key-here

.github/workflows/publish-pypi.yml

Lines changed: 147 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,170 @@
11
# This workflow is triggered when a GitHub release is created.
22
# It can also be run manually to re-publish to PyPI in case it failed for some reason.
3-
# You can run this workflow by navigating to https://www.github.com/browserbase/stagehand-python/actions/workflows/publish-pypi.yml
43
name: Publish PyPI
4+
55
on:
66
workflow_dispatch:
7+
inputs:
8+
stagehand_tag:
9+
description: "Stagehand repo git ref to build SEA binaries from (e.g. @browserbasehq/stagehand@3.0.6)"
10+
required: true
11+
type: string
712

813
release:
914
types: [published]
1015

1116
jobs:
17+
build_wheels:
18+
name: build wheels (${{ matrix.binary_name }})
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
include:
23+
- os: ubuntu-latest
24+
binary_name: stagehand-linux-x64
25+
output_path: src/stagehand/_sea/stagehand-linux-x64
26+
wheel_platform_tag: manylinux2014_x86_64
27+
- os: macos-latest
28+
binary_name: stagehand-darwin-arm64
29+
output_path: src/stagehand/_sea/stagehand-darwin-arm64
30+
wheel_platform_tag: macosx_11_0_arm64
31+
- os: macos-13
32+
binary_name: stagehand-darwin-x64
33+
output_path: src/stagehand/_sea/stagehand-darwin-x64
34+
wheel_platform_tag: macosx_10_9_x86_64
35+
- os: windows-latest
36+
binary_name: stagehand-win32-x64.exe
37+
output_path: src/stagehand/_sea/stagehand-win32-x64.exe
38+
wheel_platform_tag: win_amd64
39+
40+
runs-on: ${{ matrix.os }}
41+
permissions:
42+
contents: read
43+
44+
steps:
45+
- uses: actions/checkout@v4
46+
47+
- name: Install uv
48+
uses: astral-sh/setup-uv@v5
49+
with:
50+
version: "0.9.13"
51+
52+
- name: Checkout stagehand (server source)
53+
uses: actions/checkout@v4
54+
with:
55+
repository: browserbase/stagehand
56+
ref: ${{ inputs.stagehand_tag || vars.STAGEHAND_TAG }}
57+
path: _stagehand
58+
fetch-depth: 1
59+
# If browserbase/stagehand is private, set STAGEHAND_SOURCE_TOKEN (PAT) in this repo.
60+
token: ${{ secrets.STAGEHAND_SOURCE_TOKEN || github.token }}
61+
62+
- name: Setup pnpm
63+
uses: pnpm/action-setup@v4
64+
65+
- name: Setup Node.js
66+
uses: actions/setup-node@v4
67+
with:
68+
node-version: "23"
69+
cache: "pnpm"
70+
cache-dependency-path: _stagehand/pnpm-lock.yaml
71+
72+
- name: Build SEA server binary (from source)
73+
shell: bash
74+
run: |
75+
set -euo pipefail
76+
77+
if [[ -z "${{ inputs.stagehand_tag }}" && -z "${{ vars.STAGEHAND_TAG }}" ]]; then
78+
echo "Missing stagehand ref: set repo variable STAGEHAND_TAG or provide workflow input stagehand_tag." >&2
79+
exit 1
80+
fi
81+
82+
# Ensure we only ship the binary built for this runner's OS/arch.
83+
python - <<'PY'
84+
from pathlib import Path
85+
sea_dir = Path("src/stagehand/_sea")
86+
sea_dir.mkdir(parents=True, exist_ok=True)
87+
for p in sea_dir.glob("stagehand-*"):
88+
p.unlink(missing_ok=True)
89+
for p in sea_dir.glob("*.exe"):
90+
p.unlink(missing_ok=True)
91+
PY
92+
93+
pushd _stagehand >/dev/null
94+
pnpm install --frozen-lockfile
95+
CI=true pnpm --filter @browserbasehq/stagehand-server build:binary
96+
popd >/dev/null
97+
98+
cp "_stagehand/packages/server/dist/sea/${{ matrix.binary_name }}" "${{ matrix.output_path }}"
99+
chmod +x "${{ matrix.output_path }}" 2>/dev/null || true
100+
101+
- name: Build wheel
102+
env:
103+
STAGEHAND_WHEEL_TAG: py3-none-${{ matrix.wheel_platform_tag }}
104+
run: uv build --wheel
105+
106+
- name: Upload wheel artifact
107+
uses: actions/upload-artifact@v4
108+
with:
109+
name: wheel-${{ matrix.binary_name }}
110+
path: dist/*.whl
111+
retention-days: 7
112+
113+
build_sdist:
114+
name: build sdist
115+
runs-on: ubuntu-latest
116+
permissions:
117+
contents: read
118+
steps:
119+
- uses: actions/checkout@v4
120+
121+
- name: Install uv
122+
uses: astral-sh/setup-uv@v5
123+
with:
124+
version: "0.9.13"
125+
126+
- name: Build sdist
127+
run: uv build --sdist
128+
129+
- name: Upload sdist artifact
130+
uses: actions/upload-artifact@v4
131+
with:
132+
name: sdist
133+
path: dist/*.tar.gz
134+
retention-days: 7
135+
12136
publish:
13137
name: publish
138+
needs: [build_wheels, build_sdist]
14139
runs-on: ubuntu-latest
15-
140+
permissions:
141+
contents: read
16142
steps:
17143
- uses: actions/checkout@v4
18144

19145
- name: Install uv
20146
uses: astral-sh/setup-uv@v5
21147
with:
22-
version: '0.9.13'
148+
version: "0.9.13"
23149

24-
- name: Publish to PyPI
150+
- name: Download build artifacts
151+
uses: actions/download-artifact@v4
152+
with:
153+
path: dist
154+
155+
- name: Flatten dist directory
156+
shell: bash
25157
run: |
26-
bash ./bin/publish-pypi
158+
set -euo pipefail
159+
mkdir -p dist_out
160+
find dist -type f \( -name "*.whl" -o -name "*.tar.gz" \) -print0 | while IFS= read -r -d '' f; do
161+
cp -f "$f" dist_out/
162+
done
163+
ls -la dist_out
164+
165+
- name: Publish to PyPI
27166
env:
28167
PYPI_TOKEN: ${{ secrets.STAGEHAND_PYPI_TOKEN || secrets.PYPI_TOKEN }}
168+
run: |
169+
set -euo pipefail
170+
uv publish --token="$PYPI_TOKEN" dist_out/*

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ dist
99
.venv
1010
.idea
1111

12+
.DS_Store
13+
src/stagehand/_sea/stagehand-*
14+
src/stagehand/_sea/*.exe
15+
bin/sea/
1216
.env
1317
.envrc
1418
codegen.log

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "0.1.0"
2+
".": "0.2.0"
33
}

.stats.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 7
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-ed52466945f2f8dfd3814a29e948d7bf30af7b76a7a7689079c03b8baf64e26f.yml
3-
openapi_spec_hash: 5d57aaf2362b0d882372dbf76477ba23
4-
config_hash: 989ddfee371586e9156b4d484ec0a6cc
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-39cd9547d16412cf0568f6ce2ad8d43805dffe65bde830beeff630b903ae3b38.yml
3+
openapi_spec_hash: 9cd7c9fefa686f9711392782d948470f
4+
config_hash: 1f709f8775e13029dc60064ef3a94355

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
# Changelog
22

3+
## 0.2.0 (2026-01-06)
4+
5+
Full Changelog: [v0.1.0...v0.2.0](https://github.com/browserbase/stagehand-python/compare/v0.1.0...v0.2.0)
6+
7+
### Features
8+
9+
* Added optional param to force empty object ([b15e097](https://github.com/browserbase/stagehand-python/commit/b15e0976bc356e0ce09b331705ccd2b8805e1bfa))
10+
* **api:** manual updates ([5a3f419](https://github.com/browserbase/stagehand-python/commit/5a3f419522d49d132c4a75bf310eef1d9695a5a4))
11+
12+
13+
### Documentation
14+
15+
* prominently feature MCP server setup in root SDK readmes ([d5a8361](https://github.com/browserbase/stagehand-python/commit/d5a83610cd39ccdecc1825d67a56ab2835d9651f))
16+
317
## 0.1.0 (2025-12-23)
418

519
Full Changelog: [v0.0.1...v0.1.0](https://github.com/browserbase/stagehand-python/compare/v0.0.1...v0.1.0)

CONTRIBUTING.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,47 @@ Most of the SDK is generated code. Modifications to code will be persisted betwe
3838
result in merge conflicts between manual patches and changes from the generator. The generator will never
3939
modify the contents of the `src/stagehand/lib/` and `examples/` directories.
4040

41+
## Setting up the local server binary (for development)
42+
43+
The SDK supports running a local Stagehand server for development and testing. To use this feature, you need to download the appropriate binary for your platform.
44+
45+
### Quick setup
46+
47+
Run the download script to automatically download the correct binary:
48+
49+
```sh
50+
$ uv run python scripts/download-binary.py
51+
```
52+
53+
This will:
54+
- Detect your platform (macOS, Linux, Windows) and architecture (x64, arm64)
55+
- Download the latest stagehand-server binary from GitHub releases
56+
- Place it in `bin/sea/` where the SDK expects to find it
57+
58+
### Manual download (alternative)
59+
60+
You can also manually download from [GitHub releases](https://github.com/browserbase/stagehand/releases):
61+
62+
1. Find the latest `stagehand/server vX.X.X` release
63+
2. Download the binary for your platform:
64+
- macOS ARM: `stagehand-server-darwin-arm64`
65+
- macOS Intel: `stagehand-server-darwin-x64`
66+
- Linux: `stagehand-server-linux-x64` or `stagehand-server-linux-arm64`
67+
- Windows: `stagehand-server-win32-x64.exe` or `stagehand-server-win32-arm64.exe`
68+
3. Rename it to match the expected format (remove `-server` from the name):
69+
- `stagehand-darwin-arm64`, `stagehand-linux-x64`, `stagehand-win32-x64.exe`, etc.
70+
4. Place it in `bin/sea/` directory
71+
5. Make it executable (Unix only): `chmod +x bin/sea/stagehand-*`
72+
73+
### Using an environment variable (optional)
74+
75+
Instead of placing the binary in `bin/sea/`, you can point to any binary location:
76+
77+
```sh
78+
$ export STAGEHAND_SEA_BINARY=/path/to/your/stagehand-binary
79+
$ uv run python test_local_mode.py
80+
```
81+
4182
## Adding and running examples
4283

4384
All files in the `examples/` directory are not modified by the generator and can be freely edited or added to.

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright 2025 Stagehand
189+
Copyright 2026 Stagehand
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

README.md

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ and offers both synchronous and asynchronous clients powered by [httpx](https://
99

1010
It is generated with [Stainless](https://www.stainless.com/).
1111

12+
## MCP Server
13+
14+
Use the Stagehand MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.
15+
16+
[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=stagehand-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInN0YWdlaGFuZC1tY3AiXX0)
17+
[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22stagehand-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22stagehand-mcp%22%5D%7D)
18+
19+
> Note: You may need to set environment variables in your MCP client.
20+
1221
## Documentation
1322

1423
The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). The full API of this library can be found in [api.md](api.md).
@@ -20,35 +29,62 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta
2029
pip install stagehand-alpha
2130
```
2231

32+
## Running the Example
33+
34+
A complete working example is available at [`examples/full_example.py`](examples/full_example.py).
35+
36+
To run it, first export the required environment variables, then use Python:
37+
38+
```bash
39+
export BROWSERBASE_API_KEY="your-bb-api-key"
40+
export BROWSERBASE_PROJECT_ID="your-bb-project-uuid"
41+
export MODEL_API_KEY="sk-proj-your-llm-api-key"
42+
43+
python examples/full_example.py
44+
```
45+
2346
## Usage
2447

2548
The full API of this library can be found in [api.md](api.md).
2649

50+
## Client configuration
51+
52+
Configure the client using environment variables:
53+
54+
```python
55+
from stagehand import Stagehand
56+
57+
# Configures using the BROWSERBASE_API_KEY, BROWSERBASE_PROJECT_ID, and MODEL_API_KEY environment variables
58+
client = Stagehand()
59+
```
60+
61+
Or manually:
62+
2763
```python
28-
import os
2964
from stagehand import Stagehand
3065

3166
client = Stagehand(
32-
browserbase_api_key=os.environ.get(
33-
"BROWSERBASE_API_KEY"
34-
), # This is the default and can be omitted
35-
browserbase_project_id=os.environ.get(
36-
"BROWSERBASE_PROJECT_ID"
37-
), # This is the default and can be omitted
38-
model_api_key=os.environ.get("MODEL_API_KEY"), # This is the default and can be omitted
67+
browserbase_api_key="My Browserbase API Key",
68+
browserbase_project_id="My Browserbase Project ID",
69+
model_api_key="My Model API Key",
3970
)
71+
```
4072

41-
response = client.sessions.act(
42-
id="00000000-your-session-id-000000000000",
43-
input="click the first link on the page",
73+
Or using a combination of the two approaches:
74+
75+
```python
76+
from stagehand import Stagehand
77+
78+
client = Stagehand(
79+
# Configures using environment variables
80+
browserbase_api_key="My Browserbase API Key", # Override just this one
4481
)
45-
print(response.data)
4682
```
4783

48-
While you can provide a `browserbase_api_key` keyword argument,
84+
While you can provide API keys as keyword arguments,
4985
we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
5086
to add `BROWSERBASE_API_KEY="My Browserbase API Key"` to your `.env` file
51-
so that your Browserbase API Key is not stored in source control.
87+
so that your API keys are not stored in source control.
5288

5389
## Async usage
5490

api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ from stagehand.types import (
2020
Methods:
2121

2222
- <code title="post /v1/sessions/{id}/act">client.sessions.<a href="./src/stagehand/resources/sessions.py">act</a>(id, \*\*<a href="src/stagehand/types/session_act_params.py">params</a>) -> <a href="./src/stagehand/types/session_act_response.py">SessionActResponse</a></code>
23-
- <code title="post /v1/sessions/{id}/end">client.sessions.<a href="./src/stagehand/resources/sessions.py">end</a>(id) -> <a href="./src/stagehand/types/session_end_response.py">SessionEndResponse</a></code>
23+
- <code title="post /v1/sessions/{id}/end">client.sessions.<a href="./src/stagehand/resources/sessions.py">end</a>(id, \*\*<a href="src/stagehand/types/session_end_params.py">params</a>) -> <a href="./src/stagehand/types/session_end_response.py">SessionEndResponse</a></code>
2424
- <code title="post /v1/sessions/{id}/agentExecute">client.sessions.<a href="./src/stagehand/resources/sessions.py">execute</a>(id, \*\*<a href="src/stagehand/types/session_execute_params.py">params</a>) -> <a href="./src/stagehand/types/session_execute_response.py">SessionExecuteResponse</a></code>
2525
- <code title="post /v1/sessions/{id}/extract">client.sessions.<a href="./src/stagehand/resources/sessions.py">extract</a>(id, \*\*<a href="src/stagehand/types/session_extract_params.py">params</a>) -> <a href="./src/stagehand/types/session_extract_response.py">SessionExtractResponse</a></code>
2626
- <code title="post /v1/sessions/{id}/navigate">client.sessions.<a href="./src/stagehand/resources/sessions.py">navigate</a>(id, \*\*<a href="src/stagehand/types/session_navigate_params.py">params</a>) -> <a href="./src/stagehand/types/session_navigate_response.py">SessionNavigateResponse</a></code>

0 commit comments

Comments
 (0)