Terminal sessions run inside dtach, a minimal PTY detach/attach tool. This means:
- Sessions survive server restarts — dtach keeps the process alive independently
- A pty-wrapper inside dtach continuously writes output to a buffer file
- On server restart, the buffer is replayed so you see the full terminal history
dtach has zero rendering layer — all PTY I/O passes through transparently. tmux interposes its own terminal rendering which breaks mouse events, scroll, and selection in Claude Code's TUI. After 6+ failed attempts to fix tmux mouse handling, we migrated to dtach.
Open the same WebUI from multiple browsers or devices:
- Output broadcasts to all connected clients in real-time
- Terminal size uses the minimum cols/rows across all clients (tmux-style)
- Larger clients show padding around the terminal area
- When a client disconnects, the size may increase for remaining clients
- Editor open/close events broadcast to all clients for correct window targeting
When clients have different window sizes, the PTY is sized to the smallest client (so every client sees a complete frame). The larger clients hatch the unused region tmux-style and show a badge — "80×20 — limited by a smaller client" — so the size cap is visible instead of the terminal just looking small. Closing or enlarging the smaller client restores the full size automatically — or click Use my size on the badge to take over: the terminal resizes to this window, and the smaller client's view is blocked behind a Resume here overlay (one click takes the size back). Handy when a small window at home stays attached while you work from a bigger screen. The override follows your window as you resize it and releases automatically when you disconnect (or via the badge's Release button). A freshly attached client always gets a forced TUI repaint, so a page refresh lands on a clean frame.
If the connection to the server is lost (network interruption, server restart):
- The WebSocket client automatically reconnects with a 2-second retry interval
- All active terminal sessions are re-attached on reconnect
- Chat sessions re-attach and sync any missed messages (see Chat Mode)
- Pending messages are queued and sent once the connection is restored
Each terminal window has a gear icon (⚙) in the title bar. Click it to customize:
| Setting | Options | Default |
|---|---|---|
| Theme | Any of the 6 themes + "Default" | Follows global |
| Font size | 8-32px + "Default" checkbox | Follows global |
| Font family | System + web fonts + "Default" | Follows global |
Selecting "Default" makes the terminal follow the global setting. Overrides are persisted in the layout auto-save.
By default, the terminal auto-scrolls to show new output. When you scroll up to read history:
- Output is queued instead of written to the terminal
- The viewport stays frozen at your scroll position
- A ↓ button appears in the bottom-right corner
- Click ↓ or scroll to the bottom to flush queued output and resume auto-scroll
This prevents Claude Code's TUI redraws from yanking the viewport while you're reading.
Fullscreen (alternate-screen) TUIs — Claude's flicker-free renderer, vim, htop — own the whole viewport and handle their own scrolling, so the freeze machinery steps aside: frames always write through, and the mouse wheel is passed to the app.
Terminals render with xterm.js's WebGL renderer (device-pixel-aligned cells — no clipped rightmost column, fast flicker-free repaints), falling back to the DOM renderer where WebGL is unavailable. The area around the character grid is painted in the terminal theme's background, and cell metrics refresh automatically when the browser zoom or monitor changes.
Claude Code ≥2.1 ships a flicker-free fullscreen renderer (alternate screen + virtualized scrollback; /tui fullscreen in any session). Settings → Claude → Terminal TUI renderer controls it for terminal-mode sessions started from the WebUI:
| Value | Behavior |
|---|---|
| Auto (default) | Follow the preference saved by the CLI (/tui) |
| Fullscreen (flicker-free) | Force the alt-screen renderer (CLAUDE_CODE_NO_FLICKER=1) |
| Classic (main screen) | Force the classic renderer (CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1) |
Claude Code updates the terminal title via OSC 0 escape sequences:
- ✳ (U+2733) = idle, waiting for input
- Braille spinners (U+2800-28FF) = working
When Claude transitions to idle and the window is not focused:
- The window title bar blinks orange
- The taskbar item blinks orange
- Blinking clears when you focus the window
Configure via Settings > Terminal > Waiting blink behavior:
- Always — blink even if window is focused
- Only when unfocused — default
- Never — disable blinking entirely
On phones (≤768px) a horizontally scrollable key row sits under the terminal: Esc, Tab, ⇧Tab (cycles Claude's permission modes), Ctrl (sticky: tap it, then type a letter to send Ctrl+letter), arrow keys (hold to repeat), 📋 Paste, and common control combos (^C interrupt, ^G editor, ^R history search, ^Z, ^D, ^\ command mode).
Paste on mobile: tap 📋 — text and images both work. On HTTPS the clipboard is read directly; over HTTP a dashed "long-press here and tap Paste" pad appears, and pasting into it routes through the same pipeline as desktop Ctrl+V (images upload to the server clipboard and are handed to the CLI).
Ctrl+G on mobile: the ^G key opens the same split-pane editor as desktop.
Paste images from your system clipboard directly into Claude Code:
- Copy an image to your clipboard (screenshot, browser image, etc.)
- Focus the terminal window
- Press Ctrl+V
Behind the scenes:
- The browser intercepts Ctrl+V and reads the image from the paste event
- The image is uploaded to the server
- The server writes it to the system clipboard via
xclip(Linux) orosascript(macOS) - A raw Ctrl+V (0x16) is sent to the PTY, triggering Claude Code's clipboard image check
Linux requirement:
xclipmust be installed and a display server available (X11 or Xwayland).
When a terminal receives a BEL character (U+0007) while not focused, a bell icon appears on the window title bar. The icon clears when you focus the window.
The terminal uses xterm.js's Unicode 11 addon for correct fullwidth character width calculation. CJK monospace fonts are included in the fallback chain.
Terminal fonts are discovered dynamically:
- Client-side (Chrome 103+):
queryLocalFonts()API detects monospace fonts installed on your machine - Server fallback:
fc-list :spacing=monofor browsers withoutqueryLocalFonts - Google Web Fonts: Fira Code, JetBrains Mono, Source Code Pro, IBM Plex Mono, Inconsolata — always available
Since the terminal renders in the browser, client-side fonts are what matter, not server fonts.
For light terminal backgrounds, xterm.js's minimumContrastRatio is automatically set to 4.5 (WCAG AA). This adjusts any foreground color (including RGB escape sequences from Claude Code's diff rendering) that doesn't meet the contrast threshold against the background.
- Light backgrounds (luminance > 0.4): auto-enabled at 4.5
- Dark backgrounds: disabled (ratio = 1) — dark themes have sufficient contrast by design
- Applied on terminal creation and on theme switch
- Override via Settings > Terminal > Minimum contrast ratio
Drag a file from the file explorer and drop it on a terminal window. The shell-escaped absolute path is automatically typed into the terminal.