gmux.ai/writing/feature inventory
Featured Research May 2026 · ~25 min

The complete feature inventory.

Every shipped feature, every in-flight feature, every paused feature, every abandoned feature — accurate as of May 2026. Read this before adding a feature; you'll likely find it already exists.

Why this article exists

After several research passes, the gmux ecosystem has grown faster than any single document captures. The PyPI package, the Tauri app, the Cloudflare Worker, the gesture engine, the voice daemon, the phone app prototypes, the desktop integration bridges, the MCP brain layer — they're all real, they all interact, and they all live in different repos.

This article is the complete map. Read it before adding a feature; you'll likely find it already exists. Read it before pitching the product; you'll find more is built than you remember.

The three repos

The "gmux project" is actually a federation of repositories that mirror each other through a manual sync pipeline:

RepoRoleWhen you edit here
gmuxtestActive dev sandboxEverything new lands here first
gmux-systemConsolidated authoritative sourcePromoted from gmuxtest after testing
gmux-ui-demoPublic UI (submodule)Sync target for the open demo

Plus three satellite repos:

RepoRole
gmux (original)Legacy Python terminal stack — partly superseded
gmux-brainMemory & intelligence MCP layer
gmux.aiLanding page + Cloudflare Worker backend

Part 1 · Shipped & working features

These features work today. If you launch gmux right now, you get all of these.

1.1 Terminal & tmux integration

The base layer. Everything else assumes this works.

Session management

Status bar — the main visible feature

Called by tmux every 1 second via pane_status.py. Three calling conventions handle different parts of the bar:

Status-left: A purple gmux brand badge with session name in bg=#6c5ce7.

Status-right (attention-only): !3 ●6 ✋ 📷 🎤 — window numbers showing permission, waiting, error states; plus service indicators (camera ✋ gesture 📷 voice 🎤).

Window tabs: Each tmux window renders as N:ICON tool_suffix name todo_sfx. Real example:

6:◉:bash ai diary 3/5

That tab is window 6, agent is working, running bash, project name is "ai diary", 3 of 5 todos done.

Seven state icons with strict colour rules

IconColourMeaning
GreenAI actively running tools or streaming
RedAI idle, waiting for next message
!OrangePermission needed
^!OrangeSub-agent (Task tool child) permission needed
BlueAI just finished
GreyBun running but no session yet
DimPlain shell, no AI
Red blinkHard error

Multi-pane priority

A tmux window can hold multiple panes (a fish shell next to a qalcode2 next to a logs tail). The tab shows the most urgent state across all panes. Priority order: error → permission → sub_permission → waiting → working → done → not_started → idle. This prevents the bug where a fish pane shows "idle" and hides the qalcode2 next to it that's waiting for permission.

tmux keybindings (all use Ctrl+A prefix)

BindingAction
prefix + NJump to next RED (waiting) AI pane
prefix + CToggle camera broker
prefix + VToggle voice bridge
prefix + SNew session with popup name prompt
prefix + rReload gmux status bar
prefix + ?Quick help in status bar
prefix + IFull help window
prefix + Ctrl+SSave session (tmux-resurrect)
prefix + Ctrl+RRestore session (tmux-resurrect)
Ctrl+GDisplay "gesture mode" message
Ctrl+Alt+VDisplay "voice mode" message

1.2 AI state detection — the killer feature

This is what makes the status bar meaningful. gmux doesn't pattern-match terminal output. It reads each AI agent's own state directly from its HTTP API.

SSE-based real-time event stream

One SSE listener thread per running qalcode2/opencode instance. Connects to http://127.0.0.1:{port}/event?directory={cwd} and reconnects every 5 seconds on disconnect.

Events monitored

SSE eventState transition
session.status type=busy→ WORKING
session.status type=retry→ ERROR
session.status type=idle→ WAITING
session.idle→ WAITING (legacy)
session.error→ ERROR
permission.updated→ PERMISSION (+ async parentID check for sub-agent flag)
permission.replied→ WORKING
message.part.updated type=tool status=running→ WORKING + sets current tool name
message.part.updated type=tool status=completed/errorclears current tool
todo.updatedupdates todo_done / todo_total

Agents supported

Port discovery

Bun starts opencode on a random local port. Discovery:

  1. pgrep -P <shell_pid> bun → bun process ID
  2. ss -tlnp | grep pid={bpid} → extract 127.0.0.1:PORT
  3. Two-level tree walk handles shell → bun (direct) and shell → sh → bun (fish shell)
  4. Cached 30 seconds per pane (handles bun restarts)

OpenCode 1.4 compatibility

All endpoints now require ?directory=<cwd> query parameter. monitor.py handles both old format (/session/status returns list) and new format (returns {sessionID: {type}} record).

Sub-agent (Task tool child) detection

When permission.updated fires, the monitor does an async HTTP GET /session/{sessionID} to check the parentID field. If present, this is a sub-agent and the tab displays ^! instead of !. You can see at a glance: is the main agent waiting for permission, or a child it spawned?

Aggregator thread (every 10 seconds per pane)

1.3 Gesture control

The browser-side gesture engine is fully working. Backend desktop bridges (KDE/GNOME/Hyprland) work but are opt-in.

MediaPipe hand landmarker

Eight static gestures (geometric classification)

GestureRule
OPEN_PALMAll 5 finger tips above MCP joints
FISTAll 5 finger tips below MCP joints
POINTIndex tip above MCP, others below
PEACEIndex + middle above, ring + pinky below
PINCHdistance(index_tip, thumb_tip) < threshold
THREEIndex + middle + ring above, pinky below
THUMBS_UPThumb tip is highest landmark, fingers curled
THUMBS_DOWNThumb tip is lowest landmark, fingers curled

Four motion gestures

Detected from wrist velocity averaged over 5 frames:

Hand role assignment

Confirmation model (anti-twitch)

Two modes

Mode switches via OPEN_PALM held 1.5 seconds.

Visual feedback

Dwell selection

Session pills register as dwell targets. Hold a fingertip over a pill for ~1 second; a fill bar animates from 0% to 100% width across the bottom of the pill, then selects. Useful for projector mode where you can't easily pinch.

Calibration

1.4 Voice control

Two voice paths, auto-selected based on what's available.

Path 1 · faster-whisper daemon (local, offline)

Path 2 · Web Speech API (browser native)

Wake words

kalarc, kal arc, cal arc, qalarc, qal arc, kalarck, kalark, calarc, kal-arc — multiple spellings handle STT variation. Longest match wins.

After a wake word: command routes to the active AI pane (priority: WAITING > WORKING > DONE > any AI).

Voice → tmux command map

Voice commands intercepted before reaching the AI:

SpokenAction
"next window" / "next"tmux select-window -n
"previous window" / "previous"tmux select-window -p
"split horizontal/vertical"tmux split-window
"close pane" / "close"tmux kill-pane
"zoom"tmux resize-pane -Z
"focus left/right/up/down"tmux select-pane direction
"new window"tmux new-window
"clear"send Ctrl+L
"cancel" / "stop"send Ctrl+C
"run" / "run it"send Enter
"run tests"type pytest -xvs then Enter
"next red" / "jump to waiting"jump to next waiting pane
"window 1"–"window 9"select window by number

Anything not matching the command map gets routed as a chat message to the focused AI agent.

Voice toggle methods

1.5 Phone remote

The HTTP server on :8768 serves a mobile-optimised PWA. The WebSocket on :8767 handles real-time control.

HTTP endpoints

MethodPathPurpose
POST/voice{text, window?} — send command/prompt
GET/statusPane states JSON
GET/phoneServes phone.html PWA
POST/permission/{pane_id}/respond{response: "once"|"always"|"reject"}
GET/manifest.jsonPWA manifest
GET/Redirect to /phone

WebSocket protocol

Phone → Desktop:

Desktop → Phone: welcome, status, pane_layout, ack, gesture_ack, pong

Pane layout API

Returns pixel rectangles for every visible tmux pane. Uses tmux list-panes for character positions plus xdotool search --name to find the terminal window's pixel dimensions. Falls back to 1920×1080 if xdotool unavailable.

Phone HTML prototypes

Three mobile design versions exist (v1 Terminal Dark, v2 Glass Cards, v3 Command Bridge). A v4 unified version is planned. None have been built as APKs yet — Capacitor is the planned build path but CLI not installed.

Volume key plan (for APK)

1.6 The Tauri desktop app

The desktop window that owns the terminal. Working in dev mode; production packaging paused.

Window architecture

LabelPurposeDefault
mainThe terminal window (1400×900)Visible
aquariumDecorative avatar window (900×600)Hidden
dashboardKnowledge dashboard (planned)Hidden

Dev URL: http://localhost:1421. App identifier: dev.gmux.test. Version: 0.1.0.

PTY implementation

Auto-started sidecars

The Tauri app spawns three Python processes on launch:

ScriptPortLabel
monitor.py8769gmux-monitor
gmux_voice_daemon.py8770gmux-voice
session_restore.py --daemongmux-saver

If a port is already bound, the sidecar is skipped (don't fight existing instances). start_with_retry() waits 1.5s, checks if the process died, then polls the port for up to 4 seconds.

State polling thread (1 Hz)

Reads multiple JSON files and emits events to all three windows simultaneously:

Wayland workaround

GDK_BACKEND=x11 required for Tauri on Wayland (WebKitGTK rendering issue). Set automatically in launch.sh.

1.7 The web UI (v3 — 6,700+ lines, single HTML file)

The interface that runs inside the Tauri WebView (or as a standalone browser app). Source of truth: gmuxtest/UI_creation_independent/v2/index.html.

Status bar source indicator

A small coloured dot at the bottom corner shows which data source is feeding the UI:

Agent grid

Chat panel (right sidebar)

Data source priority

  1. Tauri events (if window.__TAURI_INTERNALS__ present)
  2. HTTP+SSE on :8769 via EventSource
  3. HTTP polling every 2 seconds if SSE fails
  4. Mock evolution fallback (UI never looks broken even offline)

1.8 Camera architecture (v4l2loopback)

A real webcam can only be opened by one process at a time. gmux solves this with a virtual camera.

Physical webcam (/dev/video0)
       ↓
   cam-broker (ffmpeg mirror)
       ↓
Virtual cam (/dev/video2, v4l2loopback)
       ├── Browser gesture engine (getUserMedia)
       ├── Tauri calibration view
       └── Python gesture engine (if used)

Ownership rules (strictly enforced)

1.9 Multi-agent session management

Built on tmux-resurrect with substantial extensions.

Session save/restore

tmux-resurrect saves window layout and CWDs. gmux extends with:

Per-pane OpenCode session data

The aggregator captures, per pane, every 10 seconds:

1.10 The landing page (gmux.ai)

A static site plus a Cloudflare Worker handling votes, emails, and stats.

Worker URL

https://gmux-ai.fivelidz.workers.dev

Display counter formula

Real vote count is multiplied by ~3.2 with non-clean wobble + jitter:

display = real * 3 + floor(log(real+1) * 1.1) + (real*11+3) % 4

Drips toward target at 2 increments/hour via 15-minute cron. Always strictly increasing. Public API field named emails (not real) to obscure the formula.

Current stats (May 12, 2026)


Part 2 · Working but opt-in

These features work but are disabled by default. Enable them deliberately.

2.1 Desktop environment gesture bridges

The gesture engine emits events on a Unix socket (/tmp/gmux-gesture.sock). Three desktop bridges subscribe to it and translate gestures into native desktop actions.

KDE Plasma (via D-Bus)

GestureAction
open_palm + swipe_rightWalk Through Desktops (next)
open_palm + swipe_leftWalk Through Desktops (reverse)
open_palm + swipe_upShowDesktopGrid
open_palm + swipe_downShow Desktop (minimize all)
fistOverview
peaceWalk Through Windows

Hyprland (via hyprctl)

Gesturehyprctl dispatch
open_palm + swipe_rightworkspace e+1
open_palm + swipe_leftworkspace e-1
fisttogglefloating
peacefocusurgentorlast
thumbs_upfullscreen 0
thumbs_downmovetoworkspacesilent e+1
threefocusurgentorlast
pinchfullscreen 0

Cooldown: 800ms between any two desktop gesture actions (configurable). Prevents rapid double-fires.

2.2 Projector mode

Designed for use 2-3 metres from a wall projector. Demo exists; full integration in progress.

Activation: gmux start --projector

2.3 The aquarium window

A second Tauri window for decorative crab avatars (one per agent), animated to reflect each agent's state. Currently hidden by default — moved to "later" per user feedback ("drop the avatar system... I want clear documentation"). Code preserved in extras/avatar_system/.


Part 3 · The memory layer (gmux-brain)

Built. Documented. Not yet wired into production opencode.json. Highest-value 30-minute task in the entire portfolio.

3.1 The three-layer memory architecture

LayerTechUpdates whenAnswers
StructuralGraphify (AST + LLM)git commit hookWhat calls what, god nodes, architecture
EpisodicMemPalace (ChromaDB + SQLite KG)after sessionsWhy X was decided, when Y changed
Workspacegmux native (SSE)continuousWhat other agents are doing right now

3.2 MCP router

Stdio MCP server speaking protocol 2024-11-05. Routes queries to the right memory layer using keyword classification (no LLM call needed):

Query containsRoutes to
calls, imports, depends, god node, community, architecture, class, functionStructural
why did, why was, decided, when did, who, history, previous, last timeEpisodic
as of, valid, temporal, when was, timeline, fact, tripleKG (temporal)
agent, pane, running, blocked, active, workspaceWorkspace
AmbiguousBoth structural + episodic

3.3 Eight MCP tools

ToolPurpose
brain_querySmart-routed query
brain_contextFull assembled ~600-token project briefing
brain_graph_queryDirect Graphify query
brain_memory_searchDirect MemPalace semantic search
brain_memory_addStore a decision/fact
brain_kg_addAdd temporal triple (subject, predicate, object, date)
brain_kg_queryAll facts about an entity
brain_statusWhat's installed, indexed, current project

3.4 Context assembler

Generates a ~500-800 token context block that gets injected into each new agent pane via CLAUDE.md or AGENTS.md:

Written with <!-- gmux-brain:start/end --> markers for safe replace-in-place.

3.5 MCP configuration (when wired)

{
  "mcpServers": {
    "gmux-brain": {
      "type": "stdio",
      "command": "python3",
      "args": ["/home/fivelidz/projects/gmux-brain/src/router.py"]
    }
  }
}

Part 4 · Active development

Work in progress as of May 12, 2026.

4.1 Completed this session

4.2 High-priority pending

  1. Token rate sparklines — verify real data feeds into sparkline infrastructure
  2. Tool historypushToolEvent() not called from real SSE path, only mock; add to applyRealState
  3. Cost USD = 0 — decide path: wait for OpenCode fix, compute from token totals, or keep calcCostUsd() fallback
  4. Chat panel SSE subscription — currently refetches every render (rate-limited 3s), should subscribe to stream
  5. Live messages streaming — SSE for streaming chat responses into UI

Part 5 · Paused

These exist but are deliberately frozen.

5.1 Installer / packaging work — paused 2026-05-12

Frozen until five end-to-end criteria pass:

  1. ./scripts/launch.sh opens Tauri app cleanly on fresh shell
  2. Status sidebar shows live pane state from :8769
  3. Spawning an agent via UI creates a new tmux window + opencode
  4. Permission approve/reject from UI works against a real OpenCode session
  5. Voice (ws://localhost:8770) connects and transcribes into UI

Specifically not to be worked on:

An installer that installs something that doesn't run cleanly is worse than no installer. The installer is the first impression.

5.2 APK / Capacitor build

Three mobile HTML prototypes exist (v1 Terminal Dark, v2 Glass Cards, v3 Command Bridge). v4 unified version planned. Capacitor not installed.

5.3 WezTerm migration — research only

wezterm_investigate/ is a proof-of-concept folder. WeztermController class drafted but not integrated.


Part 6 · Abandoned

These were tried and explicitly rejected.

6.1 Option A — gmux-ghost (transparent overlay)

Abandoned in favour of Option B (full Tauri app). Reason: DOM-based pane borders couldn't align reliably with terminal pane positions; Wayland gives no API for finding another window's pixel coordinates; Web Speech API doesn't work in webkit2gtk on Linux.

6.2 Electron

Considered as desktop framework. Not pursued. Tauri + Rust is already the stack; Electron would duplicate Chromium + Node bundling.

6.3 THUMBS_DOWN gesture

The classifier rule was never implemented. The gesture literally never fires. Decision: remove from gesture map. The reject button stays clickable/pinchable in the permission UI, but the gesture binding is removed.

6.4 Fake canned replies

Removed in v3.1 refactor. Previously: fake "Processing your message..." and "Got it" responses. Now: real errors shown, no fabricated AI responses.

6.5 Avatar system (from main UI)

Extracted and archived. Reason: competed with state dot, status chip, and pane border glow for visual attention. Code preserved in extras/avatar_system/ for potential revival in the aquarium window.


Part 7 · Service topology reference

Every port, every IPC channel, every JSON file.

7.1 Network ports

PortServiceSource
1420Vite dev (legacy gmux-app)tauri
1421Vite dev (gmuxtest)vite.config.js
5550Browser UI serverlaunch-browser.sh
8765Voice daemon (legacy / aria-phone occupies)bridge.py
8767Phone bridge WebSocketbridge.py
8768Phone bridge HTTPbridge.py
8769gmux status monitor HTTP + SSEmonitor.py
8770gmux voice daemon (faster-whisper)gmux_voice_daemon.py
9000Overlay compositor (Option A archive)gmux.py
RandomEach opencode/qalcode2 bun instancediscovered
7840–7843gmux-brain MCP servers (planned)STRATEGY.md

7.2 IPC files

PathWriterReader
/tmp/gmuxtest-pane-state.jsonmonitor.py (2s)Tauri lib.rs, bridge.py, pane_status.py, jump_red.py
/tmp/gmuxtest-services.jsonmonitor.py + pane_status.pyTauri lib.rs, pane_status.py
/tmp/gmuxtest-window-names.jsonsession_restore.py (30s)monitor.py
/tmp/gmux-gesture.sockgesture/engine.pykde_bridge.py, hyprland_bridge.py
/tmp/ram_tracker_agents.jsonagent_feed.py (GTK)Tauri polls

Part 8 · The honest position

A clear-eyed summary for anyone considering gmux's place in the ecosystem.

8.1 What's genuinely unique

Combined, gmux has features that no other terminal tool has:

8.2 The qalcode2 overlap (honest)

Many "headline" gmux features are surfacing data that qalcode2 generates:

FeatureGenerated bySurfaced by
AI stateqalcode2 SSEgmux status bar / sidebar
Todo progressqalcode2gmux status bar / sidebar
Permission eventsqalcode2 SSEgmux orange ! indicator
Tool historyqalcode2 SSEgmux Hardware tab

What gmux uniquely adds:

qalcode2 is the single-agent executor; gmux is the multi-agent interaction layer.

8.3 The distribution gap

Everything is built. The codebase is large and capable. But:

The 30-minute action that would unlock the most value: register gmux-brain in opencode.json, wire graphify + kalarc-memory, restart the agent sessions, watch every pane get ~600 tokens of smart context for free. The 5-criterion checklist for installer resumption is well-defined and three of five are already green.

Article generated: May 12, 2026 from full codebase audit across 6 repositories. Source counts: 12 internal Markdown documents, 6 Python entry points, 1 Rust lib.rs (~1500 lines), 1 monolithic HTML UI (~6700 lines), 2 Cloudflare Worker source files. Every feature claim is traceable to source.