DSH Plugins Marketplace

DSH Plugins

Plugins

/

Development & Infrastructure

/

dsh-speak

R

dsh-speak

Manifest valid★ 1

Read text aloud in the DeepSeek Harness (DSH): a speak tool for the agent, per-message and select-to-read buttons in the Web UI, and per-language voices — via the macOS say command.

UI (client)hasBundlePatch

dsh-speak

Read text aloud in the DeepSeek Harness (DSH), on the machine running it, with the macOS say command.

English | 中文

EntryWhereWhat it does
speak toolthe model can call itreads text aloud, or stops with stop: true
🔊 message actionthe action strip under every finalized assistant replyclick to read that reply, click again to stop
🔊 select-to-read bubbleabove any text you select on the page"select and read", like select-to-translate
⚙ reading settingsspeaker-gear button in the composer dockper-language voice, rate, and Han-character bias

Chinese, English, Japanese, and Korean are detected per character, and every script run is read by its own system voice in its own say process. One reading plays at a time; a new request replaces it.

Audio comes out of the machine running DSH, never the browser. No network calls, no API keys, no model downloads.

Requirements

  • macOS — playback shells out to say. (Linux with spd-say, or a browser-side speechSynthesis variant, would be a separate provider; not implemented.)
  • DSH 0.2.x — the desktop app, or any profile whose page is served to a browser.
  • Node 20+ only if you want to run the offline test.

Install

A. Through the plugin manager (recommended)

  1. Open DSH → Plugins (Settings → Plugins, or the Plugins panel in the sidebar).

  2. Install bundle and paste the repository URL:

    https://github.com/RinChanNOWWW/dsh-speak
    

    A git URL, a local absolute path, and an npm name are all accepted.

  3. The bundle patch inserts one row (speak) and the browser half is served automatically — there is no build step and no dependencies to install.

  4. Use it. If the buttons do not appear, reload the page once.

The in-app plugin manager is the intended path for the desktop app, which is why the dsh plugin CLI refuses that profile. For any other profile the CLI works too — see below.

B. Manual install into a profile

Use this when you want the plugin to live outside the profile's node_modules.

  1. Copy the package next to the profile's patch file:

    $DSH_HOME/profiles/<profile>/plugins/dsh-speak/{package.json,index.js,client.js}
    
  2. Add one row to $DSH_HOME/profiles/<profile>/cordis.patch.yml:

    - insert:
        - id: speak
          name: ./plugins/dsh-speak/index.js
    

    The name must point at the entry file: the loader resolves a .-prefixed name with import(new URL(name, baseUrl)), so a directory cannot be imported, and the browser half is found by walking up from that file to the nearest package.json.

  3. Restart the app, or let the profile reload — an added row is picked up live.

  4. To change host code later: write a new file (index.v2.js…) and remove then re-insert the row. A mounted row is not re-imported when only its name changes, and a ?v= query in the name is rejected by the loader. deploy.sh automates exactly this.

C. A dsh web profile

dsh plugin --profile web add https://github.com/RinChanNOWWW/dsh-speak

That installs the package; the bundle also has to be listed in that profile's package.json → dsh.profile.bundles for its patch to be applied. The in-app plugin manager does both steps for you.

Use

Ask the assistant

"read this aloud" / "读一下这段" / "stop reading" / "别读了"

speak argumentMeaning
texttext to read; markdown is stripped; required unless stop is true
stoptrue stops the current reading instead of starting one
languagezh / en / ja / ko — biases ambiguous text (bare Han characters) and acts as the voice fallback; does not force one voice for everything
voicean exact macOS voice name (Tingting, Kyoko, Yuna, Samantha…); reads the whole text in that one voice
ratewords per minute, 80–500
waitwait for the whole reading instead of returning as soon as it starts

It returns the character count, the languages found, the voices used, and the per-run sequence, e.g. zh:Tingting -> ko:Yuna -> ja:Kyoko -> en:Samantha.

From the interface

  • Message action — 🔊 under a finalized reply. While it reads, the icon highlights and its sound waves pulse; click again to stop. If another reply is being read it dims (clicking switches to this one), and a failure shows red with a retry hint.
  • Select to read — select text anywhere that is not an input; a small bubble appears above the selection (below it when there is no room, always clamped to the viewport). Click it to read; the bubble stays and becomes "stop reading". Selections inside inputs, textareas, and contenteditable regions are ignored, as is anything over 20,000 characters.
  • Settings — the speaker-gear button in the composer dock, or the gear inside the selection bubble.

Stopping a reading

WayNotes
the same bubble, now "停止朗读 / Stop reading"it no longer dismisses itself when it starts
the floating stop pill, bottom rightappears while anything plays — including a reading the agent started through the tool — because the page keeps a slow status heartbeat
⌘⇧S (Ctrl/Cmd+Shift+S)works anywhere, including inside the composer; rebindable in DSH's shortcut settings as speak.stop
ask the assistantspeak with stop: true

Settings

The panel offers, per language (中文 / English / 日本語 / 한국어), the voices actually installed on the machine — recommended ones first — plus a rate slider, a Bare Han switch (whether Han characters without kana read as Chinese or Japanese), a preview button, and save state.

They are stored in $DSH_HOME/dsh-speak.settings.json and also drive the speak tool, so the assistant reads with the voices you picked. Explicit tool arguments override them for one reading.

curl -s $DSH_WEB_URL/api/dsh-speak/settings   # installed voices + current settings

How it works

Two halves in one package (one loader row):

  • index.js — the host half. Registers the speak tool and four routes on the composition's web server:

    RoutePurpose
    POST /api/dsh-speak{action:"speak", text?/sessionId+messageId} or {action:"stop"}
    GET /api/dsh-speak/statuswhat is playing now: source, message identity, languages, voices, sequence, progress
    GET/POST /api/dsh-speak/settingsread/write preferences; lists installed voices
    GET/POST /api/dsh-speak/clientthe browser half's report channel (see Diagnostics)
  • client.js — the browser half, a prebuilt bundle in the format the client module loader expects (window.__ModuleLoader__.load({id, factory})). It registers four slots: conversation.chat.assistant-actions, two entries in shell.overlay, and conversation.composer.dock.

Language handling:

  • Kana makes a Han/kana run Japanese; Hangul is Korean; Latin is English; a kana-free Han run follows the Bare Han setting.
  • Sentence-ending punctuation and script changes split runs, so 中文句子。日本語の文。 keeps two voices.
  • Latin runs shorter than MIN_LATIN_RUN (12 characters of their own script, default) are folded into the surrounding language, so an acronym inside Chinese prose does not flip the voice for three words. CJK and Hangul runs are never absorbed.
  • Playback is one say process per run, started when the previous one exits: say has no inline voice switch (its [[...]] commands cover rate, pitch, volume, and input mode only), and an unsupported [[voice:…]] is read out as literal text.

Diagnostics

The browser half reports what it loaded and did to GET /api/dsh-speak/client (a 200-entry ring buffer in the host): hello (build + registered entries), style, mounted, visibility, rendered (the measured box, whether it is inside the viewport, and which ancestor would break position: fixed), error (with the component stack), plus settings and playback transitions. That is how "I clicked and nothing appeared" gets answered without devtools.

curl -s $DSH_WEB_URL/api/dsh-speak/client

Troubleshooting

SymptomCheck
nothing is readcurl -s $DSH_WEB_URL/api/dsh-speak/status — speaking should be non-null; then .../client for a browser-side failure
buttons missingreload the page; a changed client.js only reaches the page when the row is recomposed
old host code still runsa mounted row is not re-imported on a name change; deploy a new filename and remove/re-insert the row (deploy.sh)
wrong voicethe settings panel: a per-language pin wins, then the recommended voice for that language, then the system default
bare Han read in the wrong languageset Bare Han to 中文 or 日文 — kana-free Han text is genuinely ambiguous
unknown session (422)the message belongs to a session this Harness process has not loaded

Development

pnpm install      # only for @deepseek-ai/dsh-tools, used by index.js and the test
pnpm test         # offline host-half suite; spawns the real `say`, so it makes noise
./deploy.sh       # deploy into the running profile and wait for the reload (dev helper)

deploy.sh writes a new versioned entry file, removes and re-inserts the profile row, waits for the status route to come back, and keeps one entry file. It reads $DSH_PROFILE_DIR and falls back to $DSH_HOME/profiles/desktop.

The test suite stubs the tool registry, session store, and web server, and points the settings file at a temporary DSH_HOME, so it neither needs DSH nor touches your preferences.

Security notes

  • Routes only accept POST/GET and require application/json, so a cross-origin page hits a CORS preflight it cannot pass, and a simple request is rejected with 415. Text never leaves the machine — it goes straight to say.
  • The plugin deliberately does not apply DSH's connection trust fence to its routes, so they can be exercised with curl. It only ever makes the host speak.

License

MIT

Comments

Loading…

From the same category

awesome-dsh-plugin

by awesome-dsh-plugin

A curated list of plugins for DeepSeek Harness (dsh) · DeepSeek Harness 插件精选列表

Development & Infrastructure

★ 18.4k

CC0-1.0

Python

Oct 11, 2026

Index only — not installable

by 0xsline

DeepSeek Harness (DSH) ecosystem: curated plugins, tools, and infrastructure from dsh-external/hub and the public dsh-plugin topic.

Development & Infrastructure

★ 1.2k

CC0-1.0

Python

Oct 10, 2026

Index only — not installable

by pax-beehive

Open-source CLI, schemas, resolver, and DSH agent tools for DSH Plugin Hub

Development & Infrastructure

★ 406

MIT

TypeScript

Oct 6, 2026

Index only — not installable

by xiajiajun516

DeepSeek Harness (DSH) backup & restore plugin — export, import, migrate and sync your complete DSH configuration, plugins, MCP servers, skills and workspace. One-click migration to another machine.

Development & InfrastructureManifest valid

★ 177

MIT

TypeScript

Oct 11, 2026

dsh plugin --profile web add dsh-config-manager

by yjh051108

推荐组件(非必须):DeepSeek Harness 运行时注入器;已随 dsh-routing-suite 单仓库化保留,本仓库继续维护/发布。

Development & InfrastructureManifest valid

★ 165

TypeScript

Sep 18, 2026

dsh plugin --profile web add @dsh-external/dsh-super-injector

by jigjoy-ai

A CLI that turns a goal into a pull request - and a sandbox for testing concurrent AI coding agents on the Mozaik runtime.

Development & Infrastructure

★ 124

MIT

TypeScript

Oct 2, 2026

Index only — not installable