build-kernel-ts-sdk

Installation
SKILL.md

Build Kernel TS SDK

Build with the Kernel TypeScript SDK (@onkernel/sdk, generated from Kernel's OpenAPI spec by Stainless) and the React helper @onkernel/managed-auth-react. Kernel runs each browser as a unikernel-isolated VM and co-locates your code with the browser to remove CDP latency.

The SDK and CLI surface the same API. Pick one operating mode early and stay in it.

Trigger boundary

Use this skill when work involves the Kernel TypeScript SDK or a Kernel-deployed app:

  • Driving Kernel browsers from a Node/Bun/Deno service (@onkernel/sdk)
  • Deploying a Kernel App (kernel deploy) and invoking it sync or async
  • Wiring Playwright, Stagehand, Browser Use, Claude Agent SDK, Vibium, Notte, Magnitude, Laminar, or Val Town to a Kernel browser
  • Profile-backed sessions, browser pools, replays, file I/O, or computer-controls
  • Managed Auth (auth.connections.* + <KernelManagedAuth />)

Do not use this skill for:

  • Local Playwright without Kernel — use run-playwright
  • The agent-browser CLI directly without the Kernel provider — use run-agent-browser
  • Python Kernel SDK
  • Building a GitHub Copilot SDK app — use build-copilot-sdk-app

Two operating modes — decide first

Mode When Code lives Invocation
A. Embed Drive Kernel from your own service (Next.js route, worker, CLI tool) Your repo new Kernel()browsers.create → CDP / playwright.execute / computer.*
B. Deploy Long-running, browser-co-located actions; want zero CDP latency or per-invocation isolation A Kernel App (your repo, deployed via kernel deploy) Register actions → kernel deploykernel.invocations.create({ app_name, action_name, payload })

You can mix — most production setups deploy long-running browser work as a Kernel App and invoke it from an embedding service. Don't try to make a single function do both.

Hard rules

  1. KERNEL_API_KEY from env. Never hardcode. Env wins over apiKey: option only when the option is omitted; passing both is allowed.
  2. Pin the SDK. @onkernel/sdk is auto-generated by Stainless and rev's frequently. Pin a minor version range; verify method names from the installed node_modules/@onkernel/sdk/api.md if unsure.
  3. Never use browser.close() as cleanup. Playwright/Puppeteer close() only severs the local CDP connection. Always call kernel.browsers.deleteByID(session_id) (or rely on timeout_seconds).
  4. Sync invocation cap is ~100s. Anything longer must use async: true with async_timeout_seconds (10–3600) and invocations.follow(id) for SSE.
  5. Default browser context only. Kernel browsers ship with one default context and one open page. Use browser.contexts()[0] and pages()[0] — do not call browser.newContext() / context.newPage() to make a "fresh" one.
  6. Project scoping is header-driven. With an org-wide API key, scope to a project by passing defaultHeaders: { 'X-Kernel-Project-Id': '…' } to the constructor (the SDK does NOT auto-read a KERNEL_PROJECT env var — that's a user convention you have to wire through). OAuth (CLI) is always org-wide.
  7. Runtime requirements. Node 20+, TypeScript ≥ 4.9. Deno 1.28+, Bun 1.0+, Cloudflare Workers, Vercel Edge supported. No React Native.
  8. Payload max 4.5 MB. invocation.payload and invocation.output are JSON-encoded strings — caller must JSON.parse. Larger artifacts (e.g. screenshots, multi-MB blobs) go through browsers.fs.* or your own object store.

Default stance

  • stealth: true for any non-trivial site (bot detection is the rule, not the exception).
  • timeout_seconds: 300 minimum; the 60s default is too aggressive for real automation. Max is 259200 (72h).
  • Headful when you need live view, replays, or GPU. Headless for fast scripted scrapes (~8× cheaper, faster boot, but more detectable).
  • Prefer kernel.browsers.playwright.execute(id, { code }) for hot paths (it runs in the browser VM with no CDP roundtrip). Reserve raw CDP for long-lived interactive sessions.
  • Use Kernel profiles for any flow that needs login state across sessions; reach for Managed Auth when those credentials belong to your end-users.
  • A connected browser is "active". After 5s with no CDP/live-view connection it enters standby (zero compute cost) and only THEN does its timeout_seconds countdown to deletion start. Don't expect long-idle-but-open sessions to be free — keep a connection live.

Workflow

  1. Classify the operating mode (A vs B). If mixed, name which surface each piece is on.
  2. Construct the client. import Kernel from '@onkernel/sdk'. Verify env (KERNEL_API_KEY is the only required one; KERNEL_LOG, KERNEL_BASE_URL, KERNEL_CUSTOM_HEADERS, KERNEL_SUPPRESS_BUN_WARNING are optional). For local development hitting https://localhost:3001/, pass environment: 'development', baseURL: null. For project-scoped API keys, wire X-Kernel-Project-Id through defaultHeaders. See references/guides/client-and-config.md.
  3. Pick the browser-control surface — raw CDP / Playwright-inside-VM / computer-controls / browser-curl. See references/patterns/browser-control-surfaces.md.
  4. Wire profiles or Managed Auth if the agent needs persistent login. See references/patterns/profiles-pools-credentials.md and references/guides/managed-auth.md.
  5. Handle lifecycle. Always pair browsers.create with browsers.deleteByID, even on error paths. Use try/finally. See references/guides/browsers-lifecycle.md.
  6. Deploy or run. For Mode B, kernel deploy and consume invocations; for Mode A, run inside your service. See references/guides/apps-deploy-invoke.md and references/examples/deploy-and-invoke-app.md.

Reference routing

Document What it contains Load when
references/guides/client-and-config.md Env vars, environments, retries, idempotency, pagination, error taxonomy, request options Constructing the client, debugging auth/network errors, handling pagination
references/guides/browsers-lifecycle.md browsers.create params, BrowserCreateResponse, standby, termination, viewport, timeout semantics Creating, configuring, or terminating browsers
references/guides/apps-deploy-invoke.md deployments.*, invocations.create sync vs async, invocations.follow SSE, secrets, logs Deploying a Kernel App or invoking it from another service
references/guides/managed-auth.md 3-piece architecture, auth.connections.*, <KernelManagedAuth /> props, profile interop Authenticating an agent on a user's behalf into a SaaS
references/patterns/browser-control-surfaces.md Decision tree across CDP, playwright.execute, computer.*, curl Picking the right control surface for a task
references/patterns/playwright-stagehand-integration.md connectOverCDP idiom, default-context warning, Stagehand v3 launch options, kernel create --template Wiring Playwright or Stagehand to a Kernel browser
references/patterns/profiles-pools-credentials.md profiles.*, browserPools.*, credentials.*, credentialProviders.* (1Password) Persistent login state, pool warm-starts, credential providers
references/patterns/integrations-matrix.md Hookup snippets per integration (Stagehand, Browser Use, Claude Agent SDK, Vibium, etc.) Connecting a third-party agent framework to a Kernel browser
references/examples/browser-screenshot.md Minimal end-to-end TS example Sanity-check first run; copy as a starting scaffold
references/examples/deploy-and-invoke-app.md kernel deploy + invocations.create + invocations.follow walkthrough Building or invoking a Kernel App
references/examples/managed-auth-flow.md Full Next.js page + backend route + browser launch Implementing the Managed Auth handoff end-to-end
references/troubleshooting/pitfalls.md The 16 production gotchas in priority order Debugging unexpected behavior or before shipping
references/troubleshooting/files-and-replays.md browsers.fs.*, browsers.replays.*, download timing, multipart File I/O or replay download is failing or slow
references/troubleshooting/auth-and-profile-errors.md 409 conflict, profile not found, hosted-page handoff failures Managed Auth or profile errors

Steering experience

browser.close() is not cleanup. Closing the Playwright Browser only disconnects CDP. The Kernel browser keeps running until timeout_seconds elapses or you call kernel.browsers.deleteByID(session_id). Always pair create with deleteByID in a finally block.

There is already a default context and page. Calling browser.newContext() makes a second context; the cookies, storage, and profile state live on the default one. Use browser.contexts()[0].pages()[0].

Sync invocations time out at ~100s. If your action does any non-trivial browser work, set async: true and invocations.follow(id) instead. Switching after the fact requires re-deploying.

Stagehand connects via local-CDP, not Browserbase. When using @browserbasehq/stagehand with Kernel, set env: 'LOCAL' and localBrowserLaunchOptions.cdpUrl: session.cdp_ws_url. Do not set apiKey or projectId — those are Browserbase-only.

browsers.delete (singular) is deprecated. Use browsers.deleteByID(id). The plural form takes a persistent_id and belongs to the deprecated persistence model.

Do this, not that

Do this Not that
await kernel.browsers.deleteByID(session.session_id) in a finally await browser.close() and assume the browser is gone
chromium.connectOverCDP(session.cdp_ws_url) then browser.contexts()[0] browser.newContext() to "isolate" the test
kernel.browsers.playwright.execute(id, { code: '…' }) for hot paths round-trip every call over CDP from your service
async: true, async_timeout_seconds: 1800 + invocations.follow depend on the sync invocation cap holding for a multi-minute scrape
JSON.stringify(payload) and JSON.parse(invocation.output ?? 'null') pass non-JSON-serializable objects to payload
try { ... } catch (e) { if (e instanceof Kernel.APIError) … } swallow errors or catch (e: any) without checking subclasses
browsers.create({ profile: { name } }) after Managed Auth completes re-prompt the user every session
Pin @onkernel/sdk to a minor range and bump deliberately track latest (Stainless regenerates frequently)
kernel.browsers.curl(id, { url }) for HTTP from inside the browser's TLS fingerprint spin up a separate Playwright request context and lose the fingerprint
Wire defaultHeaders: { 'X-Kernel-Project-Id': '…' } for project-scoped API keys rely on key scope and get cross-project lists

Verification

End-to-end checks for any Kernel-TS task:

  1. The SDK is installed at a pinned version; node_modules/@onkernel/sdk/api.md exists and matches the methods you call.
  2. KERNEL_API_KEY resolves at runtime; if the key is org-wide, defaultHeaders: { 'X-Kernel-Project-Id': '…' } is wired through the constructor.
  3. Every browsers.create is paired with a deleteByID in a finally (grep the diff).
  4. Long-running invocations use async: true and consume invocations.follow(id) events (log, invocation_state, error, sse_heartbeat).
  5. Stagehand/Playwright wiring uses browser.contexts()[0] not newContext().
  6. Stealth is on (stealth: true) for anything user-facing or against a real SaaS.
  7. For Managed Auth: <KernelManagedAuth /> is a client component ("use client"), the backend route calls auth.connections.create and auth.connections.login, and downstream browsers.create uses the same profile.name.

Final checks

  • KERNEL_API_KEY is read from env, not hardcoded.
  • @onkernel/sdk version is pinned.
  • Every browsers.create is paired with deleteByID (or wrapped by an invocation that will reap).
  • Sync vs async invocation chosen deliberately; the right *_timeout_seconds is set.
  • Default-context-only: no browser.newContext() against a Kernel browser.
  • Errors are caught with instanceof Kernel.APIError (or specific subclass).
  • If Managed Auth is used: backend creates the connection, the React component is "use client", the success handler launches a browser with the matching profile.name.
  • If Mode B: package.json has "type": "module" for TS apps; kernel deploy succeeded; the action is registered.
  • No leftover browser.close() as the only cleanup.
  • Stealth + timeout defaults match the Default stance above unless the task justifies otherwise.

Scope boundaries

This skill covers @onkernel/sdk and @onkernel/managed-auth-react in TypeScript. It does not cover:

  • The Python SDK (kernel-python-sdk)
  • Building generic Playwright tests against your own infra (use run-playwright)
  • The full kernel CLI surface beyond deploy and invoke (read kernel --help directly)
  • Browser Use's Python framework — there is no native TS package
Related skills
Installs
3
GitHub Stars
7
First Seen
3 days ago