Every model runs on your machine

It joins the call.
Nothing leaves the room.

Send it a meeting link. It joins as its own participant, answers out loud, and draws on a whiteboard.

Live render, not a recording
Tekkibot
JMJules
ARAri
room

…so are we shipping the migration this week?

try an expression:
  • Playwright
  • Ollama
  • whisper.cpp
  • Kokoro · mlx-audio
  • PulseAudio
  • Canvas2D
  • Docker
  • Telegram

Meet has no plugin API.
So Tekki becomes the hardware.

To be in a video call you need to be two devices: a camera and a microphone. Everything else is detail. The AI half is commodity. The device half is where the work is.

  1. 01hear

    PulseAudio null sink

    Chrome plays the meeting into a sink that isn't a speaker. One parec records its monitor, and every participant is mixed for free.

  2. 02hear

    whisper.cpp

    The monitor stream becomes text on the host, where it keeps its GPU acceleration. Base English model, no timestamps.

  3. [thinking]“Only if…”
    03think

    Ollama

    A small non-reasoning model answers in a third of a second and tags its own expression inline, e.g. [thinking].

  4. 04speak

    Kokoro

    The reply becomes PCM through mlx-audio, a voice that doesn't sound like a satnav, and its amplitude drives the mouth.

  5. 05show

    canvas.captureStream()

    The avatar is drawn into a canvas at about a millisecond a frame, then handed to Meet as a camera track.

  6. navigator.getUserMediapatched
    06show

    getUserMedia, replaced

    Patched before Meet's own JavaScript runs. Meet enumerates a camera and a microphone and cannot tell they aren't hardware.

Why hearing works the other way round

Chrome routes decoded remote audio to the output device and never hands it back to WebAudio, so intercepting tracks in the page is a dead end: it attaches happily and delivers silence. Recording the sink monitor instead also means Tekki can't hear itself: its voice leaves by the microphone track and never reaches a speaker.

Why not a reasoning model

Measured over the same three turns: qwen3:4b took 23s to answer cold, then returned empty replies at 38s and 40s. On a reasoning model the token budget covers the scratchpad first, so a cap sized for two spoken sentences gets spent thinking.

turnqwen3:4b3B, no reasoning
first, cold23.4s10.1s
second38.1s · empty0.32s
third40.8s · empty0.32s

Why a cartoon
robot, exactly

Not to save effort, and not as a placeholder for something photoreal later.

  • 01

    It can't be mistaken for a person

    Anyone glancing at the call can see there's a bot in it. That's a promise the consent section makes, and an antenna is what keeps it.

  • 02

    No human character is neutral

    Any face implies an age, a gender and an ethnicity, and every viewer reads something into those. A robot sidesteps the question entirely.

  • 03

    Photoreal is a fight worth not having

    A drawing that blinks and reacts reads as charming. A nearly-human face that blinks slightly wrong reads as a corpse.

And it stays cheap: arcs and rounded rectangles, about a millisecond a frame, where a diffusion model needs hundreds. That's the whole reason local realtime is possible at all.

[neutral]
[happy]
[thinking]
[surprised]
[concerned]

Every tile is the live renderer, not a recording, the same drawAvatar that feeds the camera track in a call.

~1ms / frame
Recorded from the renderer itself rather than mocked up. The two small squares add up to the big one, which is the whole theorem in one picture.

Tutor mode

Photograph the page
it teaches from that

Send a picture of what you are stuck on, then a meeting link. It works out a running order and teaches it on a whiteboard it draws itself.

  1. Photograph the page

    The one you're stuck on. A local vision model reads it into a topic, a formula, the key facts and a worked example.

  2. Send a meeting link

    It joins, turns its camera on, and shares a whiteboard of its own. Meet never opens a screen picker, because it is never asked.

  3. Interrupt whenever

    It stops mid-sentence, answers the question, and picks up at the step it left off. The page is the syllabus, so it answers from the book rather than from memory.

The model never draws. It picks a shape by name and every coordinate is computed in code, so a thin answer becomes a thinner diagram rather than a broken one.

You drive it
from your pocket

A supervisor takes the message and forks a join session per conversation, so several chats can each hold their own meeting, one call per profile. Telegram is for when you are away from the machine; the Mac app speaks to the same supervisor directly, and the token is optional.

(a photo of a page)
Read it, and be ready to teach it.
(a Meet link)
Join that call, teaching the page if you sent one.
/draw <topic>
Share a whiteboard and draw it.
/say <text>
Say that line in the call.
/undraw
Stop presenting.
/status
What it is doing.
/stop
Leave.

In the call you can also just ask out loud. “Draw how that works” and “show me the difference” both land, and it will stop mid-sentence to answer a question.

Mac app

Or skip the terminal
entirely

A small Mac app that checks what Tekki needs, starts it, and drives a call from a window: paste a link, say something, teach a page. It configures the same thing the commands below do; it does not replace them.

Tekki 1.0

macOS 14 or later · Apple silicon or Intel · 441 kB

Download for MacRelease notes and older versions

It isn’t notarised. macOS will refuse to open it the first time, because it came from the internet and there is no paid developer identity signing it. Right-click the app and choose Open, then Open again. If you would rather not take that on trust, build it from source instead. Same app, no warning.

Chat
Paste a meeting link to join it, type to speak in the call, “draw …” for a diagram, or attach a photo of a page to be taught it. Telegram optional.
Setup
Checks Docker, Ollama, whisper, Kokoro, the bot token and the Google sign-in, and puts the fix beside whatever is missing.
Models
Which model does which job, from what Ollama actually has installed. Pull another without a terminal.
Activity
What it heard, what it said, and every board it drew.

The app still needs the repo cloned, Docker running and the three local model services up. It checks for each and tells you which is missing. Everything below is what it is checking.

Five steps,
one machine

Needs Docker, and a Mac or Linux box with enough memory to hold a 3B model. No account to create, no key to buy, no endpoint to trust.

  1. 1

    Local models

    Ollama for the thinking, whisper for the listening, Kokoro for the voice.

    shell
    ollama pull llama3.2:3b
    brew install whisper-cpp
    mkdir -p models && curl -L -o models/ggml-base.en.bin \
    https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin
    # Kokoro, for a voice that doesn't sound like a satnav
    uv venv --python 3.12 .venv
    uv pip install --python .venv/bin/python mlx-audio "misaki[en]" fastapi uvicorn
  2. 2

    Start the three services

    They stay on the host, not in the container, so they keep their GPU acceleration.

    shell
    ollama serve
    whisper-server --model models/ggml-base.en.bin --port 8178 --host 127.0.0.1 --no-timestamps
    .venv/bin/python tools/kokoro_server.py --port 8179
  3. 3

    Give Tekki a Google account of its own

    Use a throwaway. It appears in calls under that account's name. Nothing in the repo reads, stores or transmits a password.

    shell
    cd bot && ./signin.sh # opens a browser at localhost:6080; sign in by hand
  4. 4

    A Telegram bot (optional)

    Only if you want to drive it from your phone. The Mac app talks to the bot directly and needs no token. Otherwise: talk to @BotFather, send /newbot, and put the token in bot/.env.

    bot/.env
    TELEGRAM_TOKEN=123456789:AA...
  5. 5

    Go

    Message your bot /start, then send it a Meet link. Admit it when it knocks.

    shell
    cd bot && docker compose up

Honest section

What it
can't do

  • Join a call by itself

    Somebody has to admit it.

  • Tell speakers apart

    No diarisation. Everyone is one voice to it.

  • See your screen

    It can draw on a board of its own, but a share, a slide or a face is invisible to it. It reads a page you photograph, not one you hold up.

  • Draw what it wasn't told

    The board is only as good as the model behind it. On a subject a small local model doesn't know, it will draw a confident, wrong diagram.

  • Be anonymous

    Google refuses automated anonymous clients, so it needs its own account.

  • Use your Google account

    OAuth grants API scopes; there is no Meet API for joining a call as somebody else. That door doesn't exist.

  • Wait its turn well

    It ignores the noises whisper invents out of silence, and acknowledgements while it's teaching. Everything else it hears, it answers: fine one-to-one, rude in a group.

Consent

Tekki joins under its own name, renders as an obvious cartoon robot, and doesn't attempt to look human. Anyone can see there's a bot in the call. Any feature that made it harder to notice would be the wrong feature.

Also in the repo

A native macOS app, from before the browser worked

SwiftUI, putting the avatar in a window for OBS to capture and speaking through BlackHole. It works, and it's how the avatar, brain and voice were built. Becoming a device inside the page removed two prerequisites and all the manual setup.

swift run understudy-window
swift run understudy-brain
swift run understudy-render

Put a participant in the call
that owes nothing to a cloud

Clone it, pull a 3B model, and message a bot a link. Everything it hears stays on the machine it runs on.