Skip to content

About

Local-first browser bridge for AI agents: Chrome MV3 extension + Node daemon. Accessibility-tree refs, screenshots, PDFs, no telemetry. MIT.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Kai WebBridge

CI npm License: MIT

Open-source browser bridge for local AI agents. Let an agent drive your real Chromium browser — your tabs, your cookies, your logins — through a small local daemon and a Manifest V3 extension.

No cloud service, no headless browser, no telemetry. The agent talks HTTP to 127.0.0.1; the extension executes commands with chrome.debugger.

Local agent or script
  │  POST http://127.0.0.1:10087/command   {"action","args","session"}
  ▼
Kai WebBridge daemon (Node.js)  ──  sessions, output files, optional token
  │  WebSocket ws://127.0.0.1:10087/ws     hello / tool_call / tool_result
  ▼
Chrome extension (MV3)  ──  chrome.debugger → CDP → your real tab

Install

Requirements: Node.js 20+, a Chromium-based browser 120+ (Chrome, Edge, Brave, Opera, or Vivaldi).

npm (recommended)

npx -y kai-webbridge setup

Or install the CLI globally:

npm install -g kai-webbridge
kai-webbridge setup

setup downloads nothing else: the npm package already contains the extension and skill. If you use npx without installing globally, prefix later commands with npx -y kai-webbridge (for example npx -y kai-webbridge status).

From a checkout

git clone https://github.com/kai38/kai-webbridge.git
cd kai-webbridge
npm install
node bin/kai-webbridge.js setup

Release tarballs are also attached to every GitHub release for offline installs.

What setup does

  1. Copies the agent skill into detected runtimes and ~/.kai-webbridge/skills.
  2. Copies the extension to a stable path, ~/.kai-webbridge/extension, so Chrome keeps the same extension ID across upgrades.
  3. Starts the daemon on 127.0.0.1:10087.
  4. Prints the extension folder to load.

Flags: --no-start (configure only), --no-skill (skip agent runtimes), --port, --token, --home.

Load the extension (one manual step)

The browser only allows unpacked extensions to be loaded from its own UI:

  1. Open the extension manager in the browser where you want the bridge:
    • Chrome: chrome://extensions
    • Edge: edge://extensions
    • Brave: brave://extensions
    • Opera: opera://extensions
    • Vivaldi: vivaldi://extensions
  2. Turn on Developer mode.
  3. Click Load unpacked and select ~/.kai-webbridge/extension (the exact path is printed by setup).

Verify

curl -s http://127.0.0.1:10087/status

extension_connected: true means the daemon and browser are talking. extension_browser names the browser that holds the extension (for example Chrome 153.0.8010.36). If the CLI is installed globally, kai-webbridge status prints the same JSON. If the extension shows an error, open its Options page and confirm the WebSocket URL is ws://127.0.0.1:10087/ws (or the port you configured).

To update, run setup again (npx -y kai-webbridge@latest setup, or npm install -g kai-webbridge && kai-webbridge setup), then reload the extension in chrome://extensions.

Try it

curl -s -X POST http://127.0.0.1:10087/command \
  -H 'Content-Type: application/json' \
  -d '{"action":"navigate","args":{"url":"https://example.com","newTab":true,"group_title":"Example"},"session":"demo"}'

curl -s -X POST http://127.0.0.1:10087/command \
  -H 'Content-Type: application/json' \
  -d '{"action":"snapshot","args":{"format":"aria"},"session":"demo"}'

The snapshot returns lines like - link "More information..." [ref=e4]. Use @e4 as the target:

curl -s -X POST http://127.0.0.1:10087/command \
  -H 'Content-Type: application/json' \
  -d '{"action":"click","args":{"selector":"@e4"},"session":"demo"}'

curl -s -X POST http://127.0.0.1:10087/command \
  -H 'Content-Type: application/json' \
  -d '{"action":"screenshot","args":{"format":"jpeg","quality":70},"session":"demo"}'
# → {"ok":true,"data":{"path":"/tmp/kai-webbridge-screenshots/...jpg", ...}}

curl -s -X POST http://127.0.0.1:10087/command \
  -H 'Content-Type: application/json' \
  -d '{"action":"close_session","args":{},"session":"demo"}'

Tools

Category Tools
Tabs navigate, find_tab, list_tabs, list_browser_tabs, attach_tab, close_tab, close_session
Observe snapshot, inspect, read_page, wait
Act click, mouse_click, fill, select, press_key, check, hover, batch, scroll, upload, dialog
Run evaluate, cdp
Capture screenshot, save_as_pdf, network

Full request/response reference: docs/protocol.md. The agent-facing contract is skill/kai-webbridge/SKILL.md.

Sessions

One task = one session, with one Chrome tab group for the tabs it opens. The session field goes at the top level of the request body:

{"action":"navigate","args":{"url":"https://example.com","group_title":"Research"},"session":"research"}

The daemon remembers the session's current tab and injects internal _session, _tabId, and _ownedTabIds fields. The extension groups the tabs visibly under the group title, and close_session closes the whole group.

Sessions persist to ~/.kai-webbridge/sessions.json, so they resume after a daemon restart. After a browser restart, the extension's tab-group binding and list_tabs re-establish the session's tabs.

To work on a page the user already has open:

{"action":"find_tab","args":{"url":"https://example.com","borrow":true},"session":"research"}

Or inspect all open pages with list_browser_tabs, then attach_tab a tabId. Borrowed tabs are not moved into the session group and are not closed by close_session. close_tab requires force:true to close one; navigate requires newTab:true or adopt:true to reuse one.

Page briefs and batch actions

When a page is opened, attached, or resumed, the response includes a numbered map of interactive elements and a full-page screenshot:

{
  "page": {
    "counts": {"buttons": 10, "text_fields": 4, "links": 3},
    "interactive": [
      {"id": 1, "role": "button", "name": "Search", "target": "[data-kai-wb=\"1\"]"},
      {"id": 2, "type": "text", "name": "Query", "target": "[data-kai-wb=\"2\"]"}
    ]
  },
  "screenshot_path": "/tmp/kai-webbridge-screenshots/screenshot_…png"
}

Fill and click several elements in one call:

{"action":"batch","args":{"commands":"!2:t:\"Kai WebBridge\",1:c!"},"session":"research"}

batch supports c/click, t/type, s/select, k/key, h/hover, u/upload, x/check, o/uncheck, with numeric aliases 1–8. id:"text" means fill. inspect re-scrapes without acting. IDs reset after navigation or reload.

Configuration

~/.kai-webbridge/config.json (all keys optional):

{
  "host": "127.0.0.1",
  "port": 10087,
  "token": "optional-shared-secret",
  "commandTimeoutMs": 120000,
  "extensionWaitMs": 29000,
  "outputDir": "/tmp",
  "logLevel": "info"
}

CLI flags override the file: --host, --port, --token, --output-dir, --log-level, --home.

If token is set, commands must send Authorization: Bearer <token> and the extension must be configured with the same token.

Security, in one paragraph

The extension can read and control every tab (it needs the debugger permission). The daemon accepts only local connections, ignores any /command request that carries an Origin header (so web pages cannot drive it), and optionally requires a bearer token. It has no telemetry. Treat the agent exactly as you would treat a person at your keyboard. Details: docs/security.md · privacy policy.

Development

npm install
npm test          # unit tests: protocol, sessions, outputs, daemon HTTP/WS
npm run test:e2e  # real Chrome + extension + daemon round trip

The e2e test needs Chrome for Testing because Google Chrome 137+ ignores --load-extension:

npm run fetch-chrome
npm run test:e2e

The suite runs headless and covers navigation, snapshot refs, fill, click, contenteditable, screenshots, PDF, network capture, upload, dialogs, tab grouping, and session close. See CONTRIBUTING.md before sending a pull request.

Project layout

bin/            CLI entry
src/            daemon (config, sessions, hub, HTTP, outputs, persistence, CLI)
extension/      Manifest V3 extension (no build step)
skill/          agent skill installed by `setup` / `install-skill`
test/unit/      fast tests without a browser
test/e2e/       headless Chrome integration test
docs/           architecture, protocol, security
.github/        CI workflow

More: architecture · protocol · security.

Limitations

  • Top frame only: snapshot/click/fill/evaluate do not traverse cross-origin iframes (use cdp or navigate the frame URL).
  • click/fill dispatch DOM-level events, so pages that strictly require isTrusted may ignore them; mouse_click and cdp use real CDP input for those cases.
  • One browser per daemon. A second extension connection is refused with WebSocket close code 4409.
  • No multi-agent isolation: sessions are names, not security boundaries.
  • Borrowed tabs are protected: close_tab needs force:true, and navigate needs newTab:true or adopt:true.
  • HTTP/HTTPS only; file:// and chrome:// navigation is refused.
  • Chromium browsers block extensions from scripting their Web Store domains (chrome.google.com/webstore, chromewebstore.google.com). navigate can open and group those tabs, but they cannot be snapshotted, clicked, or typed into.
  • Cross-platform code exists, but automated e2e is currently verified on Linux.

Independence and trademarks

This is an independent, from-scratch implementation. It is not affiliated with, endorsed by, or sponsored by Moonshot AI, and it contains no code, skill text, icons, or other assets from the Kimi WebBridge product. The names "Kimi", "Kimi WebBridge", and "Chrome" are trademarks of their respective owners, used only to describe prior art or the runtime this project talks to.

License

MIT — see LICENSE. Third-party notices are in THIRD_PARTY_NOTICES.md.

About

Local-first browser bridge for AI agents: Chrome MV3 extension + Node daemon. Accessibility-tree refs, screenshots, PDFs, no telemetry. MIT.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages