
Security News
vlt 1.5.0 Adds Agent Skills Management
vlt 1.5.0 links skills from JavaScript dependencies to coding agents, with lockfile versioning and Socket data to filter out known malicious packages.
@karoc/dsh-smoothly-opencode-session
Advanced tools
Smoothly OpenCode Session (Smoothly OCS) — 思磨力 OpenCode 会话头: external DeepSeek Harness host plugin that attaches the OpenCode-required x-opencode-session header to model calls routed to OpenCode / OpenCode Go provider routes (stable per-conversation id; f
思磨力 OpenCode 会话头 — an external DeepSeek Harness
(DSH) host plugin that attaches the OpenCode-required x-opencode-session
request header to model calls routed to OpenCode / OpenCode Go provider
routes, using a stable per-conversation id.
Since 2026-09-05 OpenCode's relay rejects any inference request that lacks
this header (400 MissingSessionID); the value is what pins a conversation to
one upstream backend and keeps OpenCode's prompt cache warm across its turns
(tracked upstream in deepseek-harness discussion #5495).
x-opencode-session to requests that
are routed to an OpenCode(Go) provider on an allowed host (the host gate
decides, so no provider list has to be configured).x-deepseek-harness-session-id).https://opencode.ai),
as are requests that already carry the header and calls without a session id.
A provider is covered through its target host, not through its name, so
restricting injection to particular routes takes an explicit providers
list. See hosts and providers.The plugin listens on the llm/stream waterfall — a documented DSH
extension seam ("Waterfall around every streaming model call"). LOOP-built
request options are deep-frozen (mutation throws), so the header cannot be
added by rewriting options; instead the plugin:
provider + sessionId off the waterfall options for each call;AsyncLocalStorage store;globalThis.fetch once, and while such a store is active merges
x-opencode-session: <value> onto the outgoing request (unless the request
already carries the header — an existing value always wins).Both registrations are fiber-scoped (ctx.on listener + ctx.effect
disposer), so stopping / updating / unloading the plugin restores the original
fetch and removes the listener.
There is no official seam for an external plugin to add per-request headers to
adapter requests (options are deep-frozen; provider headers config is static
and deployment-owned). The fetch shim is the only external-plugin mechanism
that can attach a per-conversation value. The correct long-term fix lives
in the provider adapter itself (pi-ai); this plugin is the stopgap until that
ships. See Notes / limitations.
The row's config (in the bundle's cordis.patch.yml, or overridden per
profile) is entirely optional — the code fills defaults for missing keys.
- insert:
- id: dsh-smoothly-opencode-session
name: '@karoc/dsh-smoothly-opencode-session'
config:
# providers: [opencode, opencode-go] # optional narrowing; unset = host gate decides
mode: session-id
debug: false
Optional narrowing — you normally need no configuration here. The
authoritative discriminator is the request HOST (see hosts): leave
providers unset and every provider whose target host passes the gate is
covered, so a custom route key (for example opencode-go-self) works without
being listed and cannot break silently when it is renamed. Set it only to
restrict injection to specific provider ROUTE KEYS (the pi-ai catalog ids
opencode / opencode-go are then just two ordinary entries). Matching uses
the route key — a provider's display name (for example a UI label such as
"OC Go") is never visible here. When you do set a list, the plugin compares it
against the registered routes at the first model call and warns once about any
key no adapter registered (also written to debugFile when configured, since a
service deployment may not capture the console). The /ocgo command prints
the effective policy — gate, narrowing, mode, registered routes — with no client
UI involved.
The host gate: a request is only modified when its target host is allowed
(default ['https://opencode.ai'], subdomains included). Entries are host
(implicitly https) or scheme://host[:port]; a leading *. is ignored; IDN
entries normalize to punycode; unusable entries are reported in the startup log
instead of being ignored silently, and entries that are empty after trimming
count as not supplied — when no usable entry is left, the default rule above
applies. ['*'] disables the gate entirely — use it only for a mirror you
fully trust. If you reach OpenCode through a reverse proxy or a mirror, list
that host here (write the full scheme, and note that a bare host entry means
https) or the header will silently not be attached; the plugin warns once per
blocked provider/host pair.
session-id (default) — header value = the DSH session id of the model
call. Unique per conversation, stable across turns, compaction, retries and
restarts.uuid — a process-stable random UUID derived once per DSH session id
(opaque; resets when the process restarts).debug: true — log every streamed call that enters the injection flow
via ctx.logger (the dsh process console), and reveal raw values in
request-level records.debugFile: <absolute path> — append one JSON line per streamed call
(kind: "stream", with provider/model/session/value) and one per
injected or host-blocked request (kind: "inject" | "skip", appended
whenever the file is configured; debugRequests adds the console line, not
the file record). A configured-but-unregistered provider route appends one
kind: "diagnostic" record instead (see providers). The
stream-level record only means the call entered the injection flow; the
request-level records are what prove what was actually attached. The
stream-level record carries the raw session id and value (its 0.1.0 format,
kept for compatibility); only the request-level records are hashed by
default. The file is append-only (no rotation; an injected call writes two
records, the stream one and the request one) and written fire-and-forget, so
a short-lived process can lose its tail.debugRequests: true logs one line per request-level record at the real fetch
moment through ctx.logger (the dsh process console); the JSON record itself
is appended to debugFile when one is configured (see above). Its reason is
one of session / discovery / host-not-allowed / already-present. An
injected record carries
{"ts","kind","reason","host","provider","valueHash","valueLen"}; a skip
record describes the request without a fingerprint
(ts/kind/reason/host/provider, with host absent when the URL cannot
be parsed), and a discovery record has no provider (a bare discovery
request belongs to no route). Values are hashed by default: the value is
reduced to a 12-hex-character SHA-256 prefix, and the raw value appears only
when debug: true is set as well. (The separate stream-level record described
above keeps the raw session id — see its note.)
discoveryFallback: true (default off) attaches a process-stable UUID to
bare discovery requests that carry no session id: only GET requests whose
path ends in /models and whose host passes the gate. The Models page listing
works without this today; enable it only if your OpenCode endpoint starts
rejecting that listing.
To override configuration in a profile without editing this package, add a
patch entry with the same id to the profile's own cordis.patch.yml (it
replaces the whole config, so restate every key you need). The patch entry
form is id-targeted, not insert — see Install.
Compatibility: the earliest dsh release whose seams this plugin needs (llm/stream, GenerateOptions.sessionId, the commands service) is 0.1.0-rc.7 — that is the declared floor, derived from seam availability, not from a test pass on every release in between. It is declared as an optional peer dependency on @deepseek-ai/dsh-llm: ">=0.1.0-rc.7", which DSH evaluates against its own runtime version: a runtime outside the range is refused at load time — the plugin's layer is skipped and the exact dsh plugin allow-version remedy is printed. That evaluation itself only ships since dsh 0.1.7-rc.1, and every release that has it already satisfies this floor, so the declaration states the contract rather than enforcing it today; a dsh older than 0.1.7-rc.1 loads the plugin unchecked. The peer is peerDependenciesMeta.optional because the host supplies dsh-llm at runtime, so npm installs nothing extra. The range deliberately spells the prerelease (>=0.1.0-rc.7, not >=0.1.0): a released-version range does not match a prerelease runtime.
dsh plugin --profile web add @karoc/dsh-smoothly-opencode-session
Then fully restart your dsh profile (bundle layers are read at startup). The startup log shows:
[dsh-smoothly-opencode-session] active with mode session-id; provider narrowing: (none — the host gate decides)
[dsh-smoothly-opencode-session] host gate: https://opencode.ai
If you run DSH from a source checkout instead, load it as an overlay:
pnpm dsh web --patch ./cordis.patch.yml.
dsh plugin --profile web add git+https://github.com/karoc/dsh-smoothly-opencode-session.git
dsh plugin --profile web update @karoc/dsh-smoothly-opencode-session
Restart dsh web afterwards.
dsh plugin --profile web remove @karoc/dsh-smoothly-opencode-session
Restart dsh web afterwards. Removal is safe: the original fetch is
restored on unload, so no other provider is affected.
src/index.ts host plugin: llm/stream listener + fetch shim
cordis.patch.yml bundle layer (inserts the plugin row with defaults)
scripts/ release gate + post-publish verification
tests/ node --test unit + fake-cordis integration tests
lib/ built output (npm package entry)
npm install # installs dev deps (tsdown, @deepseek-ai/cordis types, @types/node)
npm run bundle # emits lib/index.js
npm test # node --test tests/*.test.ts (runs TypeScript directly) + the guarantee gate
pnpm works too (pnpm bundle, pnpm test); this checkout documents the npm
path because pnpm is not always on PATH.
llm/stream call receive the header —
the decision rides on that context, not on the URL path. The one-shot
model listing used by the Models page (GET <baseURL>/models) is fetched
outside it and therefore receives nothing by default; enable
discoveryFallback if your OpenCode endpoint rejects
that listing too.fetch. If
a future DSH version swaps its network stack, the header silently stops
being sent (the 400 comes back) — uninstall then. This is an external-plugin
stopgap until the provider adapter itself (pi-ai) sends the header.discoveryFallback is enabled.Do not retire this plugin on faith; verify, in this order:
<dsh-root>/packages/llm/llm-pi-ai/node_modules/@earendil-works/pi-ai/package.json
(a flat <dsh-root>/node_modules/@earendil-works/pi-ai/package.json is the
fallback; the package does not export package.json, so require.resolve
will not find it). If the path cannot be located, keep the plugin and
re-check after the next DSH upgrade.dist/ contains x-opencode-session
(grep -rl x-opencode-session <that package>/dist), determine what its
injection is keyed on: the provider id (opencode / opencode-go) or the
base URL (opencode.ai).opencode-go-self is
still not covered, so either keep the plugin or migrate that route to the
built-in opencode-go provider first.@earendil-works/pi-ai dependency
(npm view "@earendil-works/pi-ai@<declared-range>" version reports the
newest version that range allows).MIT
See CONTRIBUTING.md.
FAQs
Smoothly OpenCode Session (Smoothly OCS) — 思磨力 OpenCode 会话头: external DeepSeek Harness host plugin that attaches the OpenCode-required x-opencode-session header to model calls routed to OpenCode / OpenCode Go provider routes (stable per-conversation id; f
The npm package @karoc/dsh-smoothly-opencode-session receives a total of 8 weekly downloads. As such, @karoc/dsh-smoothly-opencode-session popularity was classified as not popular.
We found that @karoc/dsh-smoothly-opencode-session demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
vlt 1.5.0 links skills from JavaScript dependencies to coding agents, with lockfile versioning and Socket data to filter out known malicious packages.

Security News
Rust 1.100 will add opt-in dependency cooldowns to Cargo, giving security scanners and maintainers time to catch malicious crate releases.

Security News
Cloudflare is acquiring Deno’s team, which will provide another year of bug fixes and security updates before ending support for the runtime.