Halo
A minimal AI assistant that floats over your screen. It listens to the conversation, sees what's on your screen, and gives you a short suggestion in the moment: what to say or do. Halo is a from-scratch rewrite of the idea behind sohzm/cheating-daddy, with no bundler, no vendored libraries, and support for any OpenAI-compatible model.
What's new
| Cheating Daddy | Halo | |
|---|---|---|
| Models | Gemini Live / Groq / OpenAI / local: four separate code paths | One OpenAI-compatible client: Gemini, Groq, OpenAI, OpenRouter, Ollama, LM Studio, or your own server |
| Speech | WebSocket stream to Gemini Live | VAD + Whisper-compatible API (Groq, OpenAI, or a local whisper.cpp / faster-whisper) |
| Screen | Screenshot on a timer | Continuous capture with a change detector and a rolling buffer of keyframes |
| Recording | None | Optional screen recording straight to disk as .webm |
| Security | nodeIntegration: true, no isolation | contextIsolation, sandbox, strict CSP, every IPC call validated, API keys encrypted by the OS |
| Code | ~11,700 lines plus vendored libraries | ~3,100 lines, 0 runtime dependencies, no build step |
| Tests | None | 27 unit tests (npm test) |
New: Rewind ⏪(v 2.1)
Zoned out and lost the thread? Press Ctrl+Shift+Enter (or the button in the panel). Halo takes the transcript from the last 30 seconds to 5 minutes, plus a few screen keyframes, and answers in three lines:
- What happened: 2–3 bullets.
- What they need from you now: what exactly is being asked of you.
- What to say: a ready-made line.
Here's how it works:
getDisplayMedia ─▶ hidden <video> ─▶ every N ms: compare a 96×54 grayscale copy
│ │
│ (optional) ▼ did the screen change and then settle?
└▶ MediaRecorder ─▶ .webm on disk keyframe ─▶ Rewind buffer (3 min by default)
Only meaningful frames make it into the buffer: no duplicates, and nothing from the middle of an animation. The model gets a clean storyboard instead of a hundred identical screenshots. You can also pin frames in the Rewind panel, and they'll be sent along with your next question.
Everything else
- Two audio channels: the other side (system audio) and you (microphone), labeled "Them" and "You". In "Both" mode, microphone lines are suppressed while the system channel has speech, so your speakers don't echo the other person under your name.
- Auto-answer: when Halo detects a question in the other side's speech, it prepares a suggestion on its own.
- History and recaps: every session is saved (transcript plus suggestions). The Recap button has the AI write a summary with action items, and you can export it all to Markdown.
- Profiles: interview, meeting, sales, negotiation, presentation, study.
- Customizable shortcuts, opacity, font size, and click-through mode.
- One-click connection test for both the model and speech recognition.
Quick start
You'll need Node.js 20 or newer and Python 3.11+.
git clone https://github.com/stormydayy/halo-overlay
cd halo-overlay
npm install
npm start- Settings → Model: pick a provider and paste your key (Gemini, Groq, OpenAI, …). Click "Test connection".
- Settings → Speech recognition: Groq Whisper is a good start (it has a free tier, and you can reuse the same Groq key).
- On the home screen, choose a profile, add some context (resume, job description, notes) and click Start session.
The default model names are just sensible starting points, and they go out of date fast. The Model field is free text, so use whatever name your provider's docs currently list.
Fully local
- LLM: Ollama with the "Ollama (local)" preset and a vision-capable model (for example
llama3.2-vision). - Speech: any server that exposes
/v1/audio/transcriptions(whisper.cpp server, faster-whisper-server) with the "Local server" preset.
Local addresses (localhost, 192.168.*, 10.*) don't need an API key.
Shortcuts
These work globally. You can change them in Settings.
| Action | Windows / Linux | macOS |
|---|---|---|
| Answer now | Ctrl+Enter | ⌘+Enter |
| Rewind (what did I miss) | Ctrl+Shift+Enter | ⌘+Shift+Enter |
| Show / hide window | Ctrl+\ | ⌘+\ |
| Click-through | Ctrl+M | ⌘+M |
| Move window | Ctrl+arrows | ⌥+arrows |
| Wipe data | Ctrl+Shift+E | ⌘+Shift+E |
Audio capture by platform
| OS | System audio | Microphone |
|---|---|---|
| Windows | Loopback via getDisplayMedia | Yes |
| macOS | SystemAudioDump helper (from the original project) | Yes |
| Linux | Loopback if your environment supports it; otherwise microphone only | Yes |
If system audio isn't available, Halo tells you and carries on with the microphone and screen.
On macOS, grant Screen Recording and Microphone access under System Settings → Privacy & Security.
Privacy
- API keys are encrypted with your OS (
safeStorage: DPAPI / Keychain / libsecret) and are never sent to the UI. - Data only goes to the providers you've configured: short audio clips go to the speech recognition service, and text (plus screenshots, if enabled) goes to the model. Nothing phones home.
- Sessions and recordings are stored locally in the app's profile folder (the path is shown under History). "Delete all sessions and recordings" and
Ctrl+Shift+Eerase them. - Screen recording is off by default.
Disclaimer
Halo is a conversation aid, a bit like a stage prompter. Rules vary: many interviews, exams, employers and platforms prohibit outside help or recording, and laws on recording conversations differ from country to country. Check the rules wherever you use it, and tell the other people involved if the law or basic ethics call for it.
Project structure
src/
├── main/ main process (Node)
│ ├── index.js window, shortcuts, IPC
│ ├── ai.js OpenAI-compatible client: streaming chat + speech recognition
│ ├── prompts.js profiles and message building (answer / rewind / recap)
│ ├── schema.js settings schema, validation, presets (pure module)
│ ├── store.js settings on disk + key encryption
│ ├── sessions.js session history; markdown.js handles export
│ ├── recorder.js streaming .webm recording to disk
│ └── macAudio.js macOS system audio (SystemAudioDump → 16 kHz mono)
├── preload.js narrow contextBridge: the only link to the UI
└── renderer/ UI (ES modules, no build)
├── main.js session, Rewind, AI requests, navigation
├── lib/capture.js screen capture, change detector, frame buffer, recording
├── lib/audio.js audio sources → VAD → WAV → speech-to-text
├── lib/vad.js speech segmentation + WAV encoder
├── lib/session.js session state, question detector
├── lib/md.js safe markdown renderer
└── views/ settings, history
test/ 27 tests (node:test): validation, SSE streaming against a mock server, VAD, DSP, …
Development
npm start # run the app
npm run dev # run with DevTools
npm test # unit tests (no Electron needed, ~1 s)
npm run check # syntax check on every file
npm run format # prettier
npm run dist # build installers with electron-builder (output in dist/)There's no build step: the sources run as they are. electron-builder is only needed for installers.
Known limitations
SystemAudioDumpin this repo is built for Apple Silicon (arm64). System audio won't work on Intel Macs until you build the helper yourself from the source.- Speech recognition works in chunks split at pauses (typically a 1–3 second delay), not as a continuous stream. That's the price of being provider-independent.
- The question detector is a heuristic, so false positives happen. That's why auto-answer is off by default.
License and credits
GPL-3.0. The idea and the macOS audio helper come from sohzm/cheating-daddy and Mohammed-Yasin-Mulla/Sound.