Kimi WebBridge for Genii Desktop
Use this skill for browser and website tasks, including explicit /webbridge
or /kimi-webbridge requests. It handles only the browser portion of a task.
In Genii, OpenClaw, Chrome, and Kimi WebBridge run in the same bot sandbox when
desktop is enabled. Use the genii-desktop tools listed below so progress,
health checks, and browser actions stay on the configured local path.
Health Check
For slow browser work, first say one concise, user-facing progress sentence,
such as "Opening the browser." Do not mention Kimi, WebBridge, or internal
browser driver/tool names in routine progress or ordinary blockers unless the
user explicitly asks for implementation or debugging details. Then call
desktop_progress_notice with driver:"kimi-webbridge" and the same generic
message, followed by desktop_session_status.
Proceed only when the result shows:
- a
session_id webbridge.running: truewebbridge.extension_connected: true
If the desktop or extension is not healthy, report that browser automation is unavailable, include the user-relevant stage, and stop. Keep raw driver and status names in internal diagnostics unless the user explicitly asks for them. Do not guess fixes. The operator can use the Genii debug UI to restart Desktop or Gateway.
Tools
| Tool | Args | Use |
|---|---|---|
desktop_progress_notice |
stage, message, driver |
Emit a visible progress event before or between slow desktop steps |
desktop_session_status |
none | Health check and desktop runtime id/live URL |
desktop_live_url |
none | Return the noVNC desktop viewer URL |
web_navigate |
url, newTab, group_title |
Open a page in Chrome; defaults to reusing the active task tab |
web_find_tab |
url, active |
Reuse an already-open tab |
web_snapshot |
none | Accessibility tree/text with element refs; first choice for reading/click targets |
web_click |
selector |
Click an @e ref from snapshot or a CSS selector |
web_fill |
selector, value |
Fill inputs and contenteditable fields |
web_evaluate |
code |
Run compact JavaScript in the page |
web_screenshot |
format, quality, selector |
Visual fallback; avoid full-page screenshots unless needed |
web_list_tabs |
none | Inspect current tabs |
web_close_session |
none | Close task tabs only when explicitly requested or needed to unblock the task |
Standard Flow
- Emit a progress notice with
desktop_progress_notice. - Health check with
desktop_session_status. - If the user says
/webbridge ..., treat the remainder as the browser task. - Use
web_find_tabfor pages that may already be open. Otherwise useweb_navigatewithnewTab:falseor omitnewTabso the active task tab is reused. - Use
web_snapshotto read page content and locate clickable elements. - If
web_snapshotis empty or weak, wait briefly and retry once, then useweb_evaluatewith compact JavaScript. - Use
web_screenshotonly when the visual state matters or DOM reads are insufficient. Prefer small JPEG screenshots or element screenshots. - Leave useful user-visible tabs open, but do not accumulate duplicate task
tabs or Chrome extension popup tabs. Only call
web_close_sessionorweb_close_tabif the user explicitly asks to close/clean up, or if stale tabs block the current task.
Evaluate Rules
- Always return compact data. Prefer
JSON.stringify(data)or small arrays. - Wrap code in an IIFE to avoid re-declaring variables between calls:
(() => {
const data = Array.from(document.querySelectorAll("article")).slice(0, 3);
return JSON.stringify(data.map((item) => item.innerText));
})()
- If you need to scroll, use
web_evaluate:
(() => {
window.scrollBy(0, Math.floor(window.innerHeight * 0.8));
return JSON.stringify({scrolled: true, y: window.scrollY});
})()
X / Twitter Profile Extraction
For requests like "vào X xem karpathy đăng 3 bài gần nhất":
web_find_tabfor the profile URL, thenweb_navigateto the profile URL withnewTab:falseif no matching tab is open.- Wait briefly if the first snapshot is sparse.
- Use
web_snapshotfirst. - Use
web_evaluateto extract visible post candidates:
(() => {
const posts = Array.from(document.querySelectorAll("article"))
.map((article) => {
const text = article.innerText || "";
const links = Array.from(article.querySelectorAll("a[href*='/status/']"))
.map((a) => new URL(a.getAttribute("href"), location.origin).href);
return { text, links: Array.from(new Set(links)) };
})
.filter((post) => post.text.trim() || post.links.length)
.slice(0, 8);
return JSON.stringify({ url: location.href, title: document.title, posts });
})()
- Open the first distinct status URLs one by one with
web_navigateusingnewTab:falseunless you explicitly need side-by-side comparison. - On each status page, use
web_snapshotorweb_evaluateto read the main article text. - Summarize only content actually read. If X shows a login wall, rate limit, bot check, or empty timeline, say that explicitly with the observed URL and title.
Do not answer "no posts found" after a single empty snapshot. Use the fallback steps above first.
Failure Reporting
When blocked, include the failing stage and observed state:
- desktop health
- current URL/title if known
- whether snapshot was empty
- whether
document.querySelectorAll("article").lengthwas zero - whether X showed login/rate-limit/checkpoint text
This makes local debugging possible from the normal .jsonl transcript.