Back to home

momo-gen

dsh-browser-pilot

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

Stars
1
Language
TypeScript
Created
Aug 14, 2026
Updated
Aug 14, 2026

Introduction

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