NovaTerminal is a modern, cross-platform terminal emulator focused on
correctness, performance, and predictability.
Built with:
- .NET 10
- Avalonia UI
- Skia (GPU-accelerated rendering)
- Rust-based PTY backend
Supported platforms: Windows · Linux · macOS
Most terminal emulators optimize for speed or features. NovaTerminal focuses on something different:
- 🧪 Deterministic rendering
Same input → same output. Always. Enables reliable testing and replay. - 📼 Replay-driven debugging
Record terminal sessions and replay them with pixel-level consistency. - ✅ VT correctness first
Built with conformance and standards in mind---not best-effort rendering. - ⚡ GPU-accelerated rendering
Smooth, modern rendering pipeline using Skia. - 🧩 Extensible architecture
Designed for future workflows (cloud, automation, AI-assisted tooling). - 🤖 Built for AI agents
An opt-in MCP server lets Claude Code and other agents observe your live terminal sessions --- and, behind a separate opt-in, drive them.
Terminal correctness is enforced by automated tests, not guesswork.
That principle shows up everywhere: VT behavior is measured against a conformance matrix, the renderer is gated by performance contracts, and replay parity prevents silent behavioral drift.
GitHub release assets are produced as Native AOT bundles for win-x64,
linux-x64, and osx-arm64. Every release runs the gating unit-test lane on
all three OSes before any bundle is published. Installer packaging is not
available yet, so if a release does not include the bundle you need, build
from source.
For build steps, jump to Build & test below.
- VT / ANSI parsing measured against a conformance matrix
- Alternate screen support (
vim,less,htop) - Scrollback buffer
- Stable resize & reflow
- Cell-based buffer model
- Thread-safe, crash-resistant PTY backend
- Tabs and split panes
- Command palette
- Search overlay
- Profiles (local & SSH)
- Themes and fonts
- Live settings (no restart)
- Sixel Graphics (verified with
libsixel,lsix,gnuplot) - iTerm2 Inline Images (verified with
imgcat,test_iterm2.py) - Kitty Graphics Protocol (native on Linux/macOS; tunneled mode on Windows)
- Proper ConPTY synchronization — images render inline with prompts
- SSH profiles with platform-vault credential storage
- Keepalive and dynamic port forwarding
- Coalesced resize handling for fullscreen TUIs (vim, htop, tmux)
- Disconnect state surfaced in the terminal pane
- Runtime password memory (opt-in, session-scoped)
NovaTerminal guarantees identical terminal behavior across operating systems for VT interpretation, buffer state, wrapping & reflow, and search semantics. Platform-specific differences are limited to window chrome, blur/transparency, global hotkeys, and credential storage backends.
A local, stdio Model Context Protocol server
(NovaTerminal.McpServer) exposes NovaTerminal to AI coding agents (Claude Code, Claude
Desktop, VS Code, …):
- Repo / dev-companion tools — read-only and offline: project docs, VT/ANSI conformance data, and theme / SSH-profile / settings JSON validators.
- Observe (opt-in, default off) —
list_sessions,read_screen,read_scrollback,get_session_status,wait_for_events,export_replay,capture_screen: read live sessions deterministically, as text or as a rendered PNG (screenshots need their own sub-toggle and are journaled). - Act (a separate opt-in, on top of observe) —
send_input,spawn_session,close_session: type into, open, and close sessions. SSH targets additionally require a per-profile allowlist, and every acting call — allowed or denied — is recorded in an in-app activity journal.
With both toggles off there is no live endpoint at all. See the MCP server README and the acting threat model.
Build the server, then register it with your MCP client, pointing at the built DLL (launch
the compiled DLL — never dotnet run, which corrupts the stdio stream):
scripts/build.ps1 build -c Release src/NovaTerminal.McpServer # or scripts/build.shClaude Code:
claude mcp add novaterminal -- dotnet "<path-to-repo>/src/NovaTerminal.McpServer/bin/Release/net10.0/NovaTerminal.McpServer.dll"For Claude Desktop / VS Code, add the same command/args to the client's MCP config.
The repo / dev-companion tools work immediately. To expose live sessions, enable Settings → Agent access (observe) in NovaTerminal; to let an agent type into, spawn, or close sessions, also enable the Agent access (act) sub-toggle (and allowlist any SSH profiles you want reachable). Both are off by default.
NovaTerminal is organized into focused class libraries under src/ with an
acyclic dependency graph.
src/NovaTerminal.App— Avalonia/UI layer: windows, themes, settings, orchestration.src/NovaTerminal.Platform— Shared runtime primitives: input, paths, process, SSH.src/NovaTerminal.VT— Virtual Terminal engine: frame-agnostic parser logic and buffer state.src/NovaTerminal.Rendering— SkiaSharp rendering: framework-agnostic text shaping and GPU glyph caching.src/NovaTerminal.Pty— Native OS integration and PTY session management.src/NovaTerminal.Replay— Deterministic session recording and playback.src/NovaTerminal.Conformance— VT conformance matrix tooling and report generation.src/NovaTerminal.Cli— console-subsystem twin of the (WinExe) app for headless tooling:vt-report, headless replay (--replay <file>), and the SSH askpass helper.src/NovaTerminal.AgentHost.Contracts— zero-dependency wire contracts for the agent-host observe channel (shared by App and McpServer).src/NovaTerminal.McpServer— stdio-only MCP server exposing project docs, config validators, VT conformance data, and (opt-in) live terminal sessions to AI tooling: observe by default, and — behind a separate explicit opt-in — act (type into / open / close sessions).
Validation:
tests/NovaTerminal.App.Tests— primary unit and integration suite (Avalonia Headless UI), including replay, render-metrics, golden-PNG, and shell-integration lanes.tests/NovaTerminal.VT.Tests,tests/NovaTerminal.Rendering.Tests,tests/NovaTerminal.Platform.Tests,tests/NovaTerminal.McpServer.Tests— deterministic per-module suites (the blocking CI lane).tests/NovaTerminal.Architecture.Tests— the key invariants of the graph below are enforced, not aspirational: NetArchTest checks at IL, csproj, and namespace level.tests/NovaTerminal.Benchmarks— performance benchmarks and the SharpFuzz/libFuzzer harness.tests/NovaTerminal.ExternalSuites— manual vttest / native-SSH scenario driver.
graph TD
Cli[NovaTerminal.Cli] --> App[NovaTerminal.App]
App --> Platform[NovaTerminal.Platform]
App --> VT[NovaTerminal.VT]
App --> Rendering[NovaTerminal.Rendering]
App --> Pty[NovaTerminal.Pty]
App --> Replay[NovaTerminal.Replay]
Platform --> Pty
Pty --> Replay
Rendering --> VT
Replay --> VT
Conformance[NovaTerminal.Conformance]
McpServer[NovaTerminal.McpServer]
Enforced invariants (NovaTerminal.Architecture.Tests): VT is a leaf with zero project references; Pty must not depend on VT (the PTY layer delivers raw bytes only); Replay and Rendering reference exactly VT; no production assembly references test libraries. The remaining edges above are documented from the csproj references but not individually asserted.
- Agent host program — the accepted strategic direction
(
docs/agent-host/DIRECTION.md): a session-facing MCP surface so AI agents can observe, query status of, and — with explicit, separate permission — act inside live terminal sessions (send_input/spawn_session/close_session, gated by an "Agent access (act)" opt-in on top of observe, a per-profile SSH allowlist, and a visible activity journal; threat model indocs/agent-host/2026-07-12-acting-threat-model.md), with deterministic replay as the debugging story. Debug what your agent did, frame by frame: with both opt-in toggles enabled, an agent can callnovaterminal.export_replayto save a session's recent output (never input — typed keys are not retained) as a standard.recfile, and anyone can re-render it deterministically withNovaTerminal.Cli --replay <file> [--attributes]. When the pixels are what matter — inline images, TUI layout, a rendering bug —novaterminal.capture_screen(its own "Agent screenshots" opt-in, also journaled) renders a pane to a PNG offscreen from its buffer, so a minimized or occluded window captures identically and nothing outside the pane can appear in the image. - VT conformance program — every supported VT/ANSI feature is tracked in a
matrix; a dedicated CI lane regenerates the report and fails on regressions.
See
docs/vt_coverage_matrix.mdanddocs/ghostty-gaps/vt_conformance_tooling.md. - Ghostty gap tracking (regression gate) — comparison against Ghostty's
behavior is maintained as a regression gate; remaining matrix gaps are
closed when real TUI or agent workflows hit them. See
docs/ghostty-gaps/anddocs/vt_ghostty_gap_matrix.md. - Native SSH — cross-platform SSH client (experimental, opt-in) with VT
correctness, resize coalescing, dynamic forwarding, keepalive, and runtime
password memory. See
docs/SSH_ROADMAP.mdanddocs/native-ssh/.
- Rendering performance contract — snapshot-only rendering boundary,
replay parity, seam safety under fractional DPI, and conservative perf
ceilings enforced by CI. See
docs/RENDERING_PERF_CONTRACT.md. Historical design context:docs/gpu-hardening/.
Prerequisites:
- .NET 10 SDK. The solution targets
net10.0. - Rust stable toolchain installed via
rustup. Both native crates use Rust edition 2024, sorustcandcargomust be onPATH. - macOS: Xcode Command Line Tools (
xcode-select --install) so Cargo has an available system linker. - Windows: Rust's default
stable-x86_64-pc-windows-msvctoolchain expects the MSVC build tools to be installed.
Verify the toolchain before building:
dotnet --version
rustc --version
cargo --versionNotes:
dotnet buildforsrc/NovaTerminal.Apptriggerscargo build --releasefor the native PTY and native SSH libraries automatically.- The CLI project references the app project, so
dotnet buildanddotnet testboth require the Rust toolchain unless you explicitly setSKIP_RUST_NATIVE_BUILD=1for a downstream job that already has the native artifacts. - If a clean clone fails during Cargo's
build-script-buildstep on macOS, first confirmrustc/cargoare installed and that Xcode Command Line Tools are available. If the failure happened after a partial build, removesrc/NovaTerminal.App/native/targetandsrc/NovaTerminal.App/native/rusty_ssh/targetand retry.
Build:
dotnet restore
dotnet build -c ReleaseNote: if your build's stdout/stderr is captured by a parent process (CI runners, agents, test harnesses), use the wrapper scripts
scripts/build.ps1/scripts/build.shinstead of rawdotnet— they pass-nodeReuse:falseand disable the MSBuild server, preventing an indefinite hang caused by long-lived MSBuild daemons inheriting the output handles. Details inCLAUDE.md.
Run tests (same filter as the blocking CI unit lane):
dotnet test -c Release --no-build --filter "Category!=Replay&Category!=RenderMetrics&Category!=PtySmoke&Category!=Stress&Category!=GoldenSharedPng"Use ci/run.sh (Linux/macOS) or ci/run.ps1 (Windows) for the full local
CI-style sequence. Both scripts assume the .NET and Rust toolchains are already installed.
NovaTerminal is configured for Native AOT publish in
src/NovaTerminal.App/NovaTerminal.App.csproj.
The project supports win-x64, linux-x64, and osx-arm64 publish targets.
The release workflow publishes Native AOT bundles for those targets to the
corresponding GitHub Release.
Example publish command:
dotnet publish src/NovaTerminal.App/NovaTerminal.App.csproj -c Release -r win-x64 --self-contained true -p:PublishAot=true -o artifacts/publish/win-x64Swap win-x64 for linux-x64 or osx-arm64 as needed.
NovaTerminal workflows exchange artifacts between jobs (native binaries and
test results). When running via act, enable its artifact server or
artifact upload/download steps will fail.
Recommended command:
act pull_request -P ubuntu-latest=catthehacker/ubuntu:act-latest --artifact-server-path .act-artifactsNotes:
--artifact-server-pathis required foractions/upload-artifact/actions/download-artifact.- To bypass Rust rebuild inside downstream .NET jobs, set
--env SKIP_RUST_NATIVE_BUILD=1.
Under active development. Current focus and upcoming milestones are tracked
in docs/ROADMAP.md.
License: MIT.
Contributions are welcome. NovaTerminal has a strong correctness culture —
terminal core invariants are enforced and automated tests gate changes. See
CONTRIBUTING.md for details, and
docs/reviews/ for periodic deep code reviews with the
current known-issues backlog.
Thanks to Greptile for granting NovaTerminal free access to their AI code review as an open source project. It reviews every pull request here, and that extra pair of eyes is a real help on a codebase where correctness is the whole point.
NovaTerminal aims to be:
- boring in behavior
- predictable under stress
- fast without shortcuts
- cross-platform without divergence
A terminal you can trust.