- 1024 store channel:
npm i -g dsh1024once, thendsh1024 plugin --profile web add dsh-talk(counts toward the deepseek1024.com install ranking).
Voice-first session loop for DeepSeek Harness: talk to it, hear it answer.
Press the mic, speak, and the reply is spoken back — with speak-to-interrupt.
| Surface | Status |
|---|---|
| Harness | DeepSeek Harness 0.1.1-rc.2 (primary target); 0.1.2-alpha.1 runs with the speech-log gate active (see Known limitations) |
| Node | ^22.19.0 || >=24.0.0 |
| Browser | Web Speech + MediaRecorder (Chrome/Edge best); host transcription/TTS engines for the rest |
dsh-talk closes the voice loop in both directions:
speaktool — the agent speaks its replies aloud. TTS engines: the browser voice,edge-tts(network neural voices), orpiper(local). Audio plays in the browser; on hosts that can carry it, the session log records the sanitized utterance (see Security boundaries).- Composer mic button — press it, speak, and the transcription lands in the input box (or submits directly). STT engines: the browser's Web Speech (interim results included), a FunASR HTTP server, or local
whisper.cpp. - Speak-to-interrupt — starting to talk stops whatever is playing (client → host over the
talkRemote namespace). - Event announcements — turn completion, pending approvals (waterfall-safe: never blocks the gate), and errors, with a mute switch and configurable phrases.
- Settings tab — engine/language selects and announcement switches, saved as append-only profile-patch operations with backups.
browser host
🎙 press ──▶ interrupt ─────────────────▶ talk/interrupt
record (MediaRecorder / Web Speech)
transcribe (browser) or talk/transcribe ─▶ FunASR / whisper.cpp
setDraft(text) or submit() ◀── talk:speech projection ── speak tool / announcements
▶ play audio (talk/audio or speechSynthesis)
# 1. install the bundle into your profile
dsh plugin --profile web add "github:PerryLink/dsh-talk#main"
# or from npm (published releases)
dsh plugin --profile web add dsh-talk
# 2. restart and verify the row
dsh --profile web --dump-config | grep -A2 'id: talk'Then press the microphone next to the composer and talk; ask the agent to speak its reply:
> Say "hello" with the speak tool.
- git channel (latest
main):dsh plugin --profile web add "github:PerryLink/dsh-talk#main"— thepreparescript builds with production dependencies only. - npm channel (published releases):
dsh plugin --profile web add dsh-talk. - tarball channel:
pnpm packin this repo, thendsh plugin --profile web add ./dsh-talk-<version>.tgz. - uninstall:
dsh plugin --profile web remove dsh-talk(or remove the row from the profile patch).
If pnpm reports
ERR_PNPM_IGNORED_BUILDSfor this package (esbuild's harmless platform-binary validation), addallowBuilds: { esbuild: true }to yourpnpm-workspace.yaml— thedshCLI prints the exact snippet.
All tunables are Schemastery Config fields (changeable from cordis.yml). cordis.patch.yml documents each key inline.
| Key | Default | Meaning |
|---|---|---|
record.enabled |
true |
Show the composer mic button |
record.hotkey |
(none) | Optional toggle hotkey, e.g. "alt+r" |
record.maxSeconds |
60 |
Recording cap in seconds (1..600) |
record.autoSubmit |
false |
Submit the transcription as a user message (false = fill the draft) |
record.vad.enabled / silenceMs / energyThreshold |
true / 1500 / 0.01 |
Voice-activity detection: silence auto-ends the recording (degrades when AudioContext is absent) |
stt.engine |
auto |
auto / web / funasr / whisper; auto prefers a configured local engine, then Web Speech |
stt.language |
auto |
BCP-47 language or auto |
stt.interim |
true |
Show interim transcriptions (Web Speech) |
stt.silenceFinaliseMs |
4000 |
Stop continuous Web Speech recognition after this many milliseconds without speech (500..15000) |
stt.funasr.url |
(none) | FunASR inference endpoint; required when the engine is funasr |
stt.whisper.modelPath |
(none) | whisper.cpp model; required when the engine is whisper |
tts.engine |
auto |
auto / browser / edge-tts / piper; auto prefers piper, then edge-tts, then the browser voice |
tts.rate |
0 |
Rate offset in percent (-50..50) for edge-tts/piper |
tts.fallbackToBrowser |
true |
Fall back to the browser voice when a local engine fails |
tts.browser.voiceName |
(none) | Preferred browser voice name; an unknown name uses the platform default |
tts.browser.rate |
1 |
Browser SpeechSynthesis rate (0.1..10) |
tts.browser.pitch |
1 |
Browser SpeechSynthesis pitch (0..2) |
tts.piper.modelPath |
(none) | piper voice model; required when the engine is piper |
announce.enabled |
true |
Master switch for event announcements |
announce.onTurnEnd / onApproval / onError |
true |
Which events are spoken |
announce.messages.* |
"Turn complete." etc. | Spoken phrases |
interrupt |
true |
Talking stops current playback |
maxSpeakChars |
20000 |
Cap on the speak tool's text length (1..100000) |
maxAudioCacheBytes |
8388608 |
In-memory synthesized-audio cache cap (1 MiB..64 MiB) |
stt.silenceFinaliseMs and record.vad.silenceMs are separate mechanisms: the first finalises the Web Speech transcript when continuous recognition hears no speech, the second is the MediaRecorder energy-based detector that ends the recording (and submits it when record.autoSubmit is on). They run in different pipelines and share no state.
| Surface | Kind | Notes |
|---|---|---|
speak |
tool | Speaks text aloud (browser/edge-tts/piper); per-call engine/voice overrides; canonical JSON outcome |
| mic button | conversation.input.left slot |
Record → transcribe → fill draft (or submit); speak-to-interrupt on press |
| settings tab | settings.plugins.tab (id talk) |
Engine/language/announcement switches; append-only save |
talk:* |
Typert Remote | status, audio, transcribe, applySettings, interrupt (host namespace) |
- Permissions: the plugin stores nothing but an in-memory, byte-capped audio cache; microphone permission is browser-mediated. The settings tab only appends patch fragments to the profile with a timestamped backup — never rewrites the file.
- Data: audio never enters the model context or the session log. Where the host's session vocabulary accepts it, the
dsh-talk/speechevent carries the utterance id, engine, reason, size, sanitized text, and browser voice/rate/pitch when applicable; on envelope-less hosts the event is not written at all. All display/log surfaces redact credentials, JWTs, bearer headers, and temp paths. - Network: only the engines you configure are contacted.
edge-ttsperforms network synthesis, FunASR uses its configured endpoint, and Chrome'swebkitSpeechRecognitionsends microphone audio to Google's servers for transcription; browserspeechSynthesisplayback remains local.
- Model-visible ⟺ logged — the model sees only the speak tool's canonical value and render text. The
dsh-talk/speechevent is appended only when the host can carry it (see Host compatibility); thetool/call+tool/resultevents always remain the reconstructable trail. - Approval announcements never block — the
approval/requestlistener always callsnext(). - Sanitized output — credentials and temp audio paths never reach logs or displays.
- Host compatibility — the
dsh-talk/speechevent is appended through an adaptive gate. Hosts whose known-type vocabulary covers the event append it plainly; hosts with theignorableappend option append it with the marker; envelope-less hosts — every released line through0.1.1-rc.2, and0.1.2-alpha.1, which removed the envelope and fails closed on unknown types — get no append, so speech can never pollute the session log on those lines. There, the live playback history stays empty and the speak tool results are the reconstructable audit trail. - Fail loud — invalid engines, out-of-range values, and engines configured without their required model/endpoint fail the mount.
- Browser support: Web Speech and MediaRecorder are feature-detected; without them the mic button disables itself and host engines (FunASR/whisper.cpp) can still transcribe when configured.
- Local engines are your install:
edge-tts,piper, andwhisper.cppexecutables and models must be installed separately. - Recording format: the browser records with its native MediaRecorder codec; whisper.cpp may require a WAV-configured recorder or a server-side conversion for other formats.
- Settings apply on reload: the settings tab appends to the profile patch; a profile reload (or web-app restart) activates the changes.
- Live playback history is empty on envelope-less hosts: on
0.1.1-rc.2and0.1.2-alpha.1the host vocabulary does not knowdsh-talk/speech, so the gate writes nothing and the client's session-scoped playback list stays empty. Speech itself, the mic, the settings tab, and the tool are unaffected. - Legacy logs written by dsh-talk ≤ 0.2.1 may need repair before cold load: versions through
0.2.1appended unmarkeddsh-talk/speechevents. On hosts0.1.0-rc.7and newer, a session whose log already contains them fails its next cold load withSessionFormatUnsupportedError. Repair: stop the host, back up the session's.jsonllog, add"ignorable":trueas a top-level member of every JSON line whose"type"is"dsh-talk/speech"(for example, insert"ignorable":true,right after the opening{), then reopen the session. Nothing else changes and nothing is lost; new appends from this version never add unmarked events.
pnpm install # node ^22.19 || >=24
pnpm run typecheck # tsc: src + tests against the local harness checkout
pnpm run typecheck:ci # tsc against the published 0.1.1-rc.2 types (no paths)
pnpm test # vitest: 77 tests, 13 suites
pnpm run build # tsc declarations + tsdown bundles (lib/)
pnpm run verify:self-contained # dependency specs resolve from the registry
pnpm run verify:artifacts # built ESM faces + client ModuleLoader handshake
pnpm pack # the published tarballdsh, dsh-plugin, deepseek-harness, deepseek, cordis, voice, speech, tts, stt, speech-to-text, text-to-speech, microphone
- @PerryLink — creator and maintainer: speak pipeline, speech engines, mic recorder, event announcements, projection unit, and the five-language docs.
This project is one of the 33 DeepSeek Harness plugins maintained by PerryLink. If this one helps you, the others likely will too:
| Plugin | One-liner |
|---|---|
| dsh-dsh-auto-review | Second-model auto-review on the approval chain, fail-closed by default |
| dsh-dsh-background-agents | Durable background child agents with a Web UI sidebar, messaging and interrupt |
| dsh-dsh-budget | Cost governance for DeepSeek Harness: budgets, carbon, and latency in one panel. |
| dsh-dsh-checkpoint-rewind | Claude Code /rewind-equivalent: snapshots, session forks, one-shot restore |
| dsh-dsh-claude-move | Migrate Claude Code sessions, memory, skills and CLAUDE.md into DSH |
| dsh-dsh-click | Cross-platform native desktop control for DeepSeek Harness — Windows first. |
| dsh-dsh-composer-history | Terminal-style input history for the web composer: arrows, Ctrl+R search |
| dsh-dsh-data-quality | Dataset quality checks and citation cross-checks (the optional numeric bridge consumed here) |
| dsh-dsh-defend | Prompt-injection, jailbreak, and secret-leak defense for DeepSeek Harness. |
| dsh-dsh-doublecheck | Engineering-discipline guard: requirements grill, test gates, adversary review |
| dsh-dsh-draw | Unified static-image generation routing for DeepSeek Harness. |
| dsh-dsh-fast | Read-only performance diagnostics for DeepSeek Harness. |
| dsh-dsh-fund-research | Deterministic research reports for Chinese public mutual funds |
| dsh-dsh-github | GitHub PR/issues integration for DSH, every write gated by approval |
| dsh-dsh-industry-research | Industry research orchestration that seals its deliverables through this plugin's ctx.researchReport.assemble |
| dsh-dsh-library | Local document knowledge base for DeepSeek Harness. |
| dsh-dsh-local-ai | Local-model (Ollama) integration for DeepSeek Harness. |
| dsh-dsh-lsp-actions | LSP diagnostics, formatting, completion, code actions and rename over language servers |
| dsh-dsh-mask | PII masking middleware: anonymize at the model boundary, restore at the display layer |
| dsh-dsh-mcp-panel | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors |
| dsh-dsh-memento | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool |
| dsh-dsh-observe | OpenTelemetry and Langfuse observability exporter for DeepSeek Harness. |
| dsh-dsh-output-styles | Claude Code outputStyles-equivalent runtime style switching |
| dsh-dsh-permission-rules | Claude Code-style declarative allow/deny/ask permission rules with audit |
| dsh-dsh-plugin-guide | Plugin-development knowledge base as an on-demand agent skill |
| dsh-dsh-research-report | Verifiable research-report engine: content-addressed evidence ledger and sealed versions |
| dsh-dsh-score | Multi-dimensional quality scoring for DeepSeek Harness plugins. |
| dsh-dsh-session-pin | Pin sessions in the Web sidebar with durable ordering |
| dsh-dsh-session-sync | Cross-device session sync for DeepSeek Harness — a dedicated git mirror of your session store. |
| dsh-dsh-skill-pack-security | Security-audit skill pack: secret scan, dependency and supply-chain review |
| dsh-dsh-test-drive | Isolated install-and-smoke test drives for DeepSeek Harness plugins. |
| dsh-dsh-translate | Vendor parameter translation and deterministic JSON repair for DeepSeek Harness. |
Apache License 2.0 © 2026 dsh-talk contributors