Contributing to VT Code
June 17, 2026 · View on GitHub
Welcome to VT Code! We're excited that you're interested in contributing to this Rust-based terminal coding agent. This document outlines the guidelines and best practices for contributing to the project.
Table of Contents
- Getting Started
- Development Setup
- Project Structure
- Code Style
- Testing
- Submitting Changes
- Development Guidelines
- Architecture Overview
- Community
Getting Started
VT Code is a Rust-based terminal coding agent with LLM-native code understanding and robust shell safety. It supports multiple LLM providers with automatic failover, prompt caching, and token-efficient context management.
Before contributing, please familiarize yourself with:
- The README.md for an overview of the project
- The Architecture documentation for understanding the system design
- The Extension Boundaries guide before adding new trait- or provider-shaped extension points
- The Development Guide for detailed development processes
Development Setup
Prerequisites
- Rust (latest stable version) - Install from rust-lang.org
- Git
- An API key from one of the supported providers (OpenAI, Anthropic, xAI, etc.)
Setup Process
# 1. Fork and clone the repository
git clone https://github.com/your-username/vtcode.git
cd vtcode
# 2. Build the project
cargo build
# 3. Run tests to ensure everything works
cargo test
# 4. Check code quality
cargo clippy
cargo fmt --check
# 5. Try running VT Code
cargo run -- ask "Hello world"
Environment Setup
Set up your API key environment variable:
# For OpenAI (adjust for your preferred provider)
export OPENAI_API_KEY="sk-..." # Replace with your actual API key
Project Structure
Cargo workspace with ~30 crates. Rust stable, MSRV 1.88, edition 2024.
src/(root): Binary crate — CLI, session bootstrapvtcode-core/: Agent loop, tools, prompts, LLM orchestration, UIvtcode-ui/: Unified UI — design system, theme registry, TUI frameworkvtcode-config/: Config loading and schemavtcode-bash-runner/: Shell execution sandboxvtcode-acp/: Agent Client Protocol (Zed)vtcode-auth/: OAuth and credential storagevtcode-indexer/: Code indexing and searchvtcode-exec-events/:ThreadEventcontract and ATIF exportvtcode-commons/: Shared utilitiesvtcode-macros/: Procedural macrosvtcode-llm/: LLM provider abstraction and streamingvtcode-skills/: Skill discovery, loading, and validationvtcode-safety/: Command safety detection and sandboxingvtcode-a2a/: Agent2Agent protocol client and servervtcode-mcp/: Model Context Protocol client and tool discoveryxtask/: Release packaging automation
Key Directories
docs/: Documentation filestests/: Integration and end-to-end testsvtcode.toml: Configuration file (never hardcode values, always read from config)vtcode-core/src/config/constants.rs: Constants definitiondocs/models.json: Model IDs for providers
Code Style
Rust Conventions
- Naming:
snake_casefor functions/variables,PascalCasefor types - Formatting: Use 4 spaces (no tabs),
cargo fmtfor formatting - Error Handling: Use
anyhow::Result<T>with.with_context()for all fallible functions - Early Returns: Prefer early returns over nested if statements
- Variable Names: Use descriptive variable names
- No hardcoded values: Always read from
vtcode.tomlorvtcode-core/src/config/constants.rs - No emojis in code: Maintain professional code style
Documentation
- All public APIs should have Rustdoc documentation
- Complex logic should include explanatory comments
- Follow the existing documentation patterns in the codebase
- All .md files should be placed in
./docs/directory (not in the root)
Examples
Good:
/// Reads a file with proper error handling
pub async fn read_file_with_context(path: &str) -> anyhow::Result<String> {
tokio::fs::read_to_string(path)
.await
.with_context(|| format!("Failed to read file: {}", path))
}
Avoid:
// Hardcoded values
let limit = 1000;
// Unclear variable names
let x = calculate_something(a, b, c);
Testing
Running Tests
# Run all tests (preferred — parallel, fast)
cargo nextest run
# Run specific test
cargo nextest run test_name
# Run single crate
cargo nextest run -p vtcode-core
# Fallback if nextest is not installed
cargo test --workspace
Test Structure
- Unit tests: Inline with the code they test, in
#[cfg(test)]modules - Integration tests: In the
tests/directory at workspace root - Harness regressions:
cargo test -p vtcode-core --test pty_tests - Follow the Arrange-Act-Assert pattern
- Use descriptive test names that explain what is being tested
Code Quality Checks
# Fast quality gate (10-30s, recommended for iteration)
./scripts/check-dev.sh
# Full quality gate (2-5m, for PRs)
./scripts/check.sh
# Narrow checks
cargo clippy && cargo fmt --check && cargo check
Submitting Changes
Pull Request Process
- Fork the repository and create your feature branch from
main - Make your changes following the code style guidelines
- Add tests for any new functionality
- Update documentation if needed
- Run all tests to ensure nothing is broken
- Commit your changes with clear, descriptive commit messages
- Open a pull request with a detailed description of your changes
Commit Guidelines
- Use present tense ("Add feature" not "Added feature")
- Use imperative mood ("Move cursor to..." not "Moves cursor to...")
- Limit first line to 72 characters or less
- Reference issues and pull requests after the first line
- Follow the Conventional Commits specification if possible
Pull Request Guidelines
- Provide a clear title and description
- Link to any relevant issues
- Explain the problem you're solving and how you solved it
- Include any relevant screenshots or examples (if applicable)
- Ensure all CI checks pass before requesting review
Development Guidelines
Error Handling
Always use proper error handling with context:
use anyhow::{Context, Result};
pub async fn example_function(path: &str) -> Result<()> {
let content = tokio::fs::read_to_string(path)
.await
.with_context(|| format!("Failed to read file at {}", path))?;
// Process content...
Ok(())
}
Async Programming
- Use
#[tokio::main]or#[tokio::main(flavor = "multi_thread")]for async main functions when needed - Prefer async/await for I/O operations
- Use the multi-threaded flavor for CPU-intensive tasks
Configuration
- Never hardcode values - always read from
vtcode.toml - Validate configuration values at runtime
- Use constants defined in
vtcode-core/src/config/constants.rs
Security Practices
- Validate all user input and file paths
- Use safe methods for file operations
- Follow Rust's safety guarantees
- Implement proper permissions and sandboxing where applicable
Architecture Overview
Core Components
- LLM Abstractions: Provider traits with uniform async interfaces supporting OpenAI, Anthropic, Gemini, xAI, DeepSeek, Z.AI, Moonshot AI, OpenRouter, and Ollama
- Modular Tools: Internal trait-based composition for built-in tools, with MCP/manifests preferred for external extensions
- Extension Boundaries: Prefer config, manifests, plugins, and MCP over new public Rust traits for third-party integrations
- Configuration Engine: Deserializes
vtcode.tomlinto validated structs - Context Engineering System: Implements iterative, per-turn curation with token budgeting
- Security & Safety: Tree-sitter-bash for critical shell command validation and OS-native sandboxing
- MCP Integration: Model Context Protocol support for extensible tooling
User Interface
- Ratatui TUI: Reactive terminal user interface
- PTY Integration: Real-time PTY for command streaming
- Slash Commands: Fuzzy-matched commands for various actions
Community
Need Help?
- GitHub Issues: Report bugs and request features at GitHub Issues
- Discussions: Ask questions and discuss development in GitHub Discussions
Questions?
If you have questions about contributing or need clarification on any aspect of the project, feel free to open an issue or reach out through the appropriate channel. We're committed to helping new contributors get up to speed.
Thank you for contributing to VT Code and helping make it a better tool for developers!