diff --git a/.changeset/quiet-pi-extension.md b/.changeset/quiet-pi-extension.md new file mode 100644 index 000000000..3cfbeb687 --- /dev/null +++ b/.changeset/quiet-pi-extension.md @@ -0,0 +1,5 @@ +--- +"@browserbasehq/pi": minor +--- + +Publish the native Pi extension as an installable Pi package, bundling the private facade implementation. diff --git a/justfile b/justfile index a69c7a116..cd19f9e05 100644 --- a/justfile +++ b/justfile @@ -87,6 +87,7 @@ _preview commit: _publish-typescript: pnpm --filter ./packages/sdk-ts build + pnpm exec turbo run build --filter @browserbasehq/pi pnpm exec changeset publish # Publishes a commit-addressed alpha of the TypeScript SDK (`-alpha-`) @@ -95,6 +96,7 @@ _publish-typescript: _publish-typescript-alpha: pnpm exec changeset version --snapshot pnpm --filter ./packages/sdk-ts build + pnpm exec turbo run build --filter @browserbasehq/pi pnpm exec changeset publish --tag alpha --no-git-tag # Rewrites the Python project to the commit-addressed alpha (`a0.dev`) diff --git a/packages/docs/v4/integrations/pi.mdx b/packages/docs/v4/integrations/pi.mdx index 85e0830c8..c9f3526f5 100644 --- a/packages/docs/v4/integrations/pi.mdx +++ b/packages/docs/v4/integrations/pi.mdx @@ -6,27 +6,24 @@ description: "Give the Pi coding agent native Stagehand browser tools registered The Pi integration gives a Pi agent native `run`, `snapshot`, and `screenshot` tools backed by one persistent Stagehand browser per Pi session. Pi ships without built-in MCP by design; extensions register tools directly, so this integration runs in process without an MCP server or bridge. The tool descriptions, runtime validators, and system prompt come from the shared facade contract, so the tools behave the same as the MCP-based integrations. -Stagehand ships this experimental integration from the repository rather than publishing it as a standalone adapter. +The extension uses Pi’s official [package format](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/packages.md). Browserbase must publish the first `@browserbasehq/pi` release before you can use the npm install below; use the source install below while testing an unreleased change. ## Prerequisites - Node.js 24 or newer -- pnpm 11.10.0 - A model-provider credential for Pi (`OPENAI_API_KEY` or `ANTHROPIC_API_KEY`) - A current Google Chrome installation for local browser mode ## Quickstart - + ```bash -git clone https://github.com/browserbase/stagehand.git -cd stagehand -pnpm install --frozen-lockfile -pnpm exec turbo run build \ - --filter @browserbasehq/stagehand-integrations +pi install npm:@browserbasehq/pi ``` + +Use `pi install -l npm:@browserbasehq/pi` to install only for the current project. Restart Pi after installing so it loads the extension. ```bash @@ -45,27 +42,28 @@ export BROWSERBASE_API_KEY="your-browserbase-api-key" ```bash -cd packages/integrations/pi -pnpm start "Open https://example.com and report the page title." + -Two headless gotchas: print mode reads piped stdin (always redirect ` -## Install permanently +## Try the extension from source -To register the extension for every Pi session instead of loading it per invocation: +For development before the first release, build and install the package from the repository. The build bundles the private facade so installed consumers do not depend on the monorepo. ```bash +git clone https://github.com/browserbase/stagehand.git +cd stagehand +pnpm install --frozen-lockfile +pnpm exec turbo run build --filter @browserbasehq/pi pi install ./packages/integrations/pi ``` -The `pi` manifest key in the package's `package.json` points at the extension. +Use `pi list` to inspect installed packages, `pi update npm:@browserbasehq/pi` to update a published installation, and `pi remove npm:@browserbasehq/pi` to remove it. ## Configuration diff --git a/packages/integrations/pi/README.md b/packages/integrations/pi/README.md index 3f98bfb90..560ec8348 100644 --- a/packages/integrations/pi/README.md +++ b/packages/integrations/pi/README.md @@ -1,49 +1,26 @@ -# pi + Stagehand facade (native tools) +# Stagehand for Pi -[pi](https://pi.dev) has no built-in MCP by design — extensions register tools directly. This -package is a pi extension exposing the Stagehand facade tools (`run`, `snapshot`, -`screenshot`) natively, with descriptions, validation, and agent guidance imported from -`@browserbasehq/stagehand-integrations/facade`. +Install the native extension with Pi’s package manager: -## Setup - -Use Node.js 24 or later. From the repository root, build the integrations package first: - -```bash -pnpm install -pnpm exec turbo run build --filter @browserbasehq/stagehand-integrations +```sh +pi install npm:@browserbasehq/pi +pi ``` -Export the browser credentials (Browserbase is the default and recommended backend) and a model -key pi supports: +Requires Node.js 24+, an authenticated Pi model provider, and local Chrome (or `BROWSERBASE_API_KEY` for Browserbase). The initial npm release is pending; before publishing, use the development build below. No private workspace dependency is needed by the installed package. -```bash -export BROWSERBASE_API_KEY=bb_live_... -export OPENAI_API_KEY=sk-... # or ANTHROPIC_API_KEY -``` +The extension registers `run`, `snapshot`, and `screenshot` directly through Pi’s extension API. It launches a browser on the first call, reuses it throughout the session, and closes it on shutdown. -## Run +## Develop from source -One-off, pointing pi at the extension file (no install needed; pi loads TypeScript directly and -resolves `@browserbasehq/stagehand-integrations` through the workspace): +From the Stagehand repository root: -```bash -cd packages/integrations/pi -pi -e ./extensions/stagehand.ts --no-session -p "Use your browser tools: open https://example.com, snapshot it, and report the heading citing the snapshot ID." { "@browserbasehq/stagehand-go": patch "@browserbasehq/stagehand-extension": patch "browse": patch +"@browserbasehq/pi": minor --- Release the SDKs. diff --git a/scripts/release/check-changesets.ts b/scripts/release/check-changesets.ts index 708f56817..6b1c5c1a7 100644 --- a/scripts/release/check-changesets.ts +++ b/scripts/release/check-changesets.ts @@ -10,6 +10,7 @@ const allowedPackages = new Set([ "@browserbasehq/stagehand-python", "@browserbasehq/stagehand-extension", "browse", + "@browserbasehq/pi", ]); export function validateChangeset(contents: string, file: string): void { diff --git a/scripts/release/consolidate-changelogs.test.ts b/scripts/release/consolidate-changelogs.test.ts index c50e6a0d1..7dbd71528 100644 --- a/scripts/release/consolidate-changelogs.test.ts +++ b/scripts/release/consolidate-changelogs.test.ts @@ -1,4 +1,5 @@ -import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { execFileSync } from "node:child_process"; +import { copyFile, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { describe, expect, it } from "vitest"; @@ -175,3 +176,37 @@ describe("shouldPreservePackageChangelogs", () => { expect(shouldPreservePackageChangelogs(value)).toBe(expected); }); }); + +describe("integration package release", () => { + it("consolidates the Pi extension changelog through the release entrypoint", async () => { + const directory = await mkdtemp(path.join(os.tmpdir(), "stagehand-integration-release-")); + try { + const scripts = path.join(directory, "scripts/release"); + const packagePath = path.join(directory, "packages/integrations/pi"); + await mkdir(scripts, { recursive: true }); + await mkdir(packagePath, { recursive: true }); + const scriptPath = path.join(scripts, "consolidate-changelogs.ts"); + await copyFile(new URL("./consolidate-changelogs.ts", import.meta.url), scriptPath); + await writeFile( + path.join(directory, "CHANGELOG.md"), + "# Stagehand\n\n## 4.1.0\n\nExisting release.\n", + ); + await writeFile( + path.join(packagePath, "CHANGELOG.md"), + "# Integration\n\n## 0.1.0\n\nFirst package release.\n", + ); + execFileSync(process.execPath, [scriptPath], { + env: { ...process.env, CHANGESETS_ACTION_PRESERVE_CHANGELOGS: "false" }, + }); + const result = await readFile(path.join(directory, "CHANGELOG.md"), "utf8"); + expect(result).toContain("## Pi extension 0.1.0"); + expect(result).toContain("First package release."); + expect(result).toContain("## 4.1.0\n\nExisting release."); + await expect(readFile(path.join(packagePath, "CHANGELOG.md"))).rejects.toMatchObject({ + code: "ENOENT", + }); + } finally { + await rm(directory, { recursive: true, force: true }); + } + }); +}); diff --git a/scripts/release/consolidate-changelogs.ts b/scripts/release/consolidate-changelogs.ts index 346fcc167..2bd87e006 100644 --- a/scripts/release/consolidate-changelogs.ts +++ b/scripts/release/consolidate-changelogs.ts @@ -5,6 +5,10 @@ import { pathToFileURL } from "node:url"; const repositoryRoot = path.resolve(import.meta.dirname, "../.."); const rootChangelogPath = path.join(repositoryRoot, "CHANGELOG.md"); const packageChangelogs = [ + { + label: "Pi extension", + path: path.join(repositoryRoot, "packages/integrations/pi/CHANGELOG.md"), + }, { label: "TypeScript SDK", path: path.join(repositoryRoot, "packages/sdk-ts/CHANGELOG.md"), diff --git a/turbo.json b/turbo.json index df66097f7..7ae60679e 100644 --- a/turbo.json +++ b/turbo.json @@ -39,6 +39,11 @@ "browse#lint": { "dependsOn": ["@browserbasehq/stagehand#build"] }, + "@browserbasehq/pi#build": { + "dependsOn": ["^build"], + "inputs": ["$TURBO_DEFAULT$", "!dist/**"], + "outputs": ["dist/**"] + }, "@browserbasehq/stagehand-integrations#build": { "dependsOn": ["^build"], "inputs": ["$TURBO_DEFAULT$", "!dist/**"], @@ -243,7 +248,7 @@ "@browserbasehq/stagehand-integrations-example-vercel-ai-facade#typecheck": { "dependsOn": ["^build"] }, - "@browserbasehq/stagehand-integrations-example-pi-facade#typecheck": { + "@browserbasehq/pi#typecheck": { "dependsOn": ["^build"] }, "@browserbasehq/stagehand-integrations-example-claude-code-facade#typecheck": {