Even Realities G1 — Build notes

BLE takeover architecture, display constraint discovery, Claude Code integration pipeline, display modes, and Mac companion app — seven sections on replacing the phone.

01 — Context

The companion app is not a companion.

Even Realities ships the G1 with a phone app that owns the glasses. Notifications pass through it. Weather passes through it. The AI assistant passes through it. The phone is always in the loop — which means the glasses are never independent.

The premise of this build: replace the companion app entirely with a desktop-hosted runtime that owns the G1 over BLE. The glasses become a direct surface for whatever system is running on the machine — not a phone peripheral that happens to have a display.

The north star is specific: the glasses answer “when can I give feedback or guidance?” — not a clock/weather clone. Claude Code is the lead integration. The glasses show live tool progress, stop notifications, and session state without touching the phone or switching windows.

02 — The Constraint

Forty characters. Five lines. Green.

The G1 display is monochromatic green, roughly 488 pixels wide. That gives you approximately 40 characters per line and 5 lines per screen. No scrolling. No font weight variation. No color. Whatever you show has to be readable in under 300 milliseconds or it is not useful — the display sits in peripheral vision at a 20° field of view.

Interaction is limited to voice and a small touch surface on the temple arm. There is no tap target, no scroll gesture, no pointer. Most UI patterns do not transfer. The question is what does — and what should never appear in the window at all.

The hardware also splits: left and right arms are separate BLE connections. Both must be paired and synchronized. Send to left first, wait for ACK, then right. A naive sequential write takes 1.6 seconds — unusable for glanceable content that needs to appear instantly.

40chars

Line width

Maximum characters per line on the monochromatic green display.

5lines

Screen depth

Total visible lines — no scrolling, no paging.

20°FOV

Field of view

Peripheral vision — readable in under 300ms or not useful.

2arms

Dual BLE

Left and right are separate connections — both must sync.

03 — The D0 Probe

Co-opt. Don’t suppress.

The first assumption was wrong. The stock firmware HUD (time, weather, date) cannot be fully hidden. The hide_dashboard command only repositions it — it does not suppress. This was discovered empirically in the first device probe, and it changed the entire display strategy.

The pivot: instead of fighting the firmware layer, co-opt it. Feed the stock HUD with custom data via the 0x06 BLE command — your own time format, your own weather string. Set it to minimal mode so it takes as little space as possible. Then dominate the “Even AI” canvas (the second display layer) for all collaboration content.

This produces a two-layer model: firmware HUD for ambient context (the bottom of the display), custom canvas for active content (tool progress, stop notifications, session state). The layers coexist rather than compete.

Three-ring takeover

Ring 1: Own the companion connection (BLE pairing, bypass phone). Ring 2: Own the display (firmware co-option + custom canvas). Ring 3: Own the experience (attention tiers, context routing, voice).

Dual-layer display

Firmware HUD: ambient (clock, weather, battery) via 0x06. Custom canvas: active content (tool progress, notifications, state) via send_text/send_result. Co-existence, not competition.

04 — The Build

Glasses as a coding surface.

The runtime is a Python FastAPI daemon running on macOS. It maintains persistent BLE connections to both arms, exposes an HTTP API for integrations, and manages display state through a mode machine: idle home, tool progress, stop notification, tilt dashboard.

Claude Code hooks are the primary integration. A on-tool hook fires on every tool use — file reads, edits, shell commands — and pushes live progress to the glasses. A on-stop hook fires when the agent stops and needs input. The glasses show a summary frame: task count, tool count, and a “your turn” indicator. No window switching required.

The BLE transport was the hardest infrastructure problem. Stock sequential writes took 1.6 seconds per frame — unusable for tool progress that fires multiple times per second. The solution: parallel dual-arm writes that push content to both arms simultaneously, reducing latency to ~150ms. Content-hash deduplication skips writes when the display already shows the correct frame.

01Hook

Claude fires event

on-tool or on-stop posts JSON to the local daemon.

02Format

40-char layout

Word-wrap, truncate, pad to the active display anchor position.

03Hash

Dedup check

SHA-256 content hash — skip BLE write if display is current.

04Push

Parallel BLE

Dual-arm write in ~150ms (vs 1.6s sequential).

05Display

Glance frame

Tool name + status on the 40×5 canvas. Readable at a glance.

06Tilt

Dashboard on gesture

Head-up triggers clock + weather + session state overlay.

05 — Display Modes

Three stances for attention.

The display state machine has three primary layout modes, selectable via configuration:

Collaboration

Readiness-first. Shows “G1 OS” header, last action with time-ago label, session stats (tasks/tools). The idle state answers: is anything happening, and do I need to look?

Zen

Single word when idle. Nothing else. For deep work where the glasses should disappear until an interrupt arrives.

Dev

Inline tool progress — every file read, every edit, every shell command streams to the display as it happens. For pairing sessions where you want full visibility.

Active frames override all modes: tool progress shows a spinner animation with the current tool name (>> Edit, ✓ Read file.py, ✗ Edit). Stop notifications show a summary frame with an ASCII progress bar, task count, and “your turn” indicator. Head-tilt triggers a dashboard overlay regardless of mode.

06 — Mac Companion

The control surface the phone app isn’t.

A native macOS app replaces the phone companion for display configuration. The Even app uses a vertical “ladder picker” (positions 0–8) for display height — the Mac app mirrors this mental model exactly, then extends it with controls the phone app doesn’t expose: head-up angle (0–60°), display depth (1–9), text anchor position, and alignment.

Display geometry changes use a two-step preview/apply flow matching the Even app’s pattern — because the glasses physically adjust the display position and the user needs to confirm it feels right before committing. Brightness is a direct slider (0–41) with an auto-brightness toggle.

The app also surfaces daemon health: BLE connection state (per-arm), Claude session activity, current display mode, and last push timestamp. A live activity card shows the same state the glasses show — useful for debugging layout without wearing the device.

07 — What’s Still Open

The hard problems are not display.

Display is solved enough to be useful. The open problems are higher up the stack:

Attention tiers

Not everything deserves a glance. The system needs to distinguish interrupt (you must look now) from ambient (it’s there if you look) from quiet (suppressed until asked). Currently everything is “always notify.”

Voice input

The G1 mic sends LC3-encoded audio from the right arm only — not raw PCM. Decoding requires liblc3 before Whisper can transcribe. Voice commands would close the loop: glasses show state, voice responds without hands.

Context at glance-scale

40 characters is enough for “Edit: server.py” but not for “why.” The current system shows what is happening. Showing whether you should care requires inference the display layer doesn’t have yet.

Failure at speed

Wrong at glance-scale is worse than no output. If the model generates something incorrect and you trust it because you only glanced — that’s a harder failure than a phone screen where you have time to verify.