Skip to main content
Termix is a local Node.js application with a browser-based frontend. This page explains the key architectural decisions for anyone who wants to understand what’s happening behind the scenes.

System Overview

┌─────────────────────────────────────────────────┐
│                   Browser                        │
│  ┌─────────────┐  ┌──────────┐  ┌────────────┐  │
│  │  Sidebar     │  │ Terminal  │  │  Settings   │  │
│  │  (sessions,  │  │ (xterm.js)│  │  Panel      │  │
│  │   search)    │  │           │  │             │  │
│  └──────┬───────┘  └─────┬────┘  └──────┬──────┘  │
│         └────────────┬───┘──────────────┘          │
│                      │ WebSocket                    │
└──────────────────────┼─────────────────────────────┘

┌──────────────────────┼─────────────────────────────┐
│              Node.js Server (:4000)                 │
│                      │                              │
│  ┌───────────────────┴────────────────────────┐    │
│  │           WebSocket Handler                 │    │
│  │  (message routing, config, telemetry setup) │    │
│  └──────┬─────────┬──────────┬────────────────┘    │
│         │         │          │                      │
│  ┌──────┴───┐ ┌───┴────┐ ┌──┴──────────┐          │
│  │ Sessions  │ │ Config │ │ Transcript   │          │
│  │ (PTY mgmt)│ │ (CRUD) │ │ (JSONL store)│          │
│  └──────┬───┘ └────────┘ └─────────────┘          │
│         │                                           │
│  ┌──────┴──────────────────────────────────┐       │
│  │         PTY Processes (node-pty)         │       │
│  │  ┌─────────┐ ┌─────────┐ ┌──────────┐  │       │
│  │  │ claude   │ │ codex   │ │ gemini   │  │       │
│  │  └─────────┘ └─────────┘ └──────────┘  │       │
│  └─────────────────────────────────────────┘       │
│                                                     │
│  ┌──────────────┐  ┌────────────────┐              │
│  │  OTLP Receiver│  │ OpenCode Bridge│              │
│  │  POST /v1/logs│  │ POST /opencode │              │
│  └──────────────┘  └────────────────┘              │
└─────────────────────────────────────────────────────┘

Key Components

PTY Sessions (node-pty)

Each terminal session spawns a real pseudo-terminal using node-pty. The agent process runs inside this PTY and behaves exactly as if it were in a normal terminal. Termix doesn’t inject any middleware between you and the agent. Terminal output is buffered (up to 200KB per session) and sent to the browser over WebSocket. The browser renders it using xterm.js.

WebSocket Communication

A single WebSocket connection carries all messages between the browser and server. Messages are JSON-encoded with a type field for routing. The server broadcasts to all connected clients — you can have multiple browser tabs open.

OTLP Telemetry Receiver

The server runs an HTTP endpoint at POST /v1/logs that accepts OpenTelemetry log data in JSON format. When an agent is launched, Termix sets environment variables that point the agent’s OTLP exporter to this local endpoint. The receiver:
  1. Parses the OTLP resource logs
  2. Matches the log to the correct session (via termix.session_id resource attribute)
  3. Extracts the agent’s session ID from log record attributes
  4. Detects if telemetry is properly configured (triggers setup toast if not)

OpenCode Plugin Bridge

OpenCode uses a different integration path. A JavaScript plugin inside OpenCode sends HTTP events to POST /opencode-events. The bridge maps these events to the correct Termix session by matching the working directory.

Activity Monitor

A 1-second polling loop measures I/O rates for each session:
  • Bytes in/out since last poll
  • Burst duration — how long the current output burst has been going
  • Resets after 2 seconds of silence
These stats are broadcast to the browser, which uses them to determine working/idle status. This is the source of truth — not telemetry.

Transcript Store

Every session’s I/O is recorded as plain-text JSONL in ~/.termix/transcripts/. ANSI codes are stripped, short lines filtered out. The transcript is used for sidebar search — a cache is built on startup and updated incrementally.

Data Flow: Agent Status

Agent outputs text → PTY → node-pty onData
                           ├→ WebSocket 'output' → browser renders in xterm.js
                           ├→ Activity tracker counts bytes
                           └→ Transcript records stripped text

Activity poll (1s) → broadcasts stats → browser computes working/idle
                                         ├→ Updates status indicator
                                         └→ Triggers notification (if idle transition)

Data Flow: Session Resume

Agent starts → telemetry logs flow to /v1/logs
             → OTLP receiver extracts session ID
             → stored as session.sessionToken

Termix shuts down → SIGTERM/SIGINT handler
                   → saves sessions to sessions.json
                   → kills PTY processes

Termix starts → loads sessions.json
              → shows in "Previous Sessions" sidebar
              → user clicks resume
              → spawns new PTY with resume command + saved session ID

Local Only

Termix runs entirely on your machine. There’s no cloud service, no account, no external API calls. The Node.js server binds to 127.0.0.1:4000 — it’s not accessible from other machines on your network. If the Node.js server stops, all PTY processes stop too. This is intentional — Termix manages terminal sessions locally.