Agent preset
dsh-browser-pilot
Browser automation tools for the DeepSeek Harness (DSH) agent - a self-contained Cordis agent-preset plugin (Playwright).
- Source
- momo-gen
- stars
- 1 stars
- License
- MIT
- Updated
- Updated 5 days ago
Readme
# dsh-browser-pilot
> Browser automation for the [DeepSeek Harness](https://github.com/deepseek-ai/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](https://playwright.dev/).
[](LICENSE)
[](package.json)
[](package.json)
๐ [ไธญๆๆๆกฃ](README.zh.md) ยท 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](#security-model) and [`SECURITY.md`](SECURITY.md).
## Demo
A DSH agent driving the browser end-to-end โ `browser_navigate` โ `browser_type` โ `browser_click`:

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

## 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
| Layer | Choice | Notes |
| --- | --- | --- |
| Language | TypeScript 5 (strict) โ ES2022 ESM | type-safe, compiled with `tsc` |
| Runtime | Node.js โฅ 18 | `"type": "module"` |
| Engine | Playwright (Chromium / Firefox / WebKit) | the only runtime dependency |
| Host integration | Cordis plugin (`apply(ctx, config)`), registered via `ctx.tools.register` | no `isolate` realm needed โ publishes no service |
| Distribution | DSH agent preset (a directory with `agent.cordis.yml` + `preset.yml`) | referenced by relative path `./dist/index.js` |
| Tests | `node:test` + `node:assert` (built-in) | unit (guards) + integration (real Chromium) |
| Build | `tsc`, no bundler | output into `dist/` (built, not committed) |
| CI | GitHub Actions | build + test + audit |
| License | MIT | |
## Quick start
### 1. Install
Clone this repository into your DSH user preset root (the directory name becomes the preset id):
```powershell
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`:
>
> ```powershell
> $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
| Tool | Purpose |
| --- | --- |
| `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`:
```yaml
- 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-list** โ `browser_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 sandbox** โ `browser_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`](SECURITY.md).
## Development
```powershell
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](LICENSE)
Install
# Copy the composition to $DSH_HOME/.agent-presets/dsh-browser-pilot/agent.cordis.yml
Profile: web
With the hub plugin installed, ask your agent to install it by name โ it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install momo-gen-dsh-browser-pilot from the hub