Skip to content

Architecture

taiku has three main components: a CLI client, a relay server, and a browser frontend. The server never sees plaintext terminal data.

flowchart LR
    subgraph CLI["CLI (Rust)"]
        PTY[PTY Shell]
        ENC1[AES-128 Encrypt]
    end

    subgraph Server["Server (Rust)"]
        Relay[Relay + Store]
        Meta[Presence & Metadata]
    end

    subgraph Browser["Browser (Svelte)"]
        Term[xterm.js]
        ENC2[AES-128 Decrypt]
    end

    PTY --> ENC1
    ENC1 -- "gRPC / HTTP2<br/>encrypted terminal data" --> Relay
    Relay -- "WebSocket / CBOR<br/>encrypted stream" --> ENC2
    ENC2 --> Term
    Term -- "encrypted input" --> Relay
    Relay -- "encrypted input" --> ENC1
    Meta -. "cursor positions,<br/>user presence" .-> Browser

The CLI opens a bidirectional gRPC stream (Channel RPC) over HTTP/2. It sends:

  • Encrypted terminal output — AES-128-CTR ciphertext, chunked
  • Shell lifecycle events — creation acknowledgments, closure

It receives:

  • Encrypted keyboard input — from browser users
  • Resize events — when browser users resize a terminal
  • Session events — user join/leave, adoption requests

The server is a Rust binary using Tonic (gRPC) and Axum (HTTP/WebSocket). It stores:

  • Encrypted terminal chunks in memory (up to 2 MiB per shell)
  • User presence (names, cursor positions, focus state)
  • Session metadata (not terminal content)

With Redis configured, sessions can be snapshotted and routed across multiple server instances. Browser WebSocket connections are transparently proxied between nodes.

Sessions expire 5 minutes after the CLI disconnects.

Browsers connect via WebSocket to /api/s/{session_id}. The wire format is CBOR (binary, compact) — not JSON. The client wrapper handles automatic reconnection with offline message queuing.

sequenceDiagram
    participant B as Browser
    participant S as Server

    B->>S: WebSocket connect
    S->>B: Hello (user ID assigned)
    B->>S: Key verification (encrypted zeros)
    S->>S: Constant-time comparison
    S->>B: Connection established
    S->>B: Stream encrypted terminal chunks
    B->>S: Encrypted keyboard input

The frontend is SvelteKit with xterm.js (WebGL-accelerated). Terminal layout uses a tiling binary split tree computed as a flat rect map — terminals are absolutely positioned and never remounted when the layout changes.

A type-ahead addon provides optimistic local echo for typed characters before round-trip confirmation, making the experience feel local even over high-latency connections.