TARSHow it works

What happens when you say “hey TARS”

TARS is a voice assistant for one household. It runs on a Raspberry Pi at home and uses a few cloud services for the hard parts. This page follows one real request from the first word to the follow-up.

The request we follow

Alon Hey TARS, how long do I boil an egg?

TARS Nine minutes for hard, six for soft.

Alon And for a runny one?

The second question needs no wake word.
One request, second by second

0 is the moment you stop talking

Everything before 0 happens while you are still speaking. That is why the answer comes so fast: by the time you finish, the connections are open, the speaker is known and the reply is already being drafted.

The whole run at once. Press play, or pick any step.

A typical run, built from measured medians. Real answers take 1.2 to 1.5 s to the first sound. Detailed shows every lane.

A typical run, built from measured medians; measured 1.2 to 1.5 s to the first sound. After 0 the axis is 3 times wider per second, so the dense part is readable; the follow-up at the far right is not to scale. Drag the playhead along the seconds row to scrub, or tap anything to jump to it. Play moves the playhead at an even, slow pace, and Space plays or pauses.

Every real answer is measured the same way. Each one is kept with how long each stage took and which model wrote it, so the 1.2 to 1.5 s range can be checked against real use, not only a benchmark.

  1. 1−3.4 s

    You say “hey TARS”.

    You
  2. 2−2.8 s

    Stage 1 fires: the small wake model scores 0.2 or more.

    Pi
  3. 3−2.7 s

    Stage 2 says answer. Only now can anything leave the house, and TARS opens its connections while you are still talking.

    Pi to cloud
  4. 4−2.5 to 0 s

    You ask “how long do I boil an egg?” and the audio streams to Flux as you talk.

    You, Pi, Flux
  5. 50.25 s

    Flux says “maybe done”. TARS starts the answer early, in the background, while still recording.

    Flux, Pi
  6. 60.5 s

    Flux says “done”. Now the draft may be played, logged and allowed to send anything.

    Flux
  7. 70.65 s

    Qwen on Groq has the first sentence, about 0.4 s after “maybe done”, streamed.

    Groq
  8. 80.9 s

    James, the Cartesia voice, has the first sentence's audio.

    Cartesia
  9. 91.2 s

    First sound: “Nine minutes for hard, six for soft.”

    Pi
  10. 10after

    It listens a few seconds for a follow-up. “And for a runny one?” goes straight in, no wake word.

    Everyone

Time runs down. Of the two strips beside each step, the left is at home and the right is the cloud. The cloud stays hatched, closed, until stage 2 says yes, and the blue line marks the moment it opens.

    A typical run, built from measured medians; measured 1.2 to 1.5 s to the first sound.

    Every real answer is kept with how long each stage took and which model wrote it, so that range can be checked against real use, not only a benchmark.

    How it decides it was called

    A fast guess, then a careful check

    Stage 1 is cheap enough to run on every 80 ms of sound, so it is allowed to be a little eager. Stage 2 only runs when stage 1 fires, and it is the one that opens the door.

    Every 80 msA block of sound from the mic
    Stage 1The wake model scores it

    microWakeWord, local, 69 KB. A score of 0.2 or more goes on.

    Close, below 0.2: a near-miss

    Logged, never answered. It may be a missed “hey TARS”.

    score 0.2 or more
    Stage 2, the double-checkVosk listens for a small grammar, and a learned layer decides

    Still on the Pi. Nothing has left the house yet.

    AnswerThe cloud opens. Step 3 on the timeline.
    Ask“Did you call me?” The reply decides.
    IgnoreStays quiet. Kept for Review.

    How well the generic models do

    Trained on synthetic and converted voices, never on a household member. These are the models every new install starts with. The clips are on Hugging Face.

    Held-out synthetic voices, quiet97%
    Same voices with TV or people talking, 10 to 15 dB92 to 97%
    The owner, whom it never heard, 30 takes97%
    Lookalikes let through, like “hey cars” and “hey stars”0 to 10%
    False answers per hour, an hour of TV and an hour of audiobooks1 and 0 One on the TV hour, when it heard “hey darts”. Stage 1 alone fires about 30 times an hour on TV and 14 on audiobooks; stage 2 turns down all the others.
    It learns from the household

    Every wake teaches the next pair of models

    The generic models start out good on voices they have never heard. The loop makes them good on yours. People only take part in three places, all in the web app.

    1. 1

      Every wake is kept

      Its 3 seconds of audio, the scores and what followed. Close calls, the near-misses, too. All of it stays on the Pi, and in the household's own bucket if the backup is on: none of it is sent anywhere to learn from.

    2. 2

      Most label themselves

      What happened next says whether a wake was real.

    3. 3
      People, in the web app

      People answer the rest in Review

      A few taps a day. Each unsure wake has its audio, what TARS heard, what happened, and TARS's guess shaded.

      Review, with sample data
    4. 4
      People, in the web app

      Voices are grouped automatically

      Naming one lets TARS greet that person by name.

      Voices, with sample data
    5. 5

      A bigger machine trains a new pair

      A new stage 1 and stage 2, trained on those wakes in about 20 to 25 minutes. Every fifth wake is kept aside for testing, and the new pair is tested end to end against the one in use.

    6. 6
      The gate

      It installs only if it is better for this house and no worse anywhere else

      Better means it answers more of the household's real wakes, or lets fewer through that weren't for TARS. If not, it asks. Once installed, the Pi switches within seconds, and the Models page can switch back.

      The first real run said no
      Test In use New
      Other voices, quiet 94.4% 97.8% better
      Other voices, noise 83.5% 88.3% better
      Lookalikes let through 3.0% 4.8% worse
      False answers per hour, audiobooks 0 1 worse

      Not installed. Better on other voices, but worse on two things that matter. That is the rule doing its job.

      The first real run said no: better on other voices, worse on two things that matter. Detailed shows the numbers.

      Models, with sample data
    Reminders, timers and messages

    It says it again until someone says “got it”

    The same voice that answers can also speak first. You set it by voice or from the web app, and TARS says it when it's due.

    • “Remind me to call the bank at nine.”
    • “Set a pasta timer for twelve minutes.”
    • “Tell Stacey dinner's ready when she's back.”

    Said until it's heard

    TARS says it when it's due, then again every 5 minutes, at most 4 times, until someone says “got it”. After that it's marked Missed.

    Timers ring like a kitchen timer

    Until someone turns them off, for at most 15 minutes. TARS can't hear while it makes a sound, so it rings in bursts and listens in between: “stop” works without the wake word.

    “When she's back”

    Waits until TARS next recognises that voice, then says it.

    Reminders, with sample data

    The Reminders page shows each one and who acknowledged it and how, and sets new ones from a phone.

    The house

    Done means the device says so

    TARS locks the door, runs the boiler, sets the AC and plays things on the TV, through Home Assistant on the home network. It says something's done only once the device reports it.

    Checked, not assumed

    After locking, TARS reads the lock back until it says locked. An AC worked by infrared can't report back, so TARS says it sent the command, never that it's on. A lock that jams is said to have jammed, and an open door is never locked.

    Nothing is done by a draft

    TARS starts answering before you finish, but a change waits until you have. “Turn off the boiler… no, leave it” leaves it.

    Unlocking is for voices it trusts

    The door unlocks only for a voice TARS knows and trusts with it, recognised from the request itself, and only when it heard “unlock”. Anyone can lock.

    An agent works the TV

    For anything that takes several steps, a model works an Android TV box like a person with its remote, reading the screen after every step. It runs in the background, and TARS says how it went after a chime. Devices Home Assistant doesn't work are plugins: a little code of the household's own.

    Two requests

    Alon Hey TARS, lock the front door.

    TARS One moment. Locked.

    Alon And play Toy Story on Stremio.

    TARS On it.

    A minute later, after a chime: “Toy Story is playing.”
    On Telegram

    The same TARS, in writing, from anywhere

    Each person can chat with TARS on Telegram, in writing or with a voice message: ask it something, set a reminder, have it send something, or have a message said aloud at home. TARS asks Telegram for new messages, so nothing at home is opened to the internet.

    Only the people it's told about

    It answers the chats named in its settings, each as that person. Anyone else gets no answer at all, so a stranger can't even tell it's there.

    Reminders come to where you are

    One set in a chat is posted to that chat when it's due. “Tell the house dinner's ready” is said aloud at home instead, and the chat hears when it was said and who said “got it”. Whatever TARS sends at home for someone with a chat comes to their phone as well.

    Written back, even to a voice message

    A voice message is written down by the same speech to text as at home, and the reply comes in writing. Chats go straight to OpenAI's model: a chat is read whole, so Qwen's faster first word buys nothing there. Each person has their own conversation, kept until the chat has been quiet for an hour, or until they send /new.

    A chat, away from home

    Alon Remind me to call the bank at nine.

    TARS Set for 9 AM. It'll come here.

    Alon And tell the house dinner's at eight.

    TARS Saying it at home now.

    A minute later the chat reads: “Stacey said they got it at 7:42 PM.”
    When something breaks

    Every stage has a second option

    TARS fails soft, and when it can't recover it tells you in its own voice.

    Stage Normally If that fails
    End of turn Deepgram Flux Local rules
    Speech to text Flux OpenAI transcribes the same recording
    Brain Qwen on Groq Qwen on Cerebras, then OpenAIIf Groq hasn't started answering within half a second, Cerebras is asked too and the first to answer is kept. A service that fails is skipped for the next two minutes, so an outage doesn't cost every turn its timeout; with both out, OpenAI answers. A reply too long for Groq's cap, like a long note, is written on Cerebras.
    Voice Cartesia Sonic A spoken error line, made at startup
    Wake models The newest trained pair The pair it was installed with
    Mic or speaker The USB speakerphone TARS exits and the system restarts it

    A failed answer is kept in its conversation, with where it failed, and the web app shows it.

    Under the hood

    Small on purpose

    A process for each job, one folder

    The assistant
    The web app, FastAPI and React
    Telegram, if it's on
    A backup to S3 every 15 minutes, if it's on
    One SQLite database, WAL mode

    They share the database on the same machine, and a crash in one never takes another down. The backup copies everything to an S3 bucket, and makes room on the card after a month.

    Every stage is an interface

    TriggerTranscriberBrainVoice

    Swapping a cloud service for a local model is one new class and a config change.

    Every answer is measured, every change evaluated

    Each answer is kept with how long each stage took, which model wrote it and, if it failed, where and why. 29 whole conversations, hand-offs followed through, check the brain: 143 of 145 runs right.

    One command checks it all

    voice-assistant --check checks the keys, devices, models, services, the voice and the mic, and says what's wrong and what to do. Once it runs, the web app's Status page shows much of the same, live: each process by its heartbeat, each service with its key and its own status page, and the Pi's CPU, memory, temperature and disk.

    Hardware

    A Raspberry Pi 5 and a USB speakerphone, an Anker PowerConf.

    Licenses

    The code is MIT. The trained models are CC BY-NC-SA 4.0.

    The repo on GitHub ↗