momo-gen / dsh-browser-pilot

Listed

Browser automation tools for the DeepSeek Harness (DSH) agent - a self-contained Cordis agent-preset plugin (Playwright).

mainTool View source

Installation

npx -y @deepseek-ai/dsh plugin --profile web add github:momo-gen/dsh-browser-pilot

This installation command is an unverified starting point generated from the GitHub repository address.

README

Maintainer-authored documentation snapshot.

View on GitHub ↗
Commit be7d9beSynced Aug 18, 2026

dsh-browser-pilot

Browser automation for the DeepSeek Harness (DSH) agent — a self-contained Cordis agent-preset plugin that gives the agent safe, guard-railed control of a real web browser (navigate, click, type, screenshot, extract) via Playwright.

license node playwright

🌏 中文文档 · English

It is designed to be published and shared: clone this repository into your DSH user preset root, install one dependency, and your next session gains a full set of browser_* tools on top of the standard coding agent.

The agent can operate the browser, but only through explicit safety rails — URL scheme allow-listing, output-path sandboxing, and no host-side code execution. See Security model and SECURITY.md.

Demo

A DSH agent driving the browser end-to-end — browser_navigatebrowser_typebrowser_click:

Browser Pilot demo

The result of that interaction (the agent filled the input, clicked, and captured the page):

Browser Pilot screenshot

Features

  • 14 model tools exposing the full browser surface: browser_navigate, browser_snapshot, browser_text, browser_html, browser_click, browser_type, browser_press, browser_select, browser_screenshot, browser_pdf, browser_wait, browser_evaluate, browser_status, browser_close.
  • Cross-browser: Chromium, Firefox, and WebKit (Chromium by default).
  • Safe by default: javascript:/data:/file:/chrome:/about:config navigation is rejected; screenshots and PDFs are confined to the session workspace; arbitrary page JavaScript (browser_evaluate) is off until you opt in.
  • Zero harness-internal dependencies: the plugin imports only playwright and Node built-ins, so it loads from a relative path inside the preset without needing the harness's own @deepseek-ai/* packages.
  • Lifecycle-correct: the browser is a lazy singleton owned by the plugin and is closed when the preset unmounts.

Tech stack

LayerChoiceNotes
LanguageTypeScript 5 (strict) → ES2022 ESMtype-safe, compiled with tsc
RuntimeNode.js ≥ 18"type": "module"
EnginePlaywright (Chromium / Firefox / WebKit)the only runtime dependency
Host integrationCordis plugin (apply(ctx, config)), registered via ctx.tools.registerno isolate realm needed — publishes no service
DistributionDSH agent preset (a directory with agent.cordis.yml + preset.yml)referenced by relative path ./dist/index.js
Testsnode:test + node:assert (built-in)unit (guards) + integration (real Chromium)
Buildtsc, no bundleroutput into dist/ (built, not committed)
CIGitHub Actionsbuild + test + audit
LicenseMIT

Quick start

1. Install

Clone this repository into your DSH user preset root (the directory name becomes the preset id):

git clone https://github.com/<you>/dsh-browser-pilot `
  "$env:DSH_HOME/.agent-presets/browser-pilot"
cd "$env:DSH_HOME/.agent-presets/browser-pilot"
npm install
npm run build
npm run install-browsers   # downloads Chromium once (shared cache)

$env:DSH_HOME defaults to ~/.dsh (on Windows: C:\Users\<you>\.dsh).

国内用户建议用镜像 (China users: use a mirror) — downloading the browser via the npmmirror CDN is an order of magnitude faster than the official CDN (verified). Set this before npm run install-browsers:

$env:PLAYWRIGHT_DOWNLOAD_HOST='https://cdn.npmmirror.com/binaries/playwright'

2. Start a session on the preset

Create a new DSH session and pick the browser-pilot preset (or set it as your default in the preset picker). The agent now has the browser_* tools.

3. Try it

Ask the agent, for example:

Open https://example.com, tell me the page title, then take a screenshot.

The agent will call browser_navigate, browser_snapshot, and browser_screenshot in sequence.

Tool reference

ToolPurpose
browser_navigate(url, waitUntil?)Open a URL (scheme-guarded). Returns URL + title.
browser_snapshot(maxChars?)URL + title + visible body text (truncated).
browser_text(selector)innerText of the first element matching a CSS selector.
browser_html()Full page HTML (truncated).
browser_click(selector, timeout?)Click the first matching element.
browser_type(selector, text)Fill an input/textarea (replaces current value).
browser_press(selector, key)Press a key (Enter, Tab, Escape, …) on an element.
browser_select(selector, value)Select a <select> option.
browser_screenshot(filename?, fullPage?)Save a PNG/JPG/WebP into the workspace; returns the path.
browser_pdf(filename?)Save the page as PDF (headless Chromium).
browser_wait(ms)Wait a number of milliseconds.
browser_evaluate(expression)Run a JS expression in the page (opt-in).
browser_status()Whether the browser is running, plus URL + title.
browser_close()Close the browser; a later call relaunches it.

Configuration

Configuration lives in the preset row in agent.cordis.yml:

- id: tool-browser
  name: ./dist/index.js
  config:
    browser: chromium        # chromium | firefox | webkit
    headless: true           # set false for a visible window
    timeout: 30000           # per-action timeout in ms
    allowEvaluate: false     # enable browser_evaluate (runs JS in the page)
    allowFile: false         # allow file:// navigation (reads local files)
    allowedSchemes:          # extra schemes beyond http/https
      - http:
      - https:

All keys are optional and default to the safe values shown above.

Security model

The plugin is "arbitrary browser operation" with guard rails, not bare-metal access. Three invariants, all covered by unit tests:

  1. Scheme allow-listbrowser_navigate rejects javascript:, data:, file: (unless opted in), chrome:, vbscript:, and every about: URL except the inert about:blank. A bare host is treated as https://.
  2. Output-path sandboxbrowser_screenshot/browser_pdf resolve the filename against the session workspace and reject .. traversal, absolute escape, NUL bytes, and disallowed extensions.
  3. No host execution — the plugin never spawns a shell or evaluates code in the Node host. browser_evaluate runs only in the page context and only when allowEvaluate: true.

Full threat model and residual risks: SECURITY.md.

Development

npm install
npm run build          # compile src/ → dist/
npm test               # unit + integration tests (needs `npm run install-browsers` first)
npm run typecheck      # strict type check only
npm run audit          # dependency vulnerability scan

The integration tests spin up a local HTTP server and drive a real headless Chromium against it — no external network required.

Repository layout

├── agent.cordis.yml   # full preset composition (standard + this plugin row)
├── preset.yml         # preset display metadata
├── src/               # the plugin (guard.ts, browser.ts, index.ts)
├── test/              # unit + integration tests
├── dist/              # compiled plugin (loaded via ./dist/index.js; built, not committed)
├── .github/           # CI workflow
├── package.json       # build/test scripts; playwright dependency
├── SECURITY.md        # threat model and disclosure
├── CONTRIBUTING.md    # contribution guide
├── CHANGELOG.md       # release history
├── README.zh.md       # 中文文档
└── LICENSE            # MIT

License

MIT

Project files and signals

Shown items are public repository signals detected in the directory snapshot.

TestsDetected
Security policyDetected
Contributing guideDetected
DocumentationDetected

Repository information

Language
TypeScript
License
MIT
Last updated
Aug 14, 2026, 6:35 AM

Install deliberately

Review source code, permissions, lifecycle hooks, dependencies and network access. Test untrusted plugins in an isolated environment.