Based on best practices from Ratatui and terminal UI development, this FAQ addresses common questions about VT Code architecture and usage.
VT Code correctly filters key events to only process KeyEventKind::Press, avoiding duplicate events from both press and release.
See src/tui.rs:153:
if key.kind == KeyEventKind::Press {
let _ = _event_tx.send(Event::Key(key));
}This pattern is cross-platform compatible (Windows, macOS, Linux).
VT Code uses Tokio for:
- Event multiplexing - Handling terminal events, ticks, and renders concurrently without blocking
- Multi-tool execution - Running MCP tools, PTY sessions, and API calls in parallel
- Lifecycle hooks - Running shell commands asynchronously during agent events
The architecture uses tokio::select! to multiplex:
- Terminal input (blocking read in spawned task)
- Frame rate ticks (60 FPS)
- Event processing ticks (4 Hz)
When NOT to use async:
- Simple one-off CLI tasks (prefer synchronous main loop)
- Tools that don't need concurrent execution
VT Code's multi-agent coordination and tool execution justify async.
VT Code renders to stderr (via CrosstermBackend::new(std::io::stderr()) in src/tui.rs:73).
Rationale:
- Allows piping output:
vtcode ask "task" | jqdoesn't break the TUI - Makes the TUI work out-of-the-box in pipes (no special TTY detection needed)
- Compatible with shell pipelines and CI/CD environments
No. VT Code uses a single terminal.draw() call per frame that renders all widgets together. See vtcode-core/src/ui/tui/session.rs:render() method, which orchestrates all UI components in one closure.
Because VT Code strictly separates data (stdout) from metadata/logging (stderr), you can pipe the output of commands like ask and exec directly.
# Code goes to file, logs stay on screen
vtcode ask "code for a fibonacci function" > fib.pyUse vtcode exec --json to get a pipeable stream of structured events.
VT Code listens for Event::Resize(x, y) events and updates the layout automatically. The TUI widgets reflow based on the new terminal dimensions—no special handling needed.
No, VT Code can't control terminal font size. That's a terminal emulator setting. VT Code adapts to the terminal's actual size via Event::Resize.
Tip: Use tui-big-text or figlet for large ASCII art titles within the TUI.
VT Code assumes a Nerd Font for box-drawing and icon support. Install one of:
- Nerd Fonts (recommended)
- Kreative Square
VT Code is a tool/agent, not a library or framework.
However, vtcode-core (the Rust crate) is a library you can use in your own Rust projects. The binary (vtcode CLI) uses this library to implement a coding agent.
Philosophy:
- Library-like: You control the event loop and can extend VT Code's functionality
- Agent-first: The CLI provides opinionated defaults for common coding tasks
VT Code is an AI coding agent with:
- Security-first: Execution policies, workspace isolation, tool policies, and tree-sitter-bash command validation
- Multi-LLM: OpenAI, Anthropic, Gemini, Ollama, LM Studio, etc.
- Semantic code understanding: LLM-native analysis and navigation across all modern languages
- Context engineering: Token budget tracking, dynamic context curation
- Editor integration: Agent Client Protocol (ACP) for Zed, Cursor, etc.
Reasons:
- Tool execution: MCP tools, PTY sessions, API calls run concurrently
- Event handling: Terminal input, ticks, renders multiplexed with
tokio::select! - Streaming: Real-time AI responses streamed without blocking
- Lifecycle hooks: Shell commands execute without blocking the agent loop
Result: VT Code remains responsive even during long-running operations.
VT Code uses a robust state machine in src/tui.rs:
- Enter: Enable raw mode → alternate screen → start event handler
- Running: Process events → update state → render UI
- Exit: Stop event handler → leave alternate screen → disable raw mode
The ExternalAppLauncher trait allows suspending the TUI to launch editors, git clients, etc.
See src/tui.rs:303 (with_suspended_tui):
- Stops event handler
- Leaves alternate screen
- Drains pending events (critical!)
- Disables raw mode
- Runs external app
- Re-enables raw mode and returns
This prevents terminal artifacts and ensures external apps get clean input/output.
Set RUST_LOG environment variable:
RUST_LOG=vtcode_core=debug,vtcode=debug vtcodeOr configure in vtcode.toml:
[debug]
enable_tracing = true
trace_level = "debug"
trace_targets = ["vtcode_core", "vtcode"]See src/main.rs:244 and src/main.rs:260 for initialization.
The Ratatui FAQ recommends using area.intersection(buf.area) to prevent out-of-bounds rendering. This is applied in VT Code's widget implementations to clamp rendering to valid regions.
Best practice: Use Rect::intersection() and Rect::clamp() when calculating layouts manually.
- Frame rate: 60 FPS (default in
src/tui.rs:72) - Tick rate: 4 Hz (default in
src/tui.rs:71)
Both are configurable via builder methods:
tui.frame_rate(60.0).tick_rate(4.0)- Async event handling: Non-blocking
tokio::select!insrc/tui.rs:138 - Double buffering: Ratatui only renders diffs, not full redraws
- Lazy rendering: Only recompute UI when state changes (not every frame)
Yes. VT Code detects when stdout is a pipe (not a TTY) and adapts:
- Interactive mode: Full TUI if terminal is available
- Pipe mode: Text output (if piped)
Check src/main.rs:228 for TTY detection.
- Ratatui FAQ - Terminal UI best practices
- src/tui.rs - Terminal event handler implementation
- docs/ARCHITECTURE.md - VT Code system architecture