build-kernel-ts-sdk
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-browserCLI directly without the Kernel provider — userun-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 deploy → kernel.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
KERNEL_API_KEYfrom env. Never hardcode. Env wins overapiKey:option only when the option is omitted; passing both is allowed.- Pin the SDK.
@onkernel/sdkis auto-generated by Stainless and rev's frequently. Pin a minor version range; verify method names from the installednode_modules/@onkernel/sdk/api.mdif unsure. - Never use
browser.close()as cleanup. Playwright/Puppeteerclose()only severs the local CDP connection. Always callkernel.browsers.deleteByID(session_id)(or rely ontimeout_seconds). - Sync invocation cap is ~100s. Anything longer must use
async: truewithasync_timeout_seconds(10–3600) andinvocations.follow(id)for SSE. - Default browser context only. Kernel browsers ship with one default context and one open page. Use
browser.contexts()[0]andpages()[0]— do not callbrowser.newContext()/context.newPage()to make a "fresh" one. - 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 aKERNEL_PROJECTenv var — that's a user convention you have to wire through). OAuth (CLI) is always org-wide. - Runtime requirements. Node 20+, TypeScript ≥ 4.9. Deno 1.28+, Bun 1.0+, Cloudflare Workers, Vercel Edge supported. No React Native.
- Payload max 4.5 MB.
invocation.payloadandinvocation.outputare JSON-encoded strings — caller mustJSON.parse. Larger artifacts (e.g. screenshots, multi-MB blobs) go throughbrowsers.fs.*or your own object store.
Default stance
stealth: truefor any non-trivial site (bot detection is the rule, not the exception).timeout_seconds: 300minimum; the 60s default is too aggressive for real automation. Max is259200(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_secondscountdown to deletion start. Don't expect long-idle-but-open sessions to be free — keep a connection live.
Workflow
- Classify the operating mode (A vs B). If mixed, name which surface each piece is on.
- Construct the client.
import Kernel from '@onkernel/sdk'. Verify env (KERNEL_API_KEYis the only required one;KERNEL_LOG,KERNEL_BASE_URL,KERNEL_CUSTOM_HEADERS,KERNEL_SUPPRESS_BUN_WARNINGare optional). For local development hittinghttps://localhost:3001/, passenvironment: 'development', baseURL: null. For project-scoped API keys, wireX-Kernel-Project-IdthroughdefaultHeaders. Seereferences/guides/client-and-config.md. - Pick the browser-control surface — raw CDP / Playwright-inside-VM / computer-controls / browser-curl. See
references/patterns/browser-control-surfaces.md. - Wire profiles or Managed Auth if the agent needs persistent login. See
references/patterns/profiles-pools-credentials.mdandreferences/guides/managed-auth.md. - Handle lifecycle. Always pair
browsers.createwithbrowsers.deleteByID, even on error paths. Usetry/finally. Seereferences/guides/browsers-lifecycle.md. - Deploy or run. For Mode B,
kernel deployand consume invocations; for Mode A, run inside your service. Seereferences/guides/apps-deploy-invoke.mdandreferences/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 PlaywrightBrowseronly disconnects CDP. The Kernel browser keeps running untiltimeout_secondselapses or you callkernel.browsers.deleteByID(session_id). Always paircreatewithdeleteByIDin afinallyblock.
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. Usebrowser.contexts()[0].pages()[0].
Sync invocations time out at ~100s. If your action does any non-trivial browser work, set
async: trueandinvocations.follow(id)instead. Switching after the fact requires re-deploying.
Stagehand connects via local-CDP, not Browserbase. When using
@browserbasehq/stagehandwith Kernel, setenv: 'LOCAL'andlocalBrowserLaunchOptions.cdpUrl: session.cdp_ws_url. Do not setapiKeyorprojectId— those are Browserbase-only.
browsers.delete(singular) is deprecated. Usebrowsers.deleteByID(id). The plural form takes apersistent_idand 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:
- The SDK is installed at a pinned version;
node_modules/@onkernel/sdk/api.mdexists and matches the methods you call. KERNEL_API_KEYresolves at runtime; if the key is org-wide,defaultHeaders: { 'X-Kernel-Project-Id': '…' }is wired through the constructor.- Every
browsers.createis paired with adeleteByIDin afinally(grep the diff). - Long-running invocations use
async: trueand consumeinvocations.follow(id)events (log,invocation_state,error,sse_heartbeat). - Stagehand/Playwright wiring uses
browser.contexts()[0]notnewContext(). - Stealth is on (
stealth: true) for anything user-facing or against a real SaaS. - For Managed Auth:
<KernelManagedAuth />is a client component ("use client"), the backend route callsauth.connections.createandauth.connections.login, and downstreambrowsers.createuses the sameprofile.name.
Final checks
-
KERNEL_API_KEYis read from env, not hardcoded. -
@onkernel/sdkversion is pinned. - Every
browsers.createis paired withdeleteByID(or wrapped by an invocation that will reap). - Sync vs async invocation chosen deliberately; the right
*_timeout_secondsis 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 matchingprofile.name. - If Mode B:
package.jsonhas"type": "module"for TS apps;kernel deploysucceeded; 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
kernelCLI surface beyonddeployandinvoke(readkernel --helpdirectly) - Browser Use's Python framework — there is no native TS package
More from yigitkonur/skills-by-yigitkonur
run-research
>-
37run-agent-browser
Use skill if you are driving the agent-browser CLI for browser navigation, DOM-grounded interaction, session/tab management, screenshots, data extraction, or repeatable web app workflows.
33build-skills
Use skill if you are creating or substantially revising a Claude skill and need workspace-first evidence, remote comparison, and repo-fit synthesis before writing SKILL.md.
32publish-npm-package
Use skill if you are automating npm publishing via GitHub Actions and need auth, versioning, provenance, or workflow-template choices.
30build-mcp-use-server
Use skill if you are building or extending TypeScript MCP servers with the mcp-use library — tools, Zod schemas, resources, prompts, transports, OAuth, sessions, testing, and deployment.
29develop-typescript
>-
29