dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DSH plugin — free OpenCode Zen models for DeepSeek Harness (DSH). No API key needed. 在 DSH 中使用 OpenCode Zen 免费模型,无需 API key
Free OpenCode Zen models, natively inside DSH (DeepSeek Harness).
No API key. No registration. No extra process.
English | 简体中文
dsh-opencode-free registers a native DSH LlmAdapter that streams directly from
OpenCode Zen's anonymous free lane — the same
models OpenCode's own CLI uses without an account, served to your DSH model
picker as a regular provider called dsh-opencode-free.
Requests leave your machine looking exactly like traffic from the OpenCode CLI (same user agent, same correlation headers), and the model catalog stays fresh through a three-tier fallback chain. There is nothing to log into and nothing to host.
Upgrading from
opencode2dsh? This project was renamed. The plugin now installs as@dsh-opencode-free/dsh-pluginwith the provider, settings entry and data directory all under the new name. Your saved IP-pool settings and the old~/.opencode2dshcache are copied once on first start — see Renamed from opencode2dsh.
legacy/)muse-spark-* models expose only upstream-supported effort levels, and no selection keeps the provider defaultimage in modalities.input, and refused for the ones that declare text only; models.dev being silent falls back to the live-verified vision familyInstalls from a prebuilt release, so no build step and no toolchain is needed.
dsh plugin --profile web add https://github.com/ddldxiacan/dsh-opencode-free/releases/download/v0.4.3/dsh-opencode-free-dsh-plugin-0.4.3.tgz --config.strict-dep-builds=false
That is the whole install — one command, exit code 0. Then restart DSH and pick a model from the dsh-opencode-free group in the model selector.
Requirements: DSH (DeepSeek Harness) 0.1.7 or newer with a web profile, Node.js
≥ 20 (already present if DSH runs), and outbound HTTPS to opencode.ai and
models.dev.
@earendil-works/pi-ai transitively pulls in @google/genai and protobufjs,
which ship build scripts. pnpm blocks dependency build scripts by default, and
in strict mode that disagreement is a hard failure:
Error: ERR_PNPM_IGNORED_BUILDS
× adding a new package
╰─▶ Ignored build scripts: @google/genai@1.52.0, protobufjs@7.6.6
Those scripts are not needed at runtime (upstream ships both as false), so
--config.strict-dep-builds=false tells that single pnpm run to report the
skip as a warning and carry on. Verified: exit 0, no script executed, plugin
registered as a bundle.
Equivalents, if you prefer to be explicit rather than relax the check for one
run — both also work and record allowBuilds: {'@google/genai': false, protobufjs: false} in the profile:
# deny the two scripts explicitly
dsh plugin --profile web add <same-url> --allow-build='!@google/genai' --allow-build='!protobufjs'
add URL and hit that errorDo not simply retry — first remove. This is worse than it looks: pnpm has
already written the dependency into the profile's package.json when it
errors, and DSH registers a package as a profile bundle only when the run
exits 0 and the package counts as new. A plain retry therefore prints
Already up to date and exits 0 while dsh.profile.bundles never gains the
plugin — it sits in node_modules, never loads, and no model appears. Nothing
in the output says so.
Recover with an explicit remove + add:
dsh plugin --profile web remove @dsh-opencode-free/dsh-plugin
dsh plugin --profile web add https://github.com/ddldxiacan/dsh-opencode-free/releases/download/v0.4.3/dsh-opencode-free-dsh-plugin-0.4.3.tgz --config.strict-dep-builds=false
Verify it really registered: @dsh-opencode-free/dsh-plugin must appear
under dsh.profile.bundles in the profile's package.json, not only under
dependencies.
Settings → Plugins → Install, then paste the tarball URL:
https://github.com/ddldxiacan/dsh-opencode-free/releases/download/v0.4.3/dsh-opencode-free-dsh-plugin-0.4.3.tgz
The first attempt always fails once. That is by design, not a bug:
@google/genai and protobufjs;This path does not hit the silent-retry trap described below: after every
failed run the page restores package.json and pnpm-lock.yaml, so the retry
still counts as a new dependency and registers as a profile bundle. Verified
end to end on a real profile: fail → allow → retry succeeded, and
dsh.profile.bundles gained @dsh-opencode-free/dsh-plugin at 0.4.3.
If you close that dialog and use the Install button again later, it fails again and re-opens the same approval section — it will not pretend to have succeeded. Click "Allow these scripts and retry" and it goes through.
From GitHub directly (no registry involved):
dsh plugin --profile web add github:ddldxiacan/dsh-opencode-free --config.strict-dep-builds=false
This works because the repository root is the installable plugin: it carries
the dsh manifest, and the built output is committed under
packages/plugin/lib/. A git install cannot run a build — pnpm blocks prepare
scripts for git dependencies — so shipping the build is what makes this path
work. Pinning a tag is recommended for stability:
dsh plugin --profile web add github:ddldxiacan/dsh-opencode-free#v0.4.3 --config.strict-dep-builds=false
From npm (once the package is published):
dsh plugin --profile web add @dsh-opencode-free/dsh-plugin
Verify: restart dsh web, open the model picker, and pick a model from
the dsh-opencode-free group.
Pick the source you installed from; each updates in place.
Release tarball. Use the tag-scoped asset, not the version-free one:
# replace 0.4.2 with the release you are moving to
dsh plugin --profile web add https://github.com/ddldxiacan/dsh-opencode-free/releases/download/v0.4.2/dsh-opencode-free-dsh-plugin-0.4.2.tgz
The version-free releases/latest/download/... URL does not update an
existing install: pnpm resolved it once and pinned the URL plus its integrity
hash in pnpm-lock.yaml, so re-adding it is a no-op ("Lockfile is up to date,
resolution step is skipped") — even with --force, pnpm update,
pnpm install --force, or a deleted node_modules. Only a URL that differs per
release re-resolves. If you are stuck on an older build that predates the
versioned asset, do the one-time move with an explicit remove + add (or the
versioned URL, which works even then):
dsh plugin --profile web remove @dsh-opencode-free/dsh-plugin
dsh plugin --profile web add https://github.com/ddldxiacan/dsh-opencode-free/releases/latest/download/dsh-opencode-free-dsh-plugin.tgz
git install: follow master (a git spec re-resolves each time):
dsh plugin --profile web add github:ddldxiacan/dsh-opencode-free --config.strict-dep-builds=false
npm install:
dsh plugin --profile web add @dsh-opencode-free/dsh-plugin@latest
Then restart DSH. To confirm the new version landed, compare the profile's
node_modules/<pkg>/package.json with the release you expected, and check the
health snapshot at ~/.dsh-opencode-free/adapter-status.json.
If an update ever leaves the plugin installed but not loaded, it is the
ERR_PNPM_IGNORED_BUILDS trap described under Install: remove and
re-add, so the package counts as new and DSH registers it as a bundle.
Defaults work out of the box. Override via the profile's cordis.patch.yml.
The name must be the package you installed as: dsh-opencode-free for a git
install, @dsh-opencode-free/dsh-plugin for the tarball or npm.
- id: dsh-opencode-free
name: dsh-opencode-free # or '@dsh-opencode-free/dsh-plugin'
config:
mode: adapter # adapter (default) | sidecar
providerId: dsh-opencode-free
refreshSeconds: 300 # catalog refresh cadence
| Option | Default | Description |
|---|---|---|
mode | adapter | adapter: native LlmAdapter streaming straight from Zen. sidecar: legacy local-agent mode, not bundled — build the agent from legacy/agent and pass agentPath. |
providerId | dsh-opencode-free | Provider name shown in DSH. |
refreshSeconds | 300 | Live catalog refresh interval. Pricing metadata refreshes every 24 h. |
agentPath | auto-resolved | Sidecar only: path to the agent binary. |
agentArgs | — | Sidecar only: extra CLI args for the agent. |
restartDelayMs / restartMaxDelayMs / maxConsecutiveCrashes | 1000 / 60000 / 5 | Sidecar only: restart backoff and circuit breaker. |
firstEventMs / bodyIdleMs / responsesBodyIdleMs | 30000 / 120000 / 300000 | Adapter only, plugin 0.3.7+: stream-liveness watchdogs, in ms (integers from 1 to 600000). Time to the first stream event, mid-response body silence, and the body-idle floor for Responses models (muse-spark-*). Increase firstEventMs for slow cold starts. Unset keeps the defaults; restart DSH after editing. |
DSH session
│ harness chunks (block-start / text-delta / usage / finish …)
▼
ZenAdapter (registered LlmAdapter)
│ pi-ai openai-completions stream (chat models)
│ pi-ai openai-responses stream (`muse-spark-*`, Responses-only on Zen)
▼
https://opencode.ai/zen/v1 ← Authorization: Bearer public
with CLI-identical headers:
user-agent: opencode/…
x-opencode-client, x-opencode-session, x-session-affinity,
X-Session-Id, x-opencode-request, x-opencode-project
GET /v1/models; S2: models.dev
pricing metadata decides "free"; S3: a compile-time verified static list.
A disk cache (~7-day TTL) covers upstream outages.mode: sidecar, legacy) — spawns a local Go agent (a
single-tenant port of opencode2api)
on 127.0.0.1:<random>, token-authenticated, and registers a standard
llm-pi-ai route. Not part of the published package; build it from
legacy/agent (go build ./cmd/agent) and point agentPath at the binary.The plugin writes a health snapshot after every refresh round:
~/.dsh-opencode-free/adapter-status.json
{
"status": "ready",
"total": 64,
"exposed": 9,
"lastError": "",
"writtenAt": "2026-08-29T07:01:54.915Z"
}
| Symptom | Likely cause & fix |
|---|---|
403 FreeTierError / "OpenCode's free tier can only be used from within OpenCode" | The upstream restricts free-tier clients. The plugin preserves the explanation instead of reporting an invalid API key. Use the supported OpenCode client or an official API service. |
Boot screen shows Failed to load plugins … list slot "plugins.item" requires options.id, or the IP 池 entry has no configuration page | Your DSH predates the 0.1.7 Plugins page contract. Upgrade DSH to 0.1.7 (latest recommended). On 0.1.6 and older the page never mounts (it is gated on configForms.whileServed) — model routing is unaffected. |
DSH 0.1.7/0.2 cannot start after plugin installation (pending … settingsScope) | Upgrade the plugin to 0.3.5. On DSH 0.2, configure IP pooling through the installed dsh-opencode-free row on the Plugins page. |
| Only 3 models | Startup fetch raced your network; retries land within ~1 min. Check adapter-status.json for lastError. |
lastError: "fetch failed" persisting | Outbound HTTPS to opencode.ai blocked; check proxy/VPN rules. |
Rate-limit errors in chat (429 … Endpoint is unavailable) | The anonymous lane is quota-per-IP and free models are contended. Since the fix for #51 the plugin's provider retry policy rides out 429 bursts silently (8 retries, ~1s→20s backoff, ≈90s worst case per step) instead of surfacing them; when contention still wins, lower the reasoning effort, pick a less contended -free model, or enable IP pooling (multi-exit rotation) on the plugin settings page. |
| Output limit reached after reasoning with no answer | Plugin 0.3.6 retries once with thinking Off when the model supports it. Any answer text or tool-call event prevents replay. The retry preserves the original output cap and may still fail; both requests' usage is counted. Models without Off, including Muse, require a manual change of settings or model. |
Muse reports REGION_BLOCKED / "This model is not available in your country" | Zen has rejected the current network region for this model. Plugin 0.3.5 preserves that explanation; older versions mislabeled the same 403 as an invalid API key. The anonymous lane does not need a personal key. Use a model available in your region. |
Connection error to 127.0.0.1:* | A stale sidecar route shadows the adapter; plugin ≥ 0.2.1 removes it at startup. |
Install fails with ERR_PNPM_IGNORED_BUILDS | A transitive dependency of pi-ai (@google/genai, protobufjs) has build scripts that are not needed at runtime. Add --config.strict-dep-builds=false to the install command, or click Allow these scripts and retry in the Web UI. Do not simply re-run a failed bare add — see Install. |
This project used to be called opencode2dsh. The rename is complete: the npm
package, the DSH provider id, the settings entry and the data directory all use
the new name dsh-opencode-free.
Upgrading is automatic. On the first start after the update the plugin copies your state from the old name, once, without deleting anything:
| State | Old location | New location |
|---|---|---|
| Cache, health snapshot, sidecar token | ~/.opencode2dsh/ | ~/.dsh-opencode-free/ |
| Saved IP-pool settings | opencode2dsh: section of ~/.dsh/settings.yaml | dsh-opencode-free: section |
Two things the migration deliberately does not do:
After upgrading you will see the provider as dsh-opencode-free in the model
picker. Saved IP-pool settings appear on the second start: the Loader
resolves the entry's volatile ipPool value while composing a boot, so a copy
made during that boot is read on the next one. The cache and health files take
effect immediately. A deployment that cut over before this rename existed may
still list a opencode2dsh entry under DSH's Settings → Plugins; remove that
stale entry (an orphan opencode2dsh provider route left by a sidecar install is
swept automatically at startup).
If you prefer to start clean rather than migrate, delete ~/.opencode2dsh/ and
the opencode2dsh: section of ~/.dsh/settings.yaml before upgrading; the
plugin then starts with defaults.
public; nothing is stored, nothing telemetry.lib/ only; no build scripts run from dependencies.opencode.ai / models.dev.git clone https://github.com/ddldxiacan/dsh-opencode-free.git
cd dsh-opencode-free/packages/plugin
pnpm install
pnpm typecheck && pnpm test
pnpm build # bundle to lib/
The legacy Go sidecar lives in legacy/agent (go test ./...). Architecture
notes and the porting record live in docs/.
Releasing: pnpm pack in packages/plugin (prepack builds and syncs docs).
legacy/agent is a port of its anonymous-lane implementation, and the
catalog fallback chain and request-disguise details are derived from it.
This project stands on its shoulders.LinuxDo — 新的理想型社区 / a new ideal community
MIT © 2026 ddldxiacan, based on opencode2dsh © FishBottle7