dsh-opencode-sounds
Manifest validDeepSeek Harness plugin: opencode's notification sound pack for the DSH Web UI (fork of @ai-galaxy/dsh-sound)
dsh-opencode-sounds
A DeepSeek Harness (DSH) Web UI plugin that plays opencode's notification sound pack when a task finishes or something needs a human.
It is a fork of @ai-galaxy/dsh-sound (MIT) that
replaces the built-in synthesized chimes with opencode's real audio assets, and makes the
plugin English-only. The event-detection engine, the settings panel and the subagent channel
come from upstream; the sound pack, the defaults and the translations are this fork's.
Sound pack
Built-in sounds are exactly opencode's, in opencode's order:
| Family | Count | Ids |
|---|---|---|
| Alert | 10 | alert-01 … alert-10 |
| Bip-bop | 10 | bip-bop-01 … bip-bop-10 |
| Staplebops | 7 | staplebops-01 … staplebops-07 |
| Nope | 12 | nope-01 … nope-12 |
| Yup | 6 | yup-01 … yup-06 |
Plus None (silent) and Local file (your own audio file, stored in the browser).
The MP3s live in assets/audio/ and are inlined into lib/client.js as base64 data URLs by
tools/build-sounds.mjs, because the DSH client loads a plugin as a single CJS factory with no
relative-module resolver.
Defaults
Defaults mirror opencode's built-in "OpenCode Default" sound pack
(packages/tui/src/attention.ts at the tag recorded in assets/audio/PROVENANCE.md):
| DSH event | Detection | opencode source | Default sound |
|---|---|---|---|
| Completion | turn/end reason.kind === 'completed'; job → completed | done / default | bip-bop-01 |
| Approval request | approval/requested frame | permission | staplebops-06 |
| User question | question/requested, not plan-review shaped | question | bip-bop-03 |
| Plan review | question/requested classified as plan-review | question | bip-bop-05 |
| Goal blocked | goal projection enters blocked | error | nope-03 |
| Failure | job → failed; turn/end error; host/agent-error | error | nope-07 |
Separate subagent channel
Subagent-originated events (one-shot kind: 'subagent' jobs and sessions marked
origin: 'subagent' / parentId) have their own sounds and volumes:
| Subagent event | Default sound |
|---|---|
| Completion | yup-01 (opencode's subagent_done) |
| Approval / question / plan review / goal blocked / failure | none (silent) |
An Ignore subagent events switch silences the whole channel at once.
Features
- Six fully independent events, each with its own sound and volume (0–100%).
- Completion respects quiet current session; attention events always ring.
- User aborts, killed jobs, and
max-tokens/blocked/interruptedturns stay silent. - Detection adapts to the DSH build: where the connection layer exposes an event stream
(
events.mux+events.host) it is used, with mux-open replay staying silent and eachrpcIdringing at most once; on builds without it (0.1.5-rc.3 and later) the plugin reads the client-side fact sources directly (see below). - Nothing that is already true when the page loads rings: a request already pending, a goal already blocked or a job already failed is seeded silently.
- Multiple tabs: the same event rings once (BroadcastChannel tie-break); a lone tab plays immediately with no handshake.
- Config export/import as JSON (IndexedDB audio refs are inlined as data URLs).
How each sound is detected
| Event | Source (DSH 0.1.5-rc.3+) |
|---|---|
| Completion | turn/end completed in the session's own event window; the list running edge as a deferred fallback for sessions whose window is not staged |
| Failure | turn/end error, SessionSnapshot.lastAgentError, or a background job reaching failed |
| Approval | uiSession.pendingInteractions, kind approval |
| User question | uiSession.pendingInteractions, kind question |
| Plan review | uiSession.pendingInteractions, kind plan-review |
| Goal blocked | the goal projection (projectionValues.goal.goal.phase) entering blocked |
| Silent by design | turn ends aborted / blocked / max-tokens / interrupted, and jobs killed |
Approval, question and plan review are published by the interaction domains themselves, so the
plugin does not re-derive them from frame shapes. On DSH builds that still expose
connection.api.events.mux, the original frame-based watcher runs instead.
Plan review only exists while plan mode is active: exit_plan_mode raises the review question,
and the client classifies it as plan-review from that question's intent and its detail (the plan
itself). If that shape ever changes the card still appears but would sound like a plain question, so
the shape is pinned by a contract fixture in the client tests. A plan review raised inside a subagent
session uses the subagent channel, where it is silent by default.
Settings panel
Settings → Sounds. A master Enabled switch turns the whole plugin on or off, and a
Main agent / Subagents tab bar switches between the
six main event rows and the subagent panel. Each row has a sound dropdown (opencode's whole
pack, then None, then Local file), a Play button, and a volume slider; picking a sound
previews it. Choosing Local file reveals a file picker; the file is stored in IndexedDB
(dsh-opencode-sounds-audio), so the localStorage quota never limits it.
Install
Requires a DSH version with bundle-plugin support (dsh.profile.bundles + dsh.bundle.patch)
and pnpm on PATH (corepack enable or npm i -g pnpm).
# From this checkout
dsh plugin --profile web add file:/home/gonzalo/code/dsh-opencode-sounds
# Or from GitHub
dsh plugin --profile web add github:notf0und/dsh-opencode-sounds
Then restart dsh web (or refresh the page) and open Settings → Sounds.
Manual install
- Add the package to
$DSH_HOME/profiles/web/package.json— both a dependency and a bundle:"dependencies": { "dsh-opencode-sounds": "file:/home/gonzalo/code/dsh-opencode-sounds" }, "dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-opencode-sounds"] } } pnpm --dir "$DSH_HOME/profiles/web" install- Remove the old plugin:
dsh plugin --profile web remove @ai-galaxy/dsh-sound - Restart
dsh web.
The profile uses
nodeLinker: hoisted, which copiesfile:dependencies intonode_modulesat install time. Edits to this checkout do not reach the running app until you re-runpnpm --dir "$DSH_HOME/profiles/web" install(or replace the copied directory with a symlink). The web server reads bundle content per request, so a browser hard-refresh is enough afterwards — no server restart needed.
Configuration storage
- Client config: localStorage, key
dsh-opencode-sounds:config, sanitized on every read. - Local audio files: IndexedDB,
dsh-opencode-sounds-audio. - Sound values: an opencode pack id,
none,local, adata:URL, or anaudio:<id>ref. - Fields:
enabled,quietCurrent,ignoreSubagent, the six main sound + volume pairs (completionSound…failureSound,completionVolume…failureVolume) and the six subagent pairs (subagentCompletionSound…subagentFailureVolume).localFileskeeps the last chosen local file per event so switching away and back does not drop it. - The host also registers the
dsh-opencode-soundssettings namespace. The rc.6 settings API allowlist (WEB_SETTINGS_NAMESPACES) does not expose third-party namespaces to browsers, so the client uses localStorage today; the registration keeps the migration path open.
Development
npm install
npm test # host + client behavioural tests (Node only, no browser needed)
npm run check # syntax check plus a check that the embedded pack is up to date
npm run build # re-embed assets/audio/*.mp3 into lib/client.js
Layout:
lib/index.js— host half: registers the settings namespace (schema + defaults)lib/client.js— browser bundle: event detection, sound engine, settings panellib/types/index.d.ts— host-side type declarationsassets/audio/— opencode's sound files (.mp3embedded,.aackept alongside)cordis.patch.yml— bundle patch layer (inserts thedsh-opencode-soundsrow)tools/— tests, the sound-pack builder, verification scripts
Keeping up with upstream
This repo is a fork, so upstream fixes stay easy to pull. origin is this fork and upstream
is the original plugin:
git remote -v
# origin git@github.com:notf0und/dsh-opencode-sounds.git (this fork)
# upstream https://github.com/AI-Galaxy-GPU/dsh-sound.git (original)
git fetch upstream
git merge upstream/main # or: git rebase upstream/main
Most upstream work lands in the event-detection engine, where this fork is untouched; conflicts
are normally confined to the sound definitions, the defaults and the settings UI. After a merge,
re-run npm run build && npm test.
Updating the sound pack itself means fetching new files from opencode and re-embedding them:
# copy new audio into assets/audio/, refresh PROVENANCE.md, then:
npm run build && npm test
Attribution & license
- Forked from
@ai-galaxy/dsh-sound— MIT. - Sound files from opencode
(
packages/ui/src/assets/audio, tagv1.18.32) — MIT. Seeassets/audio/PROVENANCE.md. - This fork: MIT.
Comments
Loading…
From the same category
by deepseek-ai
DeepSeek Harness: Everything is a Plugin.
★ 238.6k
MIT
TypeScript
Sep 28, 2026
by nexu-io
🎨 Best DeepSeek Harness Design Plugin. The open-source Claude Design alternative. 🖥️ Local-first desktop app. 🖼️ Your coding agent becomes the design engine: prototypes, landing pages, dashboards,
★ 98.5k
Apache-2.0
TypeScript
Sep 28, 2026
by tt-a1i
Agent skill for beautiful, verifiable architecture, workflow, sequence, data-flow, and lifecycle diagrams—self-contained HTML with motion and crisp export.
★ 73.4k
↓ 5.1k/wk
MIT
JavaScript
Sep 28, 2026
dsh plugin --profile agent add @tt-a1i/archify-dshby Tencent
Open-source LLM knowledge platform: turn raw documents into a queryable RAG, an autonomous reasoning agent, and a self-maintaining Wiki.
★ 30.9k
↓ 1.1k/wk
NOASSERTION
Go
Sep 28, 2026
dsh plugin --profile web add @wxg-prc-cpg/dsh-weknoraby awesome-dsh-plugin
A curated list of plugins for DeepSeek Harness (dsh) · DeepSeek Harness 插件精选列表
★ 17.1k
CC0-1.0
Python
Sep 28, 2026
by zhu1090093659
DeepSeek Harness (DSH) Web Plugin Aggregation Ecosystem · Everything is a plugin, distributed via the Creative Workshop
★ 8.1k
Apache-2.0
TypeScript
Sep 28, 2026
dsh plugin --profile web add dsh-web