deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
RSLN-creator/dsh-web-bridge
Use your logged-in web AI (DeepSeek, GLM, Kimi, Qwen, Doubao...) as model providers in DeepSeek Harness. Web models emit tool calls, DSH runs them under its native permission system, and results return to the same web session. No API keys.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:RSLN-creator/dsh-web-bridge
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
English · 中文
Use your logged-in web AI — DeepSeek, GLM (Z.ai), Kimi, Qwen, Doubao — as model providers inside DeepSeek Harness. Web models emit tool calls, DSH executes them under its native permission and approval system, and the results go back into the same web session.
No API keys. It drives the site through your own browser login.
dsh plugin --profile web add dsh-webcode-bridge
Most "web model" integrations are fragile in the same three ways: they scrape HTML, they lose the conversation when the page reloads, and they bypass the host's tool permissions. This plugin is built the other way around:
| Concern | How it is handled |
|---|---|
| Tool permissions | The web model only proposes calls. DSH runs them with its own permission and approval system — the bridge cannot bypass it. |
| Session continuity | A per-session cursor keeps the web conversation alive across turns, across restarts, and after history rewrites. When the web session is lost the bridge replays the full first turn instead of silently starting over. |
| Long prompts | Over-threshold bodies are delivered as a file attachment, bypassing the composer's write-stall and truncation limits, with an automatic fallback to plain text if any step fails. |
| Rate limits | A configurable send gap (global and per site) plus automatic backoff-and-retry on the site's own rate-limit response. |
json code block,GET /__webcode/status, so "did it actually work" is answerable from the UI instead of from logs.| Node.js | 22.13 or newer |
| DeepSeek Harness | 0.1.0-rc.6 or newer |
| Browser | None to install — the plugin ships its own Chromium (Playwright). A system browser is used only as a fallback. |
dsh plugin --profile web add dsh-webcode-bridge
Download dsh-webcode-bridge-<version>.tgz from
Releases, then:
dsh plugin --profile web add C:\path\to\dsh-webcode-bridge-<version>.tgz
cd package/dsh-webcode-bridge
pnpm install # do NOT add --frozen-lockfile, see doc/ci-cd.md
pnpm pack # produces dsh-webcode-bridge-<version>.tgz
Restart
dsh webafter installing. Installing only swaps files on disk; the running process still has the old code loaded. This is the single most common "it does not work" report.
dsh web, then open http://127.0.0.1:3080.@deepseek-ai/dsh-client-ui-sidebar-right tabs; no third-party sidebar plugin involved). Ask a
question there and the web model runs with local tools.Tool calls produced by the web model run on your machine under DSH's normal permission prompts, and the results are returned to the same web conversation.
All settings live in Settings → Web Bridge and can also be edited through the standalone settings page. Settings are stored per profile.
| Setting | What it does |
|---|---|
| Default model | Which model a new session starts on. |
| Global instruction | A paragraph appended to the first message of every new web session. |
| Send gap | Minimum wait between two sends to the same site. Default basis is since last send (protects against send-rate limiting); since last reply finished protects against talking too fast. |
| Prompt delivery | Attachment (default): over-threshold bodies are uploaded as a file. Plain text: always write into the composer (the pre-0.16 behaviour). |
Each site gets its own tab where you can override, independently of the global value:
Follow global clears the override.Follow global / Attachment / Plain text.The fallback chain is always site override → global → built-in default, and clearing an override deletes the key rather than writing a third value — so "never configured" and "configured to follow global" stay distinguishable in the settings file.
| Variable | Effect |
|---|---|
WEBCODE_PROMPT_STORE_DIR |
Where the per-site prompt files are written. off disables writing them entirely. Default ~/.dsh/webcode. |
DeepSeek is the primary target and holds up over long sessions. GLM works but is unstable.
| Site | Status |
|---|---|
DeepSeek deepseek:deepseek |
Primary. Validated over long multi-turn tool loops on a real browser session, with auto-continue, cursor persistence and recovery from Harness history after a restart. |
GLM glm:glm-5.3 / glm-5.3-flash |
Usable but unstable. The end-to-end loop passes on a real session — a random secret that exists only in the tool result is echoed back verbatim. |
| Kimi / Qwen / Doubao / Z.ai | Wired up, not validated over long runs. Availability depends on your login. |
| Claude | Region-restricted; the site itself says so. |
| ChatGPT / Grok / Gemini | Not reachable from our network (502 plus an explanatory page). |
What "unstable" means for GLM, concretely:
Read it as: DeepSeek is the one to run all day; GLM is a good second opinion. When GLM fails, retry — attributable failures surface as coded messages rather than silent degradation.
A few design notes worth knowing before you read the source.
Each site is served from http://<siteId>.localhost:8931/, so the pathname the site sees matches its
real site and SPA routers and root-relative assets work unchanged. The exception is DeepSeek, which
is always mounted at the relay root — it validates the hostname, and a subdomain gives a blank
Unknown hostname page. *.localhost resolves to loopback, so the exposure surface is unchanged.
Sites often load scripts and styles from a different origin with crossorigin, and that origin's
Access-Control-Allow-Origin may be an illegal wildcard (https://*.deepseek.com), which browsers
refuse outright. lib/mirror.js therefore rewrites those URLs to same-origin /__static/<host>/…,
strips integrity and crossorigin, rewrites the runtime fetch/XHR calls that target those
origins, and installs an idempotent runtime hook to catch lazily-built chunk URLs.
Order matters: rewrite the site HTML first, then inject the bootstrap. Reversed, the constants
inside the bootstrap get rewritten too and the runtime comparison never matches. test/mirror.test.mjs
locks this in.
Bodies over the threshold go up as an attached .md file instead of being typed into the composer,
which sidesteps two measured failure modes: PROMPT_WRITE_STALLED (the composer stops growing while
being written) and PROMPT_TRUNCATED (the site accepts only half). Any failure on that path
falls back to plain text — delivery is an implementation detail, "the message gets sent" is the
contract.
Two sites (DeepSeek, Kimi) have their own lower thresholds because their composers were measured to truncate earlier than the global default. Sites where upload is confirmed to not be read are downgraded at runtime and remembered.
Token estimates use three measured densities (0.19.3 onward) — CJK 0.75, prose ASCII 0.30,
other ASCII (digits, punctuation, source) 0.70 — plus a 10% margin. The rule is that the estimate
never understates; the single source of truth is TOKEN_DENSITY in lib/metrics.js. Speed
figures are measured from the site's own SSE stream and are kept separate from the estimate.
| Symptom | Check |
|---|---|
| Nothing appears after installing | Restart dsh web. Then check that the plugin is listed for the web profile. |
| A site shows "not logged in" but you are logged in | The bridge uses its own browser profile. Sign in through Settings → Web Bridge → Log in, not in your daily browser. |
| Right sidebar is blank for one site | That site's page failed to load. The panel shows a per-site explanation with a retry button rather than raw JSON. |
| "Import login state from this machine" fails | Expected on Edge 128+: cookies are app-bound encrypted (v20), so copying a profile cannot decrypt them. Use Log in instead. |
| Long prompt was typed instead of attached | Check the Prompt delivery setting for that site — a per-site override may be set to Plain text. |
GET /__webcode/status exposes the live readouts (last delivery, transport mode, session slot,
rate-limit retries, fresh-conversation reasons) — that is the first place to look when the UI is
ambiguous.
cd package/dsh-webcode-bridge
pnpm test # regression, parsing and Harness adapter contracts
pnpm lint:comments # comment discipline gate
pnpm ci:local # full local CI
Useful single-file runs:
node test/glm-session-replay.test.mjs # replay a real GLM session shape offline
node test-mock/real-mirror-matrix.mjs # right-sidebar acceptance matrix, 10 sites
node test-mock/run-real-longrun.mjs # long real-browser tool loop
node scripts/verify-pack.mjs # tarball vs working tree, byte for byte
| Document | Contents |
|---|---|
| docs index | The authoritative entry point for repository documentation. |
| progress ledger | Where the project currently stands and what is next. |
| long-term issues | Known defects and why they are not fixed yet. |
| permissions and boundaries | Dependencies, permissions, external services and failure boundaries. |
| settings copy | What every settings label means, and the full explanation behind it. |
| CI/CD | Build, release and rollback. |
MIT — full text in LICENSE. Third-party notices are kept in
permissions and boundaries rather than in the license body, so
GitHub's license detection reports MIT instead of NOASSERTION.
SSE decoding protocol references the MIT project
three-water666/webcode.
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。