
Sherpa Onnx Tts
Generate local offline speech audio from text using sherpa-onnx models via a Node CLI wrapper for voice-enabled agents.
Overview
sherpa-onnx-tts is an agent skill for the Build phase that runs a Node CLI to synthesize speech locally with sherpa-onnx using configured runtime and model directories.
Install
npx skills add https://github.com/steipete/clawdis --skill sherpa-onnx-ttsWhat is this skill?
- Node entry script accepts quoted text plus optional --runtime-dir, --model-dir, --model-file, --tokens-file, --data-dir,
- Resolves SHERPA_ONNX_RUNTIME_DIR and SHERPA_ONNX_MODEL_DIR from env when flags are omitted
- Auto-picks a single .onnx model in the model directory and default tokens.txt when not specified
- spawnSync-based CLI suitable for agent shell steps without cloud TTS billing
- Usage guardrails print required env vars and exit codes on misconfiguration
Adoption & trust: 1.9k installs on skills.sh; 378k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You want voice output for an agent without paying per-character cloud TTS or exposing customer text to third-party APIs.
Who is it for?
Indie builders adding offline TTS to OpenClaw/clawdis agents who already have sherpa-onnx runtime and model assets on disk.
Skip if: Teams needing managed cloud voices, real-time streaming telephony, or TTS without downloading ONNX models and native runtimes.
When should I use this skill?
Agent or user needs local speech synthesis via sherpa-onnx with SHERPA_ONNX_RUNTIME_DIR and SHERPA_ONNX_MODEL_DIR (or explicit CLI flags).
What do I get? / Deliverables
After configuring sherpa-onnx paths, the CLI produces an audio file from quoted text via local ONNX inference the agent can play or attach.
- Audio file at the configured --output path
- CLI usage/errors that guide model and runtime resolution
Recommended Skills
Journey fit
Local TTS is built when you add voice output to an agent or CLI—canonical placement is Build agent-tooling, not launch marketing. agent-tooling captures ONNX runtime wiring, model dirs, and spawn-based synthesis scripts agents invoke—not generic frontend UI.
How it compares
Skill-wrapped local ONNX TTS—not ElevenLabs API integration or browser Web Speech alone.
Common Questions / FAQ
Who is sherpa-onnx-tts for?
Solo developers wiring on-device speech synthesis into agent workflows where shell-invoked CLIs and environment-based model paths are acceptable.
When should I use sherpa-onnx-tts?
During Build agent-tooling when you need to generate prompt or response audio files from text using sherpa-onnx before ship or demo.
Is sherpa-onnx-tts safe to install?
It executes native sherpa-onnx binaries via spawnSync and reads local model paths—verify binary provenance and review the Security Audits panel on this Prism page.
SKILL.md
READMESKILL.md - Sherpa Onnx Tts
#!/usr/bin/env node import fs from "node:fs"; import path from "node:path"; import { spawnSync } from "node:child_process"; function usage(message) { if (message) { console.error(message); } console.error( "\nUsage: sherpa-onnx-tts [--runtime-dir <dir>] [--model-dir <dir>] [--model-file <file>] [--tokens-file <file>] [--data-dir <dir>] [--output <file>] \"text\"", ); console.error("\nRequired env (or flags):\n SHERPA_ONNX_RUNTIME_DIR\n SHERPA_ONNX_MODEL_DIR"); process.exit(1); } function resolveRuntimeDir(explicit) { const value = explicit || process.env.SHERPA_ONNX_RUNTIME_DIR || ""; return value.trim(); } function resolveModelDir(explicit) { const value = explicit || process.env.SHERPA_ONNX_MODEL_DIR || ""; return value.trim(); } function resolveModelFile(modelDir, explicitFlag) { const explicit = (explicitFlag || process.env.SHERPA_ONNX_MODEL_FILE || "").trim(); if (explicit) return explicit; try { const candidates = fs .readdirSync(modelDir) .filter((entry) => entry.endsWith(".onnx")) .map((entry) => path.join(modelDir, entry)); if (candidates.length === 1) return candidates[0]; } catch { return ""; } return ""; } function resolveTokensFile(modelDir, explicitFlag) { const explicit = (explicitFlag || process.env.SHERPA_ONNX_TOKENS_FILE || "").trim(); if (explicit) return explicit; const candidate = path.join(modelDir, "tokens.txt"); return fs.existsSync(candidate) ? candidate : ""; } function resolveDataDir(modelDir, explicitFlag) { const explicit = (explicitFlag || process.env.SHERPA_ONNX_DATA_DIR || "").trim(); if (explicit) return explicit; const candidate = path.join(modelDir, "espeak-ng-data"); return fs.existsSync(candidate) ? candidate : ""; } function resolveBinary(runtimeDir) { const binName = process.platform === "win32" ? "sherpa-onnx-offline-tts.exe" : "sherpa-onnx-offline-tts"; return path.join(runtimeDir, "bin", binName); } function prependEnvPath(current, next) { if (!next) return current; if (!current) return next; return `${next}${path.delimiter}${current}`; } const args = process.argv.slice(2); let runtimeDir = ""; let modelDir = ""; let modelFile = ""; let tokensFile = ""; let dataDir = ""; let output = "tts.wav"; const textParts = []; for (let i = 0; i < args.length; i += 1) { const arg = args[i]; if (arg === "--runtime-dir") { runtimeDir = args[i + 1] || ""; i += 1; continue; } if (arg === "--model-dir") { modelDir = args[i + 1] || ""; i += 1; continue; } if (arg === "--model-file") { modelFile = args[i + 1] || ""; i += 1; continue; } if (arg === "--tokens-file") { tokensFile = args[i + 1] || ""; i += 1; continue; } if (arg === "--data-dir") { dataDir = args[i + 1] || ""; i += 1; continue; } if (arg === "-o" || arg === "--output") { output = args[i + 1] || output; i += 1; continue; } if (arg === "--text") { textParts.push(args[i + 1] || ""); i += 1; continue; } textParts.push(arg); } runtimeDir = resolveRuntimeDir(runtimeDir); modelDir = resolveModelDir(modelDir); if (!runtimeDir || !modelDir) { usage("Missing runtime/model directory."); } modelFile = resolveModelFile(modelDir, modelFile); tokensFile = resolveTokensFile(modelDir, tokensFile); dataDir = resolveDataDir(modelDir, dataDir); if (!modelFile || !tokensFile || !dataDir) { usage( "Model directory is missing required files. Set SHERPA_ONNX_MODEL_FILE, SHERPA_ONNX_TOKENS_FILE, SHERPA_ONNX_DATA_DIR or pass --model-file/--tokens-file/--data-dir.", ); } const text = textParts.join(" ").trim(); if (!text) { usage("Missing text."); } const bin = resolveBinary(runtimeDir); if (!fs.existsSync(bin)) { usage(`TTS binary not found: ${bin}`); } const env = { ...process.env }; const libDir = path.join(runtimeDir, "lib"); if (process.platform === "darwin") { env.DYLD_LIBRARY_PATH = prependEnvPath(env.DYLD_LIBRARY_PAT