Shared real browser for DSH: a native Electron window the human can watch and take over, driven by the agent over CDP with 20 browser_* tools (open/snapshot/execute/fill/screenshot/download/auth), per-task session isolation, cookie persistence, CAPTCHA detection; self-hosts on plain dsh web without a desktop shell.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-builtin-browser
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:wqty123/dsh-browser
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time. Only install sources you trust, and pin a commit (github:owner/repo#sha).
README
Documentation
| Goal | Entry |
|---|---|
| Why a shared real browser, and how it differs from headless approaches | Why a shared real browser |
| Installation, configuration, day-to-day use | User guide |
| All 20 tools: parameters, output, examples | Tool reference |
| How the seam / provider / tools layers and self-hosting work | Architecture |
| Documentation index and README split | Docs index |
What is this
dsh-builtin-browser adds browser capability to DeepSeek Harness:
- A real view, not a relay: the browser is a native
WebContentsView; the human sees every step the agent takes and can grab control at any time; - Install-and-use: with a desktop shell the shell's embedded view is used; on plain
dsh webthe plugin self-hosts — it spawns its own Electron window with zero extra configuration; - One plugin, one toolset: after install the agent automatically gets 20
browser_*tools (open, inspect, interact, fill forms, screenshot, download, auth management…).
In one sentence: installing the plugin gives you a real browser that is shared with the user and drivable by the agent.
Quick start
# Option 1: install from npm (published)
dsh plugin --profile web add dsh-builtin-browser
# Option 2: install from a checkout (one plugin, one repository)
dsh plugin --profile web add <path-to-this-repo>
After install the agent can use the browser tools, e.g.:
| What you want | Tool | Notes |
|---|---|---|
| Open a page | browser_open |
Opens a URL and returns a numbered snapshot |
| Understand a page | browser_snapshot |
Numbered inventory of inputs/buttons/links to target |
| Operate a page | browser_execute |
Runs JS in the page (native setters, framework-friendly) |
| Fill a form | browser_fill |
Fills many fields in one call, optional submit |
| See the page | browser_screenshot |
PNG capture, optionally saved for a vision model |
See the full list in Tool reference.
Main features
Why this plugin
- Install-and-use, zero config: no desktop shell or extra startup step required; on plain
dsh webit self-hosts an Electron window and thebrowser_*tools just work. - Human-in-the-loop, non-interfering: the user sees and can take over every agent action; per-task isolation gives each parallel task its own tabs and history.
- Built for the real world: CAPTCHA detection, login persistence, batch form filling, authenticated downloads, operation replay, action restriction — real-browser automation that is actually reliable.
- Testable, replaceable architecture: the provider talks to Electron through the
ElectronBrowserViewHostseam, so a future headless relay provider can serve remote deployments without touching the tool layer.
Tool reference
| Tool | Purpose | Guard |
|---|---|---|
browser_open |
Open a URL (optionally in a new tab); returns a page snapshot | ✅ |
browser_snapshot |
Numbered inventory of interactive elements (inputs/buttons/links) | – |
browser_execute |
Run JS in the page; args arrive as arguments[0..n] |
✅ |
browser_content |
Fetch the page as html / markdown / txt / json (selector, maxChars, timeoutMs) | – |
browser_click |
Click at viewport coordinates (for vision-located targets) | ✅ |
browser_type |
Type text into the focused element (CDP Input.insertText) |
✅ |
browser_fill |
Batch form fill (selector/name/label matching, controlled inputs, selects, checkbox/radio, optional submit) | ✅ |
browser_screenshot |
PNG capture, optional fullPage and savePath |
– |
browser_list_tabs |
List the session's tabs | – |
browser_switch_tab |
Switch to a tab by id (also switches the visible view when self-hosted) | ✅ |
browser_close_tab |
Close a tab by id; closing the active tab activates the next | – |
browser_reset |
Close all tabs of this task, back to one blank tab | ✅ |
browser_session |
Show this task's browser session and tabs | – |
browser_reset_session |
Close and rebuild this task's browser session | ✅ |
browser_history |
Operation log (newest last), with per-step success/error and result summary | – |
browser_replay |
Replay one step by sequence number (navigate/execute/click/type) | ✅ |
browser_download |
Download a URL with session cookies to a local file (256 MB cap) | ✅ |
browser_auth |
Export/restore cookies (login persistence, self-hosted) | ✅ |
browser_challenge |
Detect a human-verification challenge (CAPTCHA / Cloudflare / reCAPTCHA / hCaptcha / Turnstile) | – |
browser_restrict |
Restrict allowed browser actions (allow-list; empty list lifts it) | – |
"Guard" column: ✅ actions are governed by the
browser_restrictallow-list; read-only tools (snapshot/content/screenshot/list_tabs/session/challenge/history) are never blocked.
Operating discipline (click/fill)
- Prefer DOM semantics over coordinates: submit forms with
form.requestSubmit(); click withelement.click(); coordinate clicks are the last resort. - Target the right element: pages often have hidden duplicates (e.g. mobile buttons); filter visible elements with
browser_execute(getBoundingClientRect()w/h > 0,getComputedStylenotdisplay:none), then take coordinates. - Click right after taking coordinates: do not insert other operations in between (filling/scrolling moves elements and invalidates old coordinates).
- Verify before clicking: use
document.elementFromPoint(x, y)to confirm the coordinate hits the intended element (button/link), then perform the real click. - DPR awareness: CDP input uses CSS pixels; on high-DPI screens calibrate with
elementFromPointinstead of guessing coordinates.
Configuration
The plugin mounts through cordis.patch.yml (three rows); per-row config:
| Row | Key | Type | Default | Description |
|---|---|---|---|---|
browser-electron |
viewHost |
object | required | ElectronBrowserViewHost supplied by the host shell (typically !!js ctx.get('electronViewHost')) |
browser-electron |
httpOnly |
boolean | true |
Allow HTTP(S) navigation only; other protocols (e.g. file:/data:) rejected (BROWSER_NAVIGATION_BLOCKED) |
browser-electron |
snapshotMaxElements |
number | 60 |
Max snapshot elements before truncation |
browser-electron |
contentMaxChars |
number | 100000 |
Default content character cap |
tool-browser |
timeoutMs |
number | 60000 |
Cooperative tool timeout (ms) |
tool-browser |
tabTools |
boolean | true |
Register tab-management tools (browser_list_tabs etc.) |
How it works
agent (browser_* tools)
→ ctx.browser (seam, dsh-builtin-browser/browser)
→ dsh-builtin-browser/browser-electron (provider)
→ ElectronBrowserViewHost (supplied by the host shell)
→ WebContentsView + webContents.debugger (CDP)
- Seam (
browserrow): provides thectx.browserservice — provider registration, session lifecycle, error codes — decoupled from any implementation. - Provider (
browser-electronrow): operates views through theElectronBrowserViewHostseam (create/destroy/show,sendCommand), implemented with real Electron objects by the shell. - Tools (
tool-browserrow): the 20 model-facingbrowser_*tools, maintaining one browser session per calling task (DSH session).
Self-hosted mode: without a desktop shell, the plugin spawns its own Electron child process (host-main.js) and drives it over loopback TCP JSON-RPC (window title dsh-browser). The child auto-restarts after a crash; screenshots prefer Electron's native capturePage (CDP capture can hang with multiple views in the window); the plugin automatically picks the newest Electron in the environment (33.x has a compositor defect; ≥ 40 recommended).
Electron lookup order: ① require('electron') (peer dependency) → ② ELECTRON_PATH (explicit override) → ③ the newest among DSH install anchors and pnpm virtual stores. A clear error tells you when none is found.
Division of labor with the desktop shell
The browser's visible view, the browser column layout, and the column-to-view alignment belong to the host shell (e.g. dsh's apps/desktop), not this plugin. This plugin consumes the shell-provided electronViewHost and owns the seam, provider, and tools. Without a shell the plugin self-hosts and everything still works.
Requirements
- DeepSeek Harness (dsh) with the
webprofile - Electron runtime (optional peer dependency): the desktop shell carries it; on plain
dsh webthe plugin locates an Electron binary automatically (see above; ≥ 40 recommended)
Verified versions
| Component | Version |
|---|---|
| DeepSeek Harness (dsh) | 0.1.0-rc.5 |
| Electron | 43.4.0 (≥ 40 recommended; 33.x has a compositor defect) |
| Node.js | 22.20.0 |
| dsh-builtin-browser | 0.1.11 |
| OS | Windows 10 (10.0.26200) |
The plugin declares
electron >= 30; it has only been verified on Windows (macOS/Linux untested, not yet promised).
Known limitations
- Screenshots are PNG-only (CDP JPEG hangs on Electron 43); JPEG awaits a non-CDP conversion path.
- Self-hosted captures prefer Electron's native
capturePage(CDPcaptureScreenshotcan hang with multiple views in the window); the target tab is raised before capturing. fullPagecapture is flaky under software compositing on some hosts.- CAPTCHA cannot be solved automatically: snapshots flag detected challenges; ask the human to complete it in the shared window instead of retrying.
- Private mode (
privateMode) is not implemented: it needs Electron session partitioning, which is host-layer territory; this plugin does not promise it. browser_downloadfetches in the page context (keeps logins) and is subject to same-origin/CORS constraints; single files are capped at 256 MB.- The
browser_authcookie round-trip does not preservehostOnly/sameSite(host-only cookies come back as domain cookies); it is available on the self-hosted browser only. - After a self-hosted child crash the browser host restarts automatically, but sessions opened before the crash are gone — call
browser_reset_sessionto rebuild. - This plugin contains no browser-column UI — that is host-shell territory; do not treat "browser column" as a plugin feature.
Development
# Type-check + build (lib/)
pnpm run build
# Functional tests: start a local page server + Electron probe (see repo test scripts)
Code layout:
| Directory | Responsibility |
|---|---|
src/browser/ |
The ctx.browser seam and all request/result types |
src/browser-electron/ |
Electron CDP provider, self-hosted child (host-main.ts), RPC layer |
src/tool-browser/ |
Model-facing browser_* tools |
src/types/ |
Electron ambient types (shim; no hard electron type dependency) |
Acknowledgements
Special thanks to the DeepSeek Harness repository and the DeepSeek AI team: the seam, the tool runtime, and the plugin system this plugin builds on all come from that project.
Thanks as well to Cordis for the plugin foundation, and to everyone in the community who discussed, tested, gave feedback, and built plugins.
License
MIT License, see LICENSE.
This project is a community plugin for DeepSeek Harness, not an official DeepSeek product.
Links
More in this category
liustack/modlens★ 1963
Vision bridge for text-only models: paste an image, get structured JSON evidence (OCR, layout, semantics).
Anionex/dsh-vision-toolkit★ 440
Vision tasks for text-only models: intent-aware image Q&A, long-screenshot OCR, UI reproduction, grounding, and pixel diff.
superdesigndev/treg★ 419
Tool catalog for agents: search ~2,600 external endpoints (SEO and SERP, backlinks, social, people and company enrichment, ad libraries, scraping) by the task you want done, read each one's parameters and per-call price, then call it with the credential injected server-side. Ships the skill plus an MCP row that stays disabled until TREG_TOKEN is set.
Lum1104/dsh-browser★ 167
Chrome sidebar extension that lets DSH operate your browser directly, no vision capabilities required.
ysr666/dsh-vision-router★ 155
Free vision for text-only agents: built-in keyless vision chain plus pixel tools (Q&A, grounding, crop, pixel diff, colors, OCR, SVG trace, cutout, screenshots); paste an image to use it.
zhaoolee/notes★ 141
Export DSH conversations as Smartisan Notes-style PNGs, or create and update Markdown notes in a configured account-scoped workspace.