Skip to content

Repository files navigation

tmux-on-g2

English | 日本語

See your tmux session on Even Realities G2 smart glasses and talk back to it.

The web app mirrors a remote tmux pane onto the G2 display via the Even Hub SDK. Double-tap the temple to open the mic; speech is transcribed through a Whisper-compatible endpoint and piped into the pane with tmux send-keys. Native swipe on the temple scrolls; when you hit the top or bottom boundary, the app pages older/newer content in.

Built for ambient access to a long-running Claude Code (or any tmux-hosted TUI) session while away from the laptop.

Architecture

┌──────────── your host (tmux session) ────────────┐
│ tmux-g2-bridge (FastAPI, :18820)                 │
│   ├─ WS  /tmux   snapshot push + input receive   │
│   ├─ POST /asr   Whisper-compatible proxy        │
│   └─ GET /healthz                                │
└────────────────────┬─────────────────────────────┘
                     │  wss + https
┌────────────────────┴─────────────────────────────┐
│ Phone                                            │
│   Even Realities app → WebView (tmux-on-g2)      │
│     └ @evenrealities/even_hub_sdk                │
└────────────────────┬─────────────────────────────┘
                     │  Bluetooth 5.2
                ┌────┴─────┐
                │ Even G2  │
                │ 576×288  │
                └──────────┘

The app code runs on the phone as a WebView under the Even Realities companion app; only rendered frames and gestures cross the Bluetooth link. The bridge stays on your host, co-resident with the tmux server.

Prerequisites

  • Even Realities G2 + phone paired via the Even Realities app
  • An Even Hub developer account (free, for sideloading builds) — see docs
  • Node 18+ and npm on the dev machine
  • A Linux host with tmux, Python 3.10+, and systemd for the bridge
  • A Whisper-compatible ASR key (Groq default; OpenAI works too) unless you self-host
  • Phone reachable to the bridge at runtime — Tailscale is the easy option; LAN or tunneled public HTTPS also work

Quick start

Full walkthrough with troubleshooting lives in docs/SETUP.md. If you hit a specific error, docs/TROUBLESHOOTING.md has the symptom-first index.

1. Deploy the bridge

On the Linux host that owns the tmux session you want to mirror:

git clone <this-repo> tmux-on-g2
cd tmux-on-g2/bridge
sudo ./install.sh
# edit /etc/tmux-g2-bridge.env — fill ASR_API_KEY, set ALLOWED_TARGETS, TMUX_USER, etc.
sudo systemctl restart tmux-g2-bridge

Verify:

curl -s http://localhost:18820/healthz          # → ok
grep BRIDGE_TOKEN /etc/tmux-g2-bridge.env       # copy this token for the app

2. Run the app locally

cd tmux-on-g2                  # repo root
npm install
cp .env.example .env.local
# edit .env.local → point VITE_BRIDGE_URL at the bridge, paste VITE_BRIDGE_TOKEN
npm run dev                    # http://localhost:5173

Preview in the simulator (renders the glass display on your desktop):

npm run sim

3. Sideload onto real glasses

npm run build
npm run pack                   # produces tmux-on-g2.ehpk

Upload the .ehpk to the Even Hub developer portal. Flip the build's status from Private (draft) to Beta and add yourself as a tester — otherwise the tester invite link reports "テスト版の有効期限が切れました". Accept the invite promptly; links are time-limited.

After install, launch "Tmux Mirror" from the Even Realities app.

Controls

Gesture Action
Swipe up / down on the temple Scroll (native firmware-handled)
Swipe past top Page to older tmux lines
Swipe past bottom Snap back to live tail
Double-tap Toggle mic: first tap starts recording, second stops and transcribes

Repo layout

tmux-on-g2/
├── src/                          # Vite + TS web app
│   ├── config.ts                 # canvas size, rate limits, bridge URL/token
│   ├── tmux-stream.ts            # WS client (reconnect, input send)
│   ├── glass-render.ts           # SDK bridge wrapper + CC chrome trim heuristic
│   ├── asr.ts                    # PCM buffering, WAV, RMS-VAD, hallucination filter
│   ├── input-control.ts          # gesture + audioPcm event parsing
│   └── main.ts                   # boot, wiring
├── bridge/                       # Python bridge for the tmux host
│   ├── bridge.py                 # FastAPI app
│   ├── bridge.env.example
│   ├── tmux-g2-bridge.service    # systemd unit
│   ├── requirements.txt
│   └── install.sh
├── app.json                      # Even Hub manifest
├── vite.config.ts
└── docs/
    ├── SETUP.md                  # step-by-step install + first run
    ├── ARCHITECTURE.md           # data flow in detail
    ├── SDK-NOTES.md              # Even Hub SDK invariants, gotchas, resolved traps
    └── TROUBLESHOOTING.md        # symptoms → fixes

Configuration

Web app (.env.local)

Var Meaning
VITE_BRIDGE_URL WebSocket URL of the bridge, e.g. ws://100.x.y.z:18820/tmux
VITE_BRIDGE_TOKEN Value of BRIDGE_TOKEN from /etc/tmux-g2-bridge.env

Bridge (/etc/tmux-g2-bridge.env)

See bridge/bridge.env.example. Key settings:

  • BRIDGE_TOKEN — shared secret
  • ALLOWED_TARGETS — comma-separated tmux session names the bridge will mirror
  • TMUX_USER — OS user that owns the tmux server (bridge runs as root and uses sudo -n -u <user>)
  • ASR_BASE_URL / ASR_API_KEY / ASR_MODEL — any OpenAI-compatible transcription endpoint

Security notes

  • The bridge accepts bearer tokens via Authorization header or ?token= query param, compared with secrets.compare_digest.
  • ALLOWED_TARGETS gates which tmux sessions the WS endpoint will capture from; requests for other sessions are rejected.
  • The web app's .env.local token is embedded in the Vite bundle at build time (Vite rule). That bundle ships inside the .ehpk to your own device. Treat the token like an API key — rotate if you share or publish the build.
  • The bridge has no rate limiter on /asr; add one before exposing publicly.
  • Bind the bridge to 127.0.0.1 + put it behind tailscale serve (or equivalent) for TLS termination if reaching it over the public internet.

Hardware and SDK constraints

See docs/SDK-NOTES.md for the full list of Even Hub SDK 0.0.7 invariants the app was designed around. Highlights:

  • 576×288 per eye, 4-bit greyscale, single LVGL firmware font — no font size API
  • Max 1000 chars (startup) / 2000 chars (upgrade) per text container, ~400–500 chars fill the screen
  • Gesture enum: click / double-click / swipe-top / swipe-bottom / foreground toggles; long-press is reserved by "Even AI"
  • Audio: raw 16 kHz 16-bit LE mono PCM only; the companion app's built-in ASR is not exposed to apps

Contributing

See CONTRIBUTING.md. PRs welcome — especially on Japanese Whisper accuracy, other TUI chrome heuristics (shells beyond Claude Code), and image-container rendering for custom font sizes.

License

MIT. See LICENSE.

About

Stream a tmux pane to Even Realities G2 smart glasses with double-tap voice input.

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages