by jeet-dhandha
Drive multiple Chrome profiles simultaneously through Kimi WebBridge — one daemon per profile, one router, deterministic ports.
The deep catalog scan for this skill is still queued. Run an instant dependency check now instead.
# Add to your Claude Code skills
git clone https://github.com/jeet-dhandha/kimi-webbridge-fleetGuides for using ai agents skills like kimi-webbridge-fleet.
No comments yet. Be the first to share your thoughts!
Let one AI agent drive several of your real Chrome profiles at once — each with its own Google login — instead of one at a time. A drop-in layer over Kimi WebBridge: no patching, your existing
:10086calls keep working — you just add a"profile"field.
Kimi WebBridge lets an AI agent drive your real Chrome with your real logins. By design it has a single connection slot: one daemon, one extension, one profile. If you have a work account and a personal account, only one can be driven at a time — the other is rejected until you quit its Chrome or toggle its extension off.
kimi-webbridge-fleet removes that limit without patching anything. It runs one stock daemon per profile on its own port, and puts a small router on the usual :10086 so your existing calls keep working — you just add a "profile" field.
The stock daemon enforces two singletons:
kimi-webbridge start refuses to launch if anything answers http://127.0.0.1:10086/status (the probe is hardcoded to :10086, regardless of --addr).The key observation: the daemon singleton only guards :10086. Leave :10086 empty and you can start as many daemons as you like on other ports — each its own independent slot. So fleet:
10100 + hash(profileDir)), each with its own state dir;:10086 that proxies /command to the right daemon based on a top-level "profile" field;/ws directly (the router only proxies HTTP).No binary patching, nothing that breaks on a Kimi WebBridge upgrade.
Implementing this natively? If you maintain Kimi WebBridge (or want to send a patch),
docs/UPSTREAM-NATIVE-MULTIPROFILE.mdis an explicit, agent-followable spec for adding multi-profile support inside the daemon + extension — grounded in the observed protocol, with acceptance tests. With those changes, fleet becomes unnecessary.
macOS + Google Chrome only, right now. The implementation leans on macOS-specific commands and Chrome-specific paths:
| Used for | macOS command / path (this tool) | Linux/Windows equivalent (not yet implemented) |
|---|---|---|
| Open a profile window / wake the extension | "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --profile-directory=… <urls> (binary direct, headful) |
google-chrome --profile-directory=… / start chrome … |
| Is Chrome running | pgrep -x "Google Chrome" |
pgrep chrome / tasklist |
Quit Chrome (to write storage.local) |
osascript … quit then pkill |
pkill chrome / taskkill |
| Force-install policy | defaults write com.google.Chrome … |
policy JSON in /etc/opt/chrome/policies/… / registry |
| Profiles + sessions + extension registry | ~/Library/Application Support/Google/Chrome |
~/.config/google-chrome / %LOCALAPPDATA%\…\Chrome\User Data |
Porting is mostly swapping those helpers (src/profiles.mjs, src/extension.mjs).
PRs welcome. Chromium/Brave/Edge would also need their own paths and extension id.
bun too).Two steps, straight from kimi.com/features/webbridge (the "With Local Agent" flow):
1. Get the Chrome extension — Kimi WebBridge on the Chrome Web Store.
2. Install the local daemon with the official bootstrap installer:
curl -fsSL https://cdn.kimi.com/webbridge/install.sh | bash
This downloads the binary to ~/.kimi-webbridge/bin/kimi-webbridge (the path fleet orchestrates), starts the daemon, and installs the WebBridge skill into detected AI-agent runtimes.
# verify it's installed and the stock daemon answers
~/.kimi-webbridge/bin/kimi-webbridge status
# keep it current
~/.kimi-webbridge/bin/kimi-webbridge upgrade
As a Claude Code skill/plugin — so your agent can drive the fleet itself:
/plugin marketplace add jeet-dhandha/kimi-webbridge-fleet
/plugin install kimi-webbridge-fleet@kwb
As a CLI — via npm, no clone:
npx kimi-webbridge-fleet profiles # one-off
npm i -g kimi-webbridge-fleet # puts `kwb` on your PATH
From source — for hacking / PRs:
git clone https://github.com/jeet-dhandha/kimi-webbridge-fleet.git
cd kimi-webbridge-fleet
npm link # optional: puts `kwb` on your PATH
# or just run: node bin/kwb.mjs <cmd>
# 1. See your profiles, their assigned ports, and which have the extension
kwb profiles
# 2. Point each profile's extension at its OWN daemon — zero clicks (no popup).
# This writes the extension's local_url on disk, which needs Chrome closed, so
# kwb connect quits Chrome for you (your session is saved for restore).
kwb connect "Work" "Personal"
# 3. Bring up the daemons + router on :10086, reopen each window, WAKE each extension,
# and poll until each reports "✓ connected". (If Chrome is already fully quit,
# `kwb up` alone performs the connect write for you — step 2 is optional then.)
kwb up "Work" "Personal"
# 4. Drive any profile by name — same call, one extra field:
curl -s -X POST http://127.0.0.1:10086/command \
-H 'Content-Type: application/json' \
-d '{"action":"navigate","args":{"url":"https://search.google.com/search-console"},"session":"audit","profile":"Work"}'
# 5. When done
kwb down # stops the fleet, restores the stock :10086 daemon
A request with no "profile" is routed to your default (last-used profile whose daemon is up, or KWB_DEFAULT_PROFILE).
You want a morning digest: unread Reddit DMs from your Personal account and unread Slack mentions from your Work email — pulled, cross-referenced, summarized. Stock Kimi WebBridge gives you one slot, so you'd drive one account, then quit Chrome or toggle its extension off to free the slot for the other — serial, and you lose the live session. Fleet keeps both connected at once; same call, you just name the profile:
# Reddit — Personal profile
curl -s -X POST http://127.0.0.1:10086/command -H 'Content-Type: application/json' \
-d '{"action":"navigate","args":{"url":"https://www.reddit.com/message/unread/"},"session":"digest","profile":"Personal"}'
# Slack — Work profile, same instant, nothing toggled off
curl -s -X POST http://127.0.0.1:10086/command -H 'Content-Type: application/json' \
-d '{"action":"navigate","args":{"url":"https://app.slack.com/client"},"session":"digest","profile":"Work"}'
Read both, merge, act — two real sessions, zero juggling. Same trick scales to many Google accounts (Gmail / Drive / Ads / Search Console) running side by side.
Pointing a profile's extension at its own daemon port used to be a manual click in the extension popup. Fleet now does it for you, with no popup, no CDP, no dependencies — in two halves, both pure Node:
local_url key in its
chrome.storage.local LevelDB (which, unlike Secure Preferences, is not
integrity-protected). kwb connect writes it directly while Chrome is closed (LevelDB
is single-writer), replacing the popup's Connect click. The value persists, so
later kwb up runs just reconnect.local_url when it starts, but it registers no
chrome.runtime.onStartup listener, so Chrome never auto-starts it on launch — on an
already-set-up profile the write would otherwise sit unused. kwb up wakes the worker
by opening the extension's own popup page (chrome-extension://<id>/popup.html) as a
tab — the headful equivalent of clicking the toolbar icon. Chrome is launched via its
binary directly (headful), since macOS open doesn't reliably forward a
chrome-extension:// URL.This works for both Chrome-Web-Store installs and unpacked / developer-mode
builds (whose extension id Chrome assigns unpredictably — fleet identifies the extension
by name and reads back whichever id it was given). To point a profile back at the stock
single :10086 bridge: kwb connect "Work" --restore.
Why not CDP /
--remote-debugging-port? Branded Chrome 136+ refuses remote debugging on the default user-data-dir where real profiles live, and--load-extensionis ignored in Google Chrome 137+. The on-disk write + popup wake sidesteps both.
| Command | What it does |
|---|---|
kwb profiles |
List profiles, hashed ports, e |