[{"data":1,"prerenderedAt":4},["ShallowReactive",2],{"readme:browser-harness-js":3},"\u003Cimg src=\"https:\u002F\u002Fr2.browser-use.com\u002Fgithub\u002Fasbfgihsbfbaosfjla.png\" alt=\"Browser Harness\" width=\"100%\" \u002F>\u003Ch1>Browser Harness JS ♞\u003C\u002Fh1>\n\u003Cp>The thinnest possible bridge from the LLM to Chrome. \u003Cstrong>No harness, no recipes, no rails\u003C\u002Fstrong> — just every CDP method as a typed JS call.\u003C\u002Fp>\n\u003Cp>One persistent WebSocket, 56 domains, 652 typed wrappers, zero wrapping of what Chrome already does.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>  ● agent: wants to click a button\n  │\n  ● no click() helper, no upload_file(), no goto()\n  │\n  ● agent writes the CDP call itself        await session.Input.dispatchMouseEvent({...})\n  │                                          await session.DOM.setFileInputFiles({...})\n  ✓ done — same pattern for all 652 methods\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>The protocol is the API.\u003C\u002Fstrong> If Chrome can do it, you can call it.\u003C\u002Fp>\n\u003Ch2>Installation\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-bash\">npx skills add https:\u002F\u002Fgithub.com\u002Fbrowser-use\u002Fbrowser-harness-js --skill cdp\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Or paste this into your agent — it'll install the skill, put the CLI on your PATH, and run a first task:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-text\">Run `npx skills add https:\u002F\u002Fgithub.com\u002Fbrowser-use\u002Fbrowser-harness-js --skill cdp`, then\nsymlink `browser-harness-js` into a directory on my PATH, then use the cdp skill to drive\nmy browser: look at all the tabs I have open, group them by topic, and screenshot the most\ninteresting one.\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>(The CLI auto-installs \u003Ca href=\"https:\u002F\u002Fbun.sh\" rel=\"nofollow ugc noopener\">\u003Ccode>bun\u003C\u002Fcode>\u003C\u002Fa> on first run if it's missing. Set \u003Ccode>BROWSER_HARNESS_SKIP_BUN_INSTALL=1\u003C\u002Fcode> to opt out.)\u003C\u002Fp>\n\u003Cp>If Chrome asks you to tick a remote-debugging checkbox, do it — that's how the agent attaches:\u003C\u002Fp>\n\u003Cimg src=\"https:\u002F\u002Fraw.githubusercontent.com\u002Fbrowser-use\u002Fbrowser-harness-js\u002FHEAD\u002Fdocs\u002Fsetup-remote-debugging.png\" alt=\"Remote debugging setup\" width=\"520\" \u002F>\u003Cp>See \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fbrowser-use\u002Fbrowser-harness-js\u002Fblob\u002FHEAD\u002Finteraction-skills\u002F\" rel=\"nofollow ugc noopener\">interaction-skills\u002F\u003C\u002Fa> for recipes on the mechanics that are not obvious from the CDP method list alone.\u003C\u002Fp>\n\u003Ch2>Files\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Ccode>SKILL.md\u003C\u002Fcode> — day-to-day usage; how to connect, pick a tab, call methods, persist state\u003C\u002Fli>\n\u003Cli>\u003Ccode>sdk\u002Fbrowser-harness-js\u003C\u002Fcode> — tiny CLI that auto-spawns the server and forwards snippets\u003C\u002Fli>\n\u003Cli>\u003Ccode>sdk\u002Frepl.ts\u003C\u002Fcode> — Bun HTTP server holding one persistent \u003Ccode>Session\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>\u003Ccode>sdk\u002Fsession.ts\u003C\u002Fcode> — the \u003Ccode>Session\u003C\u002Fcode> class: transport, connect, target routing, events\u003C\u002Fli>\n\u003Cli>\u003Ccode>sdk\u002Fgen.ts\u003C\u002Fcode> — codegen: reads \u003Ccode>browser_protocol.json\u003C\u002Fcode> + \u003Ccode>js_protocol.json\u003C\u002Fcode> → typed wrappers\u003C\u002Fli>\n\u003Cli>\u003Ccode>sdk\u002Fgenerated.ts\u003C\u002Fcode> — every CDP method as \u003Ccode>session.&lt;Domain&gt;.&lt;method&gt;(params)\u003C\u002Fcode> (generated)\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>No helpers file. No \u003Ccode>click()\u003C\u002Fcode>, no \u003Ccode>goto()\u003C\u002Fcode>, no \u003Ccode>upload_file()\u003C\u002Fcode> — just the protocol, typed.\u003C\u002Fp>\n\u003Ch2>Why no pre-baked helpers?\u003C\u002Fh2>\n\u003Cp>Every helper is a lie about what CDP already gives you. \u003Ccode>click(x, y)\u003C\u002Fcode> hides \u003Ccode>Input.dispatchMouseEvent\u003C\u002Fcode> — which has 14 parameters the LLM might need (button, clickCount, modifiers, pointerType, force, tangentialPressure, …). A harness that exposes three of them quietly limits what the agent can do.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Types are the docs. \u003Ccode>session.Page.navigate(\u003C\u002Fcode> triggers autocomplete with the exact params — same JSDoc as the CDP reference.\u003C\u002Fli>\n\u003Cli>No version drift. The SDK is regenerated from the upstream protocol JSON; new Chrome methods appear as soon as you swap the JSON.\u003C\u002Fli>\n\u003Cli>No \"helper doesn't handle my case\" detours. If CDP can do it, the agent can call it — directly, typed, today.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>The only \"helpers\" you'll find are things CDP itself is missing:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>listPageTargets()\u003C\u002Fcode> — filters \u003Ccode>chrome:\u002F\u002F\u003C\u002Fcode> \u002F \u003Ccode>devtools:\u002F\u002F\u003C\u002Fcode> out of \u003Ccode>Target.getTargets\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>\u003Ccode>resolveWsUrl({wsUrl|port|profileDir})\u003C\u002Fcode> — reads \u003Ccode>DevToolsActivePort\u003C\u002Fcode> for Chrome 144+\u003C\u002Fli>\n\u003Cli>\u003Ccode>session.use(targetId)\u003C\u002Fcode> \u002F \u003Ccode>session.waitFor(method, pred, timeout)\u003C\u002Fcode> — the two routing primitives you genuinely need\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>Contributing\u003C\u002Fh2>\n\u003Cp>PRs welcome. The best way to help: \u003Cstrong>contribute a new interaction skill\u003C\u002Fstrong> under \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fbrowser-use\u002Fbrowser-harness-js\u002Fblob\u002FHEAD\u002Finteraction-skills\u002F\" rel=\"nofollow ugc noopener\">interaction-skills\u002F\u003C\u002Fa> when you figure out the CDP recipe for something non-obvious (a dropdown framework, a shadow-DOM trap, a network-wait pattern).\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Keep recipes in \u003Cstrong>pure CDP\u003C\u002Fstrong> — \u003Ccode>session.Domain.method(...)\u003C\u002Fcode>, not wrapped helpers.\u003C\u002Fli>\n\u003Cli>Lead with the shortest method call that works; add the workaround or trap afterwards.\u003C\u002Fli>\n\u003Cli>Small and focused beats comprehensive. One mechanic per file.\u003C\u002Fli>\n\u003Cli>Bug fixes, codegen improvements, and \u003Ccode>session.ts\u003C\u002Fcode> refinements are equ\u003C\u002Fli>\n\u003C\u002Ful>\n",1784308501323]