cd /news/ai-agents/show-hn-hey-spark-open-source-voice-… · home › topics › ai-agents › article
[ARTICLE · art-161634] src=github.com ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Show HN: Hey Spark – open-source voice assistant for your laptop, any LLM brain

ContextuAI released Hey Spark, an open-source always-listening voice assistant for macOS 14+ on Apple Silicon and Windows 11 that runs wake-word detection (openWakeWord), speech-to-text (faster-whisper) and text-to-speech (Piper or Kokoro) locally on the CPU while routing requests to Claude via the Claude Agent SDK, Hermes Agent, or any OpenAI-compatible model including local ones through Ollama. Hey Spark connects to tools such as GitHub, Gmail and Calendar through MCP servers with per-server allowlists, requiring a spoken "yes" before any tool that sends, creates or updates, and blocking destructive tools by default. The release requires about 1 GB of disk for models, and audio leaves the machine only if a user selects a cloud STT backend such as Deepgram or ElevenLabs.

read12 min views8 publishedOct 31, 2026
Show HN: Hey Spark – open-source voice assistant for your laptop, any LLM brain
Image: Michielbdejong (auto-discovered)

by ContextuAI

An always-listening voice assistant for your laptop. Say "Hey Spark", ask a question or give a command, and hear the answer. The wake word, speech recognition and voice all run locally on your CPU. The brain is Claude, Hermes Agent, or any OpenAI-compatible model, including a local one through Ollama. Spark reaches your tools (GitHub, Gmail, Calendar, your own systems) through MCP servers, and it asks out loud before doing anything that changes something.

"Hey Spark, what's on my calendar tomorrow?" "Set a pasta timer for ten minutes." "Summarize the open pull requests on hey-spark." "Let's start a new project called weather-bot." → "I'll create a folder, a git repo and a private GitHub repo called weather-bot. Should I go ahead?"

  • Local wake word. A bundledopenWakeWord model for "Hey Spark".Train your own wake word for free in Google Colab, or use Picovoice Porcupine.
  • Local speech.faster-whisper speech-to-text andPiper orKokoro text-to-speech, all CPU-only. Deepgram and ElevenLabs are optional cloud backends.
  • Your choice of brain. Claude through theClaude Agent SDK , your ownHermes Agent , or any OpenAI-compatible API: OpenAI, Azure OpenAI, OpenRouter, Groq, Together, Ollama, LM Studio or vLLM.
  • Connectors over MCP , with per-server allowlists. Read-only tools run freely; anything that sends, creates or updates needs aspoken "yes" , and destructive tools are blocked by default.
  • Conversation that feels natural. Spark streams its answer sentence by sentence, stays awake for follow-ups without the wake word, ignores speech that isn't meant for it, and can be interrupted by saying the wake word (barge-in).
  • A personality of your choice. Plain and brief by default, or a composed British butler with a dry wit who calls you "sir", answers the wake word with "Yes, sir?" and speaks in a British voice. SeePersonality and voice .
  • Memory and shortcuts. It keeps editable Markdown notes about each connected system, and you can map a short phrase ("good morning") to a detailed prompt.
  • Desktop app for macOS and Windows: a single Start/Stop button, a light that shows what Spark is doing, and windows for Connectors, Shortcuts, the Brain, and Personality & Voice.
  • Everything is swappable from config.yaml : wake word, VAD, STT, TTS and brain backends, with no code changes.
flowchart LR
    mic[Mic 16 kHz] --> wake[Wake word<br/>openWakeWord]
    wake --> vad[Record until silence<br/>Silero VAD]
    vad --> stt[Speech to text<br/>faster-whisper]
    stt --> brain[Brain<br/>Claude or OpenAI-compatible]
    brain <--> mcp[MCP connectors<br/>+ spoken confirmation]
    brain --> split[Sentence splitter]
    split --> tts[Text to speech<br/>Piper / Kokoro]
    tts --> spk[Speaker]

Nothing leaves your machine before the wake word. After it, only the text of your request goes to the brain you chose. Audio leaves the machine only if you pick a cloud STT backend.

Requirements: macOS 14 or later on Apple Silicon, or Windows 11 (see Platform support), a microphone, about 1 GB of disk for models, and a brain: Claude Code signed in to your Claude account (or with an Anthropic API key), an OpenAI-compatible key, or Ollama running locally. A USB speakerphone with echo cancellation works best.

Get the latest build from Releases. Each file has a .sha256 checksum next to it.

macOS (Apple Silicon, macOS 14+)

  1. Download HeySpark-<version>-macos-arm64.dmg , open it and dragHeySpark intoApplications .
  2. Open it from Applications. If macOS says it can't verify the app, open System Settings → Privacy & Security , scroll down and clickOpen Anyway . (Or runxattr -dr com.apple.quarantine /Applications/HeySpark.app once in Terminal.)
  3. Allow microphone access when macOS asks.

Settings, logs, models and your .env live in ~/Library/Application Support/HeySpark.

Windows (Windows 11)

  1. Download and run HeySpark-Setup-<version>.exe . It installs per-user and needs no admin rights. The installer isn't code-signed yet, so Windows SmartScreen may warn you: chooseMore info → Run anyway .
  2. Open Hey Spark from the Start menu.

Settings, logs, models and your .env live in %LOCALAPPDATA%\HeySpark.

Then, on either platform:

  1. Click the brain button, pick a provider and enter your key (or pick Ollama).
  2. Press Start . The first start downloads the speech models (about 200 MB). Then say*"Hey Spark"* .
git clone https://github.com/contextuai/hey-spark.git
cd hey-spark
uv sync --all-extras                 # plain `uv sync` skips the optional backends

uv run spark models download

cp .env.example .env                 # (Windows: copy) then set your key; see "Choose a brain"

uv run spark doctor                  # every required check should show ✔
uv run spark                         # say "Hey Spark, what's the capital of Japan?"

No microphone handy? uv run spark --text lets you type questions and read answers, and uv run spark --brain mock --text runs fully offline with no key at all.

Brain Set up Good for
Claude (default) Claude Code installed and signed in (orANTHROPIC_API_KEY in.env ) The best tool use and connector work. Supports the researcher sub-agent and fast/deep model routing
Hermes Agent Hermes Agent with its API server on, and itsAPI_SERVER_KEY Giving your Hermes agent a voice: it answers with its own model, tools, memory and skills
OpenAI-compatible cloud (OpenAI, Azure, OpenRouter, Groq, Together) The provider's key in .env , andbrain.backend: openai_compat Using a model or account you already have
Local (Ollama, LM Studio, vLLM) Run the server, pull a tool-capable model (e.g. qwen2.5:7b ) Fully local : with faster-whisper and Piper, nothing leaves your machine

The easiest way to switch is the desktop app's Brain window, which also tests the connection and checks that the model can call tools. See docs/openai_brain.md for the provider presets and the config.yaml settings.

With Claude, brain.mode picks the models: auto (default) sends quick requests to brain.fast_model and bigger ones to brain.deep_model; deep answers everything with brain.deep_model and hands tool-heavy lookups to a researcher on a faster model (the best answers, and the highest API cost). You can also switch by voice ("use the deep model", "back to auto").

The default config.yaml uses the bundled model assets/wakewords/hey_spark.onnx. Nothing to set up. If it misses you or wakes on its own, tune wakeword.options.openwakeword.threshold.

Want your own wake word? tools/wakeword_trainer.ipynb trains one for any phrase on a free Colab GPU in about an hour, with no recordings needed. docs/wakeword.md walks through it step by step, plus the Porcupine alternative.

  • Follow-ups: after a reply, Spark stays awake for 3 minutes (attention.awake_s ), so you can keep talking without the wake word. It answers only speech that's meant for it, then plays a soft chime when it falls asleep.
  • Commands: "new topic" (fresh conversation), "go to sleep", "never mind", and "mute yourself" (it then stops listening until you click the mic button in the window). Film-style ones work too: "stand down", "belay that", "clean slate protocol", "full power", "go dark".
  • Timers and time: "set a pasta timer for 10 minutes", "what timers do I have", "what time is it".
  • New projects: "let's start a new project called weather-bot". After youryes , Spark createsprojects.root_dir/weather-bot with git and a first commit, a private GitHub repo and a tracking issue through yourgh login (it never pushes), and can open Claude Code in the folder.
  • Shortcuts: map a phrase like "good morning" to a detailed prompt in the Shortcuts window (orshortcuts.json ). Fifteen come built in: "rise and shine" for the morning briefing, "what's next?", "sitrep", "check the post", "run a diagnostic", "house party protocol" and more. Seedocs/commands.md .
  • Barge-in: withapp.barge_in: true , saying the wake word while Spark is talking stops it. Turn this on only with an echo-cancelling speakerphone.
  • Earcons: a chime on wake, a tick while thinking, a low tone on errors.
  • Personality and voice: pick the butler personality and a British voice in the Personality & Voice window (orapp.persona: butler inconfig.yaml ). Seedocs/persona.md .

Connectors are MCP servers defined in mcp_servers.json (with ${VAR} placeholders only; the values come from .env). Add them by hand or in the desktop app's Connectors window. Each server's tool policy lives in config.yaml under connectors::

  • allowed_tools are read-only and pre-approved.
  • side_effecting tools (send, create, update) need aspoken "yes" every time. Spark says one line about what it will do and waits. Silence, an unclear answer or "no" means it doesn't happen.
  • destructive tools are blocked unless you setallow_destructive: true for that server.
  • Any tool on none of these lists is denied.

Create a fine-grained token for the repos Spark may see:Issues: Read and write ,Pull requests: Read andContents: Read . 2. In the Connectors window, opengithub (underFrom config files ) and clickEdit config . Replace${SPARK_GITHUB_PAT} with your token and pressSave and test . Spark moves the token to.env .

{
  "github": {
    "type": "http",
    "url": "https://api.githubcopilot.com/mcp/",
    "headers": { "Authorization": "Bearer YOUR_TOKEN" }
  }
}

Switch it on. Spark uses GitHub's own labels for the tools: reading runs freely, creating an issue asks you first, and deleting is off. Try "What are the open issues in my-repo?"

This is GitHub's official github-mcp-server, hosted by GitHub. GitHub's docs list Copilot access as a prerequisite for the hosted server (Copilot has a free plan); if your account is refused, or you'd rather run it on your own computer, see docs/connectors.md. Paste the token itself: GitHub's VS Code example uses ${input:...}, a VS Code prompt that Spark can't show.

Choose Add connectors in the Connectors window and paste any MCP server's JSON (the mcpServers block from its README or from Claude Desktop), or import Claude Desktop's servers in one click. docs/connectors.md covers servers set up by hand in mcp_servers.json and config.yaml, including Gmail, Google Calendar and Outlook through Composio. The claude.ai Gmail and Calendar connectors are off by default: they work only through a claude.ai login in your own Claude CLI, so they're for personal setups.

  • Before the wake word, audio never leaves the wake-word detector, and no audio is stored unless you run with --debug-audio .
  • After the wake word, your words are transcribed locally (unless you choose Deepgram) and the text goes to the brain you chose.
  • Secrets live only in .env or the environment. A redaction filter masks them, and common token shapes, in every log line.
  • Spark keeps local logs you can read and delete: transcripts (logs/transcripts.log , turn off withlogging.transcripts: false ) and an activity history (history/ , seeactivity: inconfig.yaml ). They never leave your machine.

Everything is in config.yaml, and every key has a comment. Override any key per run with an environment variable (SPARK_<SECTION>__<KEY>) or a CLI flag:

wakeword: { backend: openwakeword }   # openwakeword | porcupine
stt:      { backend: faster_whisper } # faster_whisper | deepgram
tts:      { backend: kokoro }         # kokoro | piper | elevenlabs | print
brain:    { backend: claude_agent }   # claude_agent | openai_compat | mock
$env:SPARK_STT__BACKEND = "deepgram"; uv run spark
uv run spark --stt deepgram --tts kokoro

All commands #

uv run spark                         # voice mode
uv run spark --text                  # type questions, print answers (no audio devices)
uv run spark --text --speak          # type questions, hear answers
uv run spark --no-tts                # voice in, printed answers out
uv run spark --debug-audio           # also save the last utterance to debug_audio/
uv run spark -v                      # debug logging (shows tool calls by name)
uv run spark desktop                 # the desktop window
uv run spark doctor                  # environment checks, each with a fix
uv run spark models download         # whisper + the configured voice (Kokoro George by default)
uv run spark bench stt|tts|brain     # latency benchmarks (median / p90)
uv run spark bench latency           # live: wake word to first audio, end to end
uv run spark bench false-wake --minutes 30   # live: count false wakes on background audio

Per-turn latency breakdowns are appended to logs/latency.jsonl.

Platform Status
macOS 14+, Apple Silicon Desktop app ( .dmg ) and source. Every build is self-tested in CI. New in 0.1.0, so please report anything odd.
Windows 11 Desktop app (installer) and source. The platform Hey Spark was developed on (WASAPI audio).
Intel Macs, Linux From source only, untested. The code is cross-platform Python; reports and pull requests are welcome.

Everything runs on the CPU; no GPU is needed.

macOS (on a Mac with the Xcode command-line tools):

bash scripts/build_macos.sh

This freezes the app into build/dist/HeySpark.app, signs it ad hoc, runs its self-test and writes build/installer/HeySpark-<version>-macos-arm64.dmg. Set MACOS_SIGN_IDENTITY (plus APPLE_ID, APPLE_TEAM_ID and APPLE_APP_PASSWORD) to sign with a Developer ID and notarize.

Windows:

powershell -ExecutionPolicy Bypass -File scripts\build_windows.ps1

This freezes the app into build\dist\HeySpark\HeySpark.exe. With Inno Setup 6 installed (winget install JRSoftware.InnoSetup), it also writes build\installer\HeySpark-Setup-<version>.exe.

Releases are built by GitHub Actions (build-apps.yml), which also builds both apps for pull requests that touch packaging or the desktop app.

uv run pytest -q                     # offline suite: fakes and synthesized audio, about a minute
uv run pytest -q -m live             # hits real Claude / cloud APIs (needs keys)
uv run ruff check . && uv run ruff format --check .

The architecture in one line: every component is an abstract class in spark/interfaces.py, and spark/registry.py maps the backend names in config.yaml to implementations. spark/app.py is the state machine. CONTRIBUTING.md explains how to add a backend, run the tests and send a pull request, and docs/design/SPEC.md is the original design spec. Hardware checks that need a real mic are in docs/dev/MANUAL_QA.md.

Hey Spark was built with Claude Code. The project's agents and skills are in .claude/, and the original phase plans and reports are in docs/dev/history.

Contributions are welcome: see CONTRIBUTING.md and the Code of Conduct. Please report vulnerabilities privately as described in SECURITY.md. Release notes are in CHANGELOG.md.

The code is MIT © 2026 Nagendra Rao Jogi.

The bundled wake-word model (assets/wakewords/hey_spark.onnx) is licensed separately under CC BY-NC-SA 4.0 (non-commercial), because its training data has mixed licenses. See assets/wakewords/LICENSE. For commercial use, train your own model on data you're licensed to use, or use Porcupine. Licenses for the dependencies and the downloaded speech models are listed in THIRD_PARTY_NOTICES.md.

Hey Spark is an open-source project from ContextuAI, makers of ContextuAI Solo.

── more in #ai-agents 4 stories · sorted by recency
── more on @contextuai 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-hey-spark-op…] indexed:0 read:12min 2026-10-31 · —