Pluggable local-agent platform for Even Realities G2 smart glasses
Website · Get started · Systems map · Documentation
For the full plan and design see planning.md and architecture.md. New here? The interactive Setup & Connect app (source) walks through setting up CI Companion, signing in with Companion Intelligence, and connecting a Companion Hub in three steps (developer preview: the app is not in the Even Hub store yet).
![]() Even Realities HUD ready state |
![]() Even Realities settings |
![]() Chat response displayed in the glasses app |
The CI Companion phone WebView — the control surface paired with the G2 glasses. Voice-first: tap the mic or long-press the G2 touchbar, and answers stream onto the glasses HUD (mirrored in the Glasses display preview).
It ships on the Companion Intelligence design system — sage --primary (#c5e8dc), Manrope. As a heads-up display it is dark-only: a single surface pinned to color-scheme: dark, tuned for the Even Realities G2 phosphor aesthetic. There is no light theme by design, so every screen below is captured on the one dark surface.
The WebView has two tabs — Chat and Settings — plus two HUD overlays (permission prompts, mid-stream frames) that only render inside the native Even Hub runtime. Screens below are captured headlessly from the production Vite build (npm run build + serve), so they reflect exactly what ships.
The default tab and landing surface. Shows the CI Companion mark, quick-prompt suggestion chips (What time is it?, Quick weather, Read me my next event, Set a 5-min timer, Define a word), the live Glasses display preview that mirrors the G2 HUD, and the mic dock at the bottom. The status bar reports glasses-connection state and the active model.
The configuration tab. The Account card offers Sign in with Companion Intelligence (CI-Portal OIDC) and shows the signed-in identity; the CI-Hub card is a one-tap quick-connect (Ollama / Hermes / OpenClaw) derived from your Hub base URL. Below them, the AI Backend card selects the Backend Kind (Local LLM, OpenAI-like, Claude Code, Codex CLI, OpenClaw) and holds Backend URL, API Key, Model, API Mode, and Streaming, followed by the System Prompt, Speech-to-Text, Text-to-Speech, and Reset sections. Token/session state persists through device-backed bridge storage (localStorage in the simulator). The sage --primary accent marks the active tab and the selected backend card.
Two more surfaces render on top of the Chat tab but cannot be captured headlessly — they are gated on the live Even Hub SDK bridge (waitForEvenAppBridge), which only resolves inside the Even Hub app or its simulator:
- Permission prompt (
?screen=prompt) — the approve/deny card the HUD shows when a hub-routed agent (Claude Code / Codex / OpenClaw) requests a tool. Ring double-tap approves, single-tap denies (deliberate: an accidental brush of the touchbar must never approve an agent action). - Mid-stream frame (
?screen=stream) — a live answer streaming onto the G2 display, which additionally needs a reachable AI backend.
In a plain headless browser the bridge never resolves, so both deep-links fall through to the Chat tab shown above. These are documented here rather than screenshotted so nothing on this page is fabricated; capture them from the Even Hub simulator when a HUD reference is needed.
- Interface
- What this is
- Architecture overview
- Quick start
- Voice pipeline
- AI backend compatibility
- Glasses display
- Project structure
- Further reading
| Feature | What it provides |
|---|---|
| Glasses UI | Render chat and HUD surfaces inside Even Hub's mobile WebView. |
| Device bridge | Use Even Hub's JavaScript bridge for display, microphone and BLE audio. |
| Streaming backends | Select compatible OpenAI-style chat or Responses APIs. |
| Voice loop | Stream response text/audio back through the native runtime. |
ci-even-realities is an Even Hub app for the Even Realities G2 smart glasses, plus a sibling agent-hub/ Node service that brokers local agents.
flowchart LR
press["G2 touchbar<br/>long-press"] --> mic["MicCapture"]
mic --> stt["Whisper STT"]
stt --> adapter["ApiAdapter"]
subgraph hub["agent-hub (LAN, optional)"]
direction TB
openai["openai"]
localllm["local-llm"]
claudecli["claude-cli"]
codexcli["codex-cli"]
openclaw["openclaw"]
end
adapter --> hub
localllm -.-> ollama["Ollama / Hermes"]
claudecli -.-> claude["Claude Code"]
codexcli -.-> codex["Codex CLI"]
openclaw -.-> gateway["OpenClaw Gateway"]
hub -- SSE stream --> renderer["GlassesRenderer"]
renderer --> display["G2 display"]
hub -. "permission_prompt cards<br/>ring double-tap = approve · tap = deny" .-> display
The glasses app stays a thin OpenAI SSE client. All agent-specific glue lives in agent-hub/. Point Backend URL at the hub, set Backend Kind in Settings, you're done.
The app runs as a standard web page inside the Even Hub iOS/Android app, or in any modern browser (simulator / dev mode).
Even Hub hosts the web UI in a mobile WebView and exposes a JavaScript bridge to the glasses; the selected chat backend streams text or audio back through the same bridge.
flowchart LR
App[CI glasses web app] --> WebView[Even Hub WebView]
WebView <--> Bridge[Even JavaScript bridge]
Bridge <--> Glasses[Display, mic and BLE audio]
App --> Backend[OpenAI-style backend]
Backend --> App
See docs/architecture.md for the full deep-dive. The high-level layers are:
| Layer | File(s) | Responsibility |
|---|---|---|
| Entry point | src/Main.ts |
Bootstrap, SDK bridge wiring, gesture routing |
| AI adapter | src/ai/ApiAdapter.ts |
Auto-selects Chat Completions vs Responses API |
| Chat Completions | src/ai/ChatCompletions.ts |
/v1/chat/completions, client-side history |
| Responses API | src/ai/ResponsesApi.ts |
/v1/responses, server-side context |
| SSE parser | src/ai/StreamParser.ts |
Parses text/event-stream chunks |
| Audio capture | src/audio/MicCapture.ts |
WebAudio mic recording via Even Hub SDK |
| LC3 decode | src/audio/LC3Decoder.ts |
Converts G2 BLE audio frames to PCM/WAV |
| TTS | src/audio/TTSPlayer.ts |
Web Speech TTS playback through phone speaker |
| Whisper STT | src/stt/WhisperSTT.ts |
/v1/audio/transcriptions (Whisper-compatible) |
| Web Speech STT | src/stt/WebSpeechSTT.ts |
Browser Web Speech API (fallback) |
| Glasses renderer | src/glasses/GlassesRenderer.ts |
Word-wrap + paginate text for 488 px display |
| Settings | src/config/Settings.ts |
localStorage-persisted BackendConfig |
| UI | src/ui/ |
ChatView, SettingsView, StatusBar, CSS |
| Tool | Install command |
|---|---|
| Node.js ≥ 18 | nodejs.org |
| Even Hub CLI | sudo npm install -g @evenrealities/evenhub-cli |
| Even Hub Simulator | sudo npm install -g @evenrealities/evenhub-simulator |
| Vite (global, optional) | sudo npm install -g vite@latest |
cd ci-glasses-app
npm installnpm run dev
# Listening on http://0.0.0.0:5173In a second terminal:
evenhub-simulator http://<YOUR_LAN_IP>:5173The simulator opens a browser window that mirrors what the Even Hub mobile app renders.
Open the Settings tab. Two fast paths:
- Account → Sign in with Companion Intelligence runs the CI-Portal OIDC flow
(Authorization-Code + PKCE). The returned access token is used for backend
calls and refreshes itself — no API key to manage. Issuer / client / scope are
configurable under Advanced (defaults: issuer
https://hub.ci.computer/api/auth, clientci-even). - CI-Hub quick-connect — set your Hub base URL, then tap Ollama, Hermes, or OpenClaw to fill the backend fields with the standardized CI-Hub endpoints.
Or configure the AI Backend card manually:
| Field | Default | Description |
|---|---|---|
| Backend URL | http://localhost:8080 |
Base URL of any OpenAI-compatible server |
| API Key | ci-local-key |
Bearer token (ignored once you sign in with OIDC) |
| Model | ci-companion |
Model name forwarded to the backend |
| API Mode | auto |
auto probes the server; or force completions / responses |
| STT Provider | whisper |
whisper (server-side) or webspeech (browser) |
| TTS | off | Speaks responses through phone speaker |
npm run build # outputs dist/Upload dist/ to the Even Hub portal or use the CLI:
evenhub-cli publish dist/1. Long-press G2 touchbar → MicCapture.startCapture()
2. Release → MicCapture.stopCapture() → ArrayBuffer (WAV)
3. WhisperSTT.transcribe() → POST /v1/audio/transcriptions
4. ApiAdapter.sendMessage() → POST /v1/chat/completions OR /v1/responses
5. SSE stream → GlassesRenderer.displayStreaming()
6. Ring tap → nextPage() / prevPage()
7. Ring double-tap → clearHistory()
See docs/architecture.md for sequence diagrams and the full flow.
The ApiAdapter supports both OpenAI API generations:
| API | Endpoint | Notes |
|---|---|---|
| Chat Completions | POST /v1/chat/completions |
Client-side history, messages[] |
| Responses API | POST /v1/responses |
Server-side context, store: true |
In auto mode the adapter sends an OPTIONS /v1/responses probe. If the backend responds with 2xx or 405, the Responses API is used; otherwise it falls back to Chat Completions.
See docs/api-compatibility.md for migration details and payload examples.
The G2 display is a 640 × 350 px MicroLED (green-on-black). The renderer uses:
- 488 px usable text width
- 21 px font size → ≈ 42 characters per line
- 5 lines per screen (page)
Long responses are automatically word-wrapped and paginated. Navigation is via the G2 ring (single tap = next page, double tap = clear).
See docs/glasses-display.md for full display spec details.
The glasses app's Settings panel now exposes a Backend Kind selector. Each kind tells the app what to expect on the wire and (for hub-routed kinds) which adapter the hub will load.
| Kind | Where it runs | Notes |
|---|---|---|
openai |
Any OpenAI-compatible URL | Today's default. Hub optional. |
local-llm |
Ollama / vLLM / llama.cpp on LAN | Hermes-3 / Hermes-4 GGUFs land here. |
claude-cli |
agent-hub spawning Claude Code |
Supports permission_prompt events; ring double-tap approves, single tap denies. |
codex-cli |
agent-hub spawning Codex CLI |
Same permission flow as Claude. |
openclaw |
agent-hub forwarding to OpenClaw Gateway |
Node port of the dAAAb Cloudflare bridge. |
See agent-hub/README.md for env vars and adapter details.
ci-even-realities/
├── README.md ← you are here
├── architecture.md ← system design with mermaid charts
├── planning.md ← workstreams, milestones, decisions log
├── ROADMAP.md ← next steps for testing and development
├── agent-hub/ ← Node service brokering Claude/Codex/OpenClaw/local-LLM
│ ├── README.md
│ └── src/
│ ├── server.ts
│ ├── router.ts
│ ├── sse.ts
│ ├── events.ts
│ ├── sessions.ts
│ └── adapters/
│ ├── Adapter.ts
│ ├── passthrough.ts
│ ├── claudeCli.ts
│ ├── codexCli.ts
│ └── openclaw.ts
├── docs/
│ ├── architecture.md ← system architecture deep-dive
│ ├── api-compatibility.md ← Chat Completions vs Responses API
│ ├── dev-setup.md ← complete developer environment guide
│ ├── glasses-display.md ← G2 display spec and rendering details
│ ├── ci-pipeline.md ← hand-maintained: what each GH Actions workflow does + gh commands
│ └── CI.md ← generated (do not hand-edit): why triggers are gated, canonical dispatch commands
├── notes/
│ ├── even-realities-resources.md ← links, community notes, SDK tips
│ └── openai-api-transition.md ← Chat Completions → Responses API transition notes
├── er-connect/ ← public "Setup & Connect" page, deployed to er.ci.computer (Cloudflare Worker)
└── ci-glasses-app/ ← Even Hub app source
├── index.html
├── app.json
├── package.json
├── vite.config.ts
├── tsconfig.json
└── src/
├── Main.ts
├── ai/
│ ├── ApiAdapter.ts
│ ├── ChatCompletions.ts
│ ├── ResponsesApi.ts
│ └── StreamParser.ts
├── audio/
│ ├── LC3Decoder.ts
│ ├── MicCapture.ts
│ └── TTSPlayer.ts
├── config/
│ └── Settings.ts
├── glasses/
│ └── GlassesRenderer.ts
├── stt/
│ ├── STTEngine.ts
│ ├── WebSpeechSTT.ts
│ └── WhisperSTT.ts
└── ui/
├── ChatView.ts
├── SettingsView.ts
├── StatusBar.ts
└── styles.css
| Resource | Link |
|---|---|
| Even Hub (portal and docs) | https://hub.evenrealities.com/ |
| Even Hub developer console (upload; needs an Even Realities developer login) | https://hub.evenrealities.com/hub |
| Even Hub SDK (npm) | https://www.npmjs.com/package/@evenrealities/even_hub_sdk |
| Even Hub CLI (npm) | https://www.npmjs.com/package/@evenrealities/evenhub-cli |
| Even Realities design guidelines (Figma) | https://www.figma.com/design/X82y5uJvqMH95jgOfmV34j/ |
| CI Server (backend) | https://github.com/companionintelligence/ci-server |
| OpenAI Responses API docs | https://platform.openai.com/docs/api-reference/responses |
| OpenAI Chat Completions docs | https://platform.openai.com/docs/api-reference/chat |
| Even G2 community notes | https://github.com/nickustinov/even-g2-notes/tree/main |
| Awesome Even Realities G1 | https://github.com/galfaroth/awesome-even-realities-g1 |
| Setup & Connect page | er-connect/ — deploys to er.ci.computer |
| CI pipeline reference | docs/ci-pipeline.md — what each workflow does + gh commands |
| Surface | Where it runs |
|---|---|
| Chat and settings | Web application and simulator/dev workflow |
| HUD overlays | Native runtime only, as called out in the feature section |
| Voice pipeline | Uses the selected compatible AI backend |
| Even Hub upload | Production build/upload path |
The simulator is useful for UI iteration, but it does not validate native HUD overlays or actual glasses behavior. Validate those through the native runtime and device-specific workflow documented below. Keep backend credentials in local configuration.




