---
name: kernel-browser
description: Bridge `browser-harness` (browser-use's CDP harness) to a Kernel cloud browser via one env var. Use whenever a task needs a browser that is not the user's local Chrome — headless servers, parallel sub-agents, persistent logins, regional IPs, unattended jobs.
---

# kernel-browser

Teaches the one-env-var bridge between [`browser-harness`](https://github.com/browser-use/browser-harness) and a [Kernel](https://onkernel.com) cloud browser. Everything else (installing the kernel CLI, minting/deleting sessions, recording replays) lives in skills maintained upstream — install them too.

## Prereqs (install these skills, this one composes them)

- [`browser-harness`](https://github.com/browser-use/browser-harness) — `SKILL.md` from the repo. Covers heredoc form, the helper library (`new_tab`, `page_info`, `js`, …), interaction skills, daemon model.
- [`kernel-cli`](https://www.skills.sh/kernel/skills/kernel-cli) — `npx skills add https://github.com/kernel/skills --skill kernel-cli`. Covers the full Kernel CLI surface: install + auth, `kernel browsers create / list / get / delete` (stealth, headless, profile, proxy, viewport, timeout, …), and `kernel browsers replays start / stop / download`.

Plus `jq`, and the Kernel CLI authenticated — either `kernel login` (OAuth, the normal path) or `KERNEL_API_KEY` exported (for headless / CI environments with no browser available for OAuth).

## The bridge

After minting a kernel browser per the `kernel-cli` skill, do this:

```bash
export BU_CDP_WS=$(echo "$SESSION" | jq -r '.cdp_ws_url')
BU_NAME=kernel browser-harness <<'PY'
new_tab("https://example.com")
print(page_info())
PY
```

- `BU_CDP_WS` tells `browser-harness` to use the Kernel CDP URL instead of discovering local Chrome. The harness picks it up from env — no flag, no `connect` call.
- `BU_NAME=kernel` namespaces the harness daemon socket so this run doesn't collide with a local-Chrome harness daemon you might also have running.
- Kernel browsers boot **headful by default** — print `browser_live_view_url` from the create response so the user can watch.

## Multi-step usage (the daemon does the work)

For tasks that span more than one shell call — mint, drive, inspect, drive more, tear down — you do **not** need to thread `BU_CDP_WS` through every call. The harness daemon caches the CDP connection by `BU_NAME` and reuses it.

The only state you actually need to persist between calls is `SESSION_ID`, for teardown. Write it to a known file when you mint:

```bash
# mint (one shell call)
SESSION=$(kernel browsers create --stealth -o json)
echo "$SESSION" | jq -r '.session_id'  > /tmp/kernel-sid
export BU_CDP_WS=$(echo "$SESSION" | jq -r '.cdp_ws_url')
BU_NAME=kernel browser-harness <<'PY'                  # first call: starts the daemon, caches the connection
new_tab("https://news.ycombinator.com"); print(page_info())
PY

# subsequent harness calls (separate shell call — no BU_CDP_WS needed)
BU_NAME=kernel browser-harness <<'PY'
print(js("document.querySelector('.titleline a').textContent"))
PY

# teardown (separate shell call)
kernel browsers delete "$(cat /tmp/kernel-sid)" && rm /tmp/kernel-sid
```

If `/tmp/kernel-sid` ever gets lost, recover the session ID with `kernel browsers list -o json | jq`.

## Parallel sub-agents

One session, one `BU_NAME`. Per-call env vars work cleanly:

```bash
BU_NAME=a BU_CDP_WS="$CDP_A" browser-harness <<'PY' …
BU_NAME=b BU_CDP_WS="$CDP_B" browser-harness <<'PY' …
```

## Notes

- The Kernel CDP URL is a JWT-signed `wss://` endpoint — paste it directly into `BU_CDP_WS`, no rewriting.
- If `browser-harness` errors with `BU_CDP_WS unreachable`, the kernel session probably hit its idle timeout. Mint a new one. `--timeout N` on create extends it.
- Always tear down (`kernel browsers delete "$(cat /tmp/kernel-sid)"`) when the task ends — sessions bill until idle timeout otherwise. If you lost the SID file, `kernel browsers list -o json | jq` recovers it.
- Recording → wrap the harness call between `kernel browsers replays start "$SESSION_ID" -o json` (capture the returned `replay_id`) and `kernel browsers replays stop "$SESSION_ID" "$REPLAY_ID"`, then `kernel browsers replays download "$SESSION_ID" "$REPLAY_ID" -f ./replay.mp4`.
