How Romeo learned to answer to its own name
Romeo ships a custom-trained Hey Romeo wake word, picks the right model format for your hardware, and hands your voice off to capture without extra clicks.

Romeo listens for its own name. The desktop app ships with a custom-trained "Hey Romeo" wake word instead of the stock phrases that come with open-source wake-word engines, so you can start talking to Romeo without touching the keyboard. The model is bundled inside the app in both ONNX and TFLite formats, and openWakeWord handles detection. A toggle in Settings under Preferences switches listening off completely, at the engine itself rather than only in the interface.
Every launch, the app writes four values to the agent backend's config: wake word enabled, openwakeword as the provider, the phrase "Hey Romeo", and the path to the bundled model. Before writing, it checks that the model file exists. The write runs every time, so the setup can never drift back to a generic wake word. Hearing the phrase does not open the mic by itself, so when the backend fires a wake.detected event, the app starts voice capture and flips the Record button to Stop.
Your hardware decides which model format loads. Apple Silicon Macs load the TFLite model, because openWakeWord's ONNX backend returns near-zero scores on macOS ARM64, a known upstream bug. Windows and Intel Macs use the ONNX file. The iPad companion view uses the same TFLite model through a separate Python detector. It reads 16 kHz mono audio in 80 ms frames and confirms a wake after two frames above a 0.6 score threshold, the same defaults the desktop listener uses.
Packaging caused the biggest snag. Electron bundles app files into an asar archive, and the wake-word engine runs as a separate process that can't read files inside it. The fix unpacks the wakewords folder at build time and resolves the model directory one way for packaged builds and another for source. A related bug appeared later on the iPad side: its detector looked for the model next to its own folder, which only works in source. Now the app passes the exact path through an environment variable, using the same directory logic.
More articles

Inside our resumable, review-gated video production pipeline
How we built a local seven-step pipeline that turns a history topic into a captioned video, with resumable state, bounded retries, and a human review gate.

How to build a thought-bubble tooltip with pure CSS
A step-by-step CSS tutorial for a tooltip that reads its label from a data attribute, pops up in a rounded bubble, trails off in three little circles and stays clickable, with no JavaScript.

Building night sky effects that know when to sit out
How the Night Sky UI Kit's star cursor, starfield and aurora check the visitor's device and settings before they draw a single frame.

How our pull requests get an automatic first review
A Cloudflare Worker picks up GitHub pull request webhooks, has Claude review the diff, submits a real GitHub review, and posts the notification into the correct Slack channel for pull requests.

How visitors book a call on our site
A look at the site's booking flow: a custom scheduling component, a small two-route API, and the checks that keep a 60-minute call from being double-booked.