@arach/speakeasy

One API. Every voice.

await say("Text to speech, with nothing in the way.");

Give your coding agent a voice. One command installs the skill; after that it speaks its own summaries, with a real player — transport, speed, and a synced transcript. Or use the library directly: macOS voices, OpenAI, ElevenLabs, Groq, and Gemini behind one function.

$ bunx @arach/speakeasy plugin codex
~950 downloads/mo zero runtime dependencies Node ≥ 22.12 or Bun
// the proof

Five providers. One sentence.

The same words, synthesized five ways. Press play — this is the whole pitch.

macOS System fallback Free. No key. Always there.
OpenAI tts-1 · nova · warm & reliable
ElevenLabs voice IDs · premium quality
Groq Orpheus · very fast
Gemini 2.5 Flash TTS
// missing key? rate limit? offline? // → falls back to the system voice. // It always says something.
// the use case

Your agent finished ten minutes ago.
You were making coffee.

Hook SpeakEasy into Claude Code, Cursor, or Codex and your tools speak a one-line summary when they stop. No API key — the system voice is free.

// ~/.claude/settings.json { "hooks": { "Stop": [{ "command": "npx @arach/speakeasy \"$SUMMARY\"" }] } }
"Build completed successfully." system voice
"Claude needs your permission." system voice
"Waiting for your input." system voice

$ npx @arach/speakeasy "it works" — try it. that's the install.

// the engineering

Built like a library, not a landing page.

01It never stays silent.

Automatic fallback walks your provider order — OpenAI down, key missing, offline — and lands on the system voice. Providers →

fallbackOrder: ["openai", "groq", "system"]

02It never says the same thing twice.

SQLite cache keyed on text, voice, and rate. The second call is a file read, not an API bill. Cache →

cache: { enabled: true, ttl: "7d" }

03It knows what matters.

A priority queue with interrupt: an error alert cuts the line; a status update waits its turn. Queue →

speak(msg, { priority: "high", interrupt: true })
// the contract

That's the entire API.

If you can read this block, you can ship it.

import { SpeakEasy } from "@arach/speakeasy"; const speaker = new SpeakEasy({ provider: "openai", openaiVoice: "nova", rate: 180, cache: { enabled: true }, }); await speaker.speak("Hello, world.");
Browse the docs
New
Introducing SpeakEasy for Codex
A Mac app and iPad control surface built on this library. Speak to the task you're in; hear the answer come back.
See it →