Skip to content

Terminal Integration

Repl integrates with the host terminal at several levels: it detects window size, decodes VT keyboard sequences, emits progress notifications to capable terminals, and classifies terminal identity to adapt rendering. This page documents those interactions.

VT sequence notation used throughout this page:

AbbreviationExpansionHex
ESCEscape0x1B
CSIControl Sequence Introducer (ESC [)0x1B 0x5B
OSCOperating System Command (ESC ])0x1B 0x5D
SS3Single Shift Three (ESC O)0x1B 0x4F
BELBell0x07

ANSI escape sequences are enabled or disabled based on a precedence chain:

Precedence (highest → lowest)Source
Session overrideTerminalSessionOverrides.AnsiSupported
Explicit configOutputOptions.AnsiMode = Always / Never
NO_COLORAny set value disables ANSI (per no-color.org)
CLICOLOR_FORCE=1Forces ANSI on
Redirected outputConsole.IsOutputRedirected disables ANSI
TERM=dumbDisables ANSI

When ANSI is enabled, the default renderer uses 256-color SGR styling (38;5;N). Add Repl.Spectre for 24-bit color (38;2;r;g;b) and richer rendering — Spectre.Console always requests true-color when ANSI is on.


Repl uses the terminal window size to format output (table column widths, word wrap, indentation). The width is resolved from the first available source:

SourceContext
TerminalSessionOverrides.WindowSizeExplicit override — always wins
Console direct queryLocal interactive sessions — Console.WindowWidth
DTTERM probe (CSI 18 t)Streamed/WebSocket sessions — active probe at startup
Telnet NAWS (RFC 1073)Telnet sessions — negotiated at connection
@@repl: control protocolWebSocket/SignalR clients — client-pushed JSON
Default fallback120 columns

For sessions over a stream pair (WebSocket, named pipe, custom transport), Repl sends CSI c (DA1 — Device Attributes) followed by CSI 18 t (DTTERM window size request) immediately after connection. The terminal’s response (CSI 8 ; rows ; cols t) is parsed as the initial size.

Resize events — when the user resizes the terminal window during a session — are delivered as the same CSI 8 ; rows ; cols t sequence and processed continuously.

Repl.Telnet negotiates the Telnet NAWS option (RFC 1073) during the connection handshake. Window dimensions are received via subnegotiation and updated on resize. Repl.Telnet also negotiates TERMINAL-TYPE (RFC 1091) to obtain the terminal identity string.

Custom transport clients (WebSocket, SignalR) can push metadata by writing a @@repl: JSON control message to the input stream. The framework parses hello and resize verbs:

@@repl:{"verb":"hello","terminal":"xterm-256color","cols":220,"rows":50,"ansi":true}
@@repl:{"verb":"resize","cols":160,"rows":40}

This is Repl’s own convention — not a terminal standard. Client libraries that wrap the StreamedReplHost can use it to pass terminal state.


For sessions over a stream pair (StreamedReplHost, Telnet, WebSocket), Repl decodes VT escape sequences from the input stream. The following key events are recognized:

KeysVT sequence shape
Arrow keys (Up/Down/Left/Right)CSI A / B / C / D
Home / EndCSI H / F or CSI 1~ / 4~
Insert / DeleteCSI 2~ / 3~
Page Up / Page DownCSI 5~ / 6~
F1–F4SS3 P / Q / R / S

For local interactive mode, keyboard input goes through the standard Console.ReadKey path, which handles modifiers natively on the host OS.


Repl emits OSC 9;4 progress notifications — supported by Windows Terminal, ConEmu, WezTerm, iTerm2, and Ghostty — so the host shows a progress indicator in the taskbar or title bar.

The escape sequence format:

ESC ] 9;4;<state>;<percent> BEL

State codes:

StateCodeMeaning
Normal1In progress, known percent
Error2Failed
Indeterminate3In progress, percent unknown
Warning4Completing with warnings
Clear0Done — remove progress indicator

Control emission with InteractionOptions.AdvancedProgressMode:

app.Options(o =>
{
o.Interaction.AdvancedProgressMode = AdvancedProgressMode.Auto; // default
// AdvancedProgressMode.Always — always emit
// AdvancedProgressMode.Never — never emit
});

In Auto mode, OSC 9;4 is emitted when any of the following is true:

  • The local environment sets WT_SESSION (Windows Terminal), ConEmuANSI=ON (ConEmu), or TERM_PROGRAM=WezTerm.
  • The session’s terminal capabilities include ProgressReporting (see Terminal capabilities below).

Emission is suppressed when TMUX is set or TERM starts with screen or tmux, since multiplexers pass the raw escape sequence to the outer terminal unparsed.

OSC 9;4 is never emitted when ANSI output is disabled or when the session is in protocol-passthrough mode (e.g., MCP serve).


When a session connects, Repl classifies its terminal identity to determine which capabilities to enable. The identity string comes from:

  • Telnet TERMINAL-TYPE negotiation (Repl.Telnet)
  • @@repl:hello JSON control message (terminal field)
  • TerminalSessionOverrides.TerminalIdentity — explicit override

The classifier maps substrings of the identity string to capability flags:

Terminal identity containsAnsiProgressReportingVtInputResizeReporting
windows terminal
wezterm
iterm
ghostty
conemu
xterm, vt, ansi
alacritty, rxvt, konsole, gnome, linux
screen, tmux
dumb

Matching is case-insensitive and substring-based — xterm-256color matches xterm.

VtInput enables VT keyboard sequence decoding. ResizeReporting enables live terminal resize events. Omitting either flag in a TerminalSessionOverrides override will silently suppress that behavior.

For local sessions (no identity string), terminal detection falls back to environment variables: WT_SESSION, ConEmuANSI (any case — on, On, ON all match), and TERM_PROGRAM are checked for OSC 9;4 gating.

Override capabilities when the auto-detection doesn’t fit:

// In a hosted session:
new TerminalSessionOverrides
{
TerminalIdentity = "xterm-256color",
TerminalCapabilities = TerminalCapabilities.Ansi
| TerminalCapabilities.VtInput
| TerminalCapabilities.ResizeReporting,
}

Handlers can query terminal properties to adapt their output:

using Repl.Interaction;
app.Map("report", (ITerminalInfo terminal, IDataStore store) =>
{
if (terminal.WindowSize?.Width >= 120)
return BuildWideReport(store);
else
return BuildCompactReport(store);
});

With Repl.Spectre, adaptation is automatic — Spectre.Console degrades gracefully when the terminal doesn’t support colors or Unicode.


In CLI mode, Repl suppresses banners and interactive prompts automatically. For protocol commands (the completion bridge, mcp serve), all framework diagnostics go to stderr and structured output to stdout, making output safe to pipe.


Currently in place:

  • OSC 9;4 progress in supported terminals
  • ANSI 256-color rendering (default) and 24-bit color via Repl.Spectre
  • Screen clear and cursor positioning for interactive menus
  • VT key decoding (arrows, Home/End, PgUp/PgDn, F1–F4)
  • Terminal size probing and live resize events
  • Terminal identity classification (15+ terminal families)

Not yet implemented:

  • Kitty Keyboard Protocol — extended modifier-aware key input (CSI <code>;<mods> u)
  • Mouse reporting (?1000 / ?1006 and variants)
  • Alternate screen buffer (?1049)
  • Bracketed paste mode (?2004)
  • Sixel and Kitty graphics
  • OSC 7 (working directory), OSC 8 (hyperlinks), OSC 52 (clipboard), OSC 133 (shell integration marks)
  • True-color palette in the default renderer (256-color only; 24-bit available via Repl.Spectre)

These primitives form the foundation for a future TUI mode — full-screen, keystroke-driven surfaces (panels, menus, live updates) that will compose with the same command graph. The current Repl.Spectre integration covers static rich rendering; a dedicated Repl.Tui package is on the roadmap.