Skip to content

[STG-2486] feat(cli): stamp detected agent on session userMetadata#2323

Draft
shrey150 wants to merge 1 commit into
mainfrom
shrey/cli-session-agent-attribution
Draft

[STG-2486] feat(cli): stamp detected agent on session userMetadata#2323
shrey150 wants to merge 1 commit into
mainfrom
shrey/cli-session-agent-attribution

Conversation

@shrey150

@shrey150 shrey150 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

⚠️ DRAFT — overnight autonomous; needs Shrey review

Linear: STG-2486

What

Stamp the detected coding agent onto the Browserbase session userMetadata at session create, under a new agent key (e.g. agent: "claude", "cursor", "codex", "hermes").

Scope is the browse CLI package only (packages/cli). The single behavioral change is in applyCliAttribution() in packages/cli/src/commands/cloud/sessions/create.ts: after the existing browse_cli / cli_version / install_id stamping, it now also calls detectAgent() and — only when a value is returned — sanitizes it through toMetadataValue() and sets userMetadata.agent.

Why

The CLI already computes the coding agent via detectAgent() (packages/cli/src/lib/agent.ts), but today that value only flows to PostHog telemetry (packages/cli/src/lib/telemetry.ts) — it is not stamped on the Browserbase session itself. Without it on the session, we cannot attribute cloud sessions to the coding agent that drove them (Claude Code / Cursor / Codex / etc.) in our internal analytics.

This is the CLI-side prerequisite for that attribution: adding agent to the session metadata mirrors the agent property already sent to PostHog, so our internal analytics can join sessions back to the agent.

Design notes:

  • Minimal + guarded. agent is only set when detectAgent() returns a truthy value (and the sanitized value is non-empty). No agent → no agent key, matching how install_id is handled.
  • Best-effort, never throws. detectAgent() is wrapped in .catch(() => null), so a detection failure can never break session creation.
  • Consistent style. Value runs through toMetadataValue() (same as the other attribution keys) so the session-create validator never 400s on a stray character or over-length value.
  • Caller metadata preserved. User-supplied userMetadata (via --body / --stdin) is untouched except for the authoritative attribution keys.

Note: the sibling driver path (packages/cli/src/lib/driver/remote.ts, used by open --remote) stamps the same browse_cli/cli_version/install_id keys but is out of scope for this PR, which targets the applyCliAttribution (sessions create) path per the task. It can be given the same agent key in a follow-up if desired.

Changeset

Added a PATCH changeset for the browse package. browse is in the changeset ignore list, but release-impacting CLI changes still get a patch changeset (this changes the session metadata the CLI sends).

E2E Test Matrix

Command / flow Observed output Confidence / sufficiency
pnpm --filter browse run check (tsc --noEmit) after pnpm turbo run build --filter browse exit 0, no diagnostics Proves the change type-checks against the built workspace. (A fresh worktree first errors on unbuilt @browserbasehq/stagehand; those errors are pre-existing/unrelated and clear once the workspace dep is built via turbo.)
pnpm turbo run build --filter browse 4 successful, 4 total; browse:build executed tsc -p tsconfig.json + oclif manifest Proves create.ts compiles into dist/ (verified dist/commands/cloud/sessions/create.js contains detectAgent() + userMetadata.agent = sanitized).
vitest run tests/cli-cloud-contract.test.ts tests/agent.test.ts Test Files 2 passed, Tests 57 passed Full session-create contract suite + agent-detection suite green, including 2 new contract tests below. These run the compiled CLI (bin/run.js) as a subprocess against a fake Browserbase server and assert the actual POST /v1/sessions body.
New test: agent detected (HERMES_SESSION_PLATFORM=telegram) Captured request body userMetadata.agent === "hermes" Proves a detected agent is stamped onto the real outgoing session-create request.
New test: no agent (all known agent env vars cleared) Captured body userMetadata.browse_cli === "true", userMetadata.agent === undefined Proves the agent key is omitted when nothing is detected, while base attribution still flows.
eslint src/commands/cloud/sessions/create.ts tests/cli-cloud-contract.test.ts exit 0, no output Lint clean (import ordering, style).

Not run locally: no live Browserbase session was created against production (overnight autonomous; nothing irreversible). The contract tests exercise the exact request body via a fake server subprocess, which is the load-bearing behavior here; a real live session would only additionally confirm the Browserbase API accepts the agent key (it accepts arbitrary userMetadata today).

🤖 Generated with Claude Code


Summary by cubic

Stamp the detected coding agent on session create in the browse CLI by setting userMetadata.agent. This enables internal analytics attribution of CLI-created cloud sessions to agents and aligns with PostHog telemetry (Linear STG-2486).

  • New Features
    • Set userMetadata.agent from detectAgent() in applyCliAttribution(); value sanitized via toMetadataValue().
    • Only set when detected; never throws; preserves caller userMetadata; browse_cli/cli_version/install_id/agent override caller values.
    • Scope: sessions create path only; driver open --remote unchanged.
    • Added contract tests for detected and no-agent cases; added patch changeset for browse.

Written for commit 985ea63. Summary will update on new commits.

Review in cubic

The CLI already computes the coding agent via detectAgent() but only sends
it to PostHog telemetry. Stamp it onto the Browserbase session-create
`userMetadata` (`agent` key) alongside the existing browse_cli/cli_version/
install_id attribution, so CLI-created cloud sessions can be attributed to
the coding agent (Claude Code / Cursor / Codex / etc.) in Snowflake.

- Only set when detectAgent() returns a value; best-effort, never throws.
- Sanitized through toMetadataValue() like the other attribution keys.
- Adds contract tests for the detected and no-agent cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 985ea63

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

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

Not sure what this means? Click here to learn what changesets are.

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

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.

1 participant