Thank you for your interest in contributing to claude-vm! This guide will help you get started.
Run the automated setup script:
./bin/setupThis script will:
- Detect your OS (macOS or Linux Debian/Ubuntu)
- Install Rust toolchain if needed
- Install Lima VM if needed
- Install development dependencies
- Install Rust development tools (clippy, rustfmt)
- Build the project
- Run all tests
If you prefer to set up manually:
-
Install Rust (1.70+)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-
Install Lima (for testing)
macOS:
brew install lima
Linux:
# See https://lima-vm.io/docs/installation/ -
Install development tools
rustup component add clippy rustfmt cargo install cargo-watch # Optional, for auto-rebuild -
Build the project
cargo build
-
Run tests
cargo test
# Debug build (fast, with debug symbols)
cargo build
# Release build (optimized)
cargo build --release
# Watch mode (auto-rebuild on changes)
cargo watch -x build# Run all tests
cargo test
# Run only unit tests
cargo test --lib
# Run only integration tests
cargo test --test integration_tests
# Run a specific test
cargo test test_name
# Run tests with output
cargo test -- --nocapture# Run clippy (Rust linter)
cargo clippy
# Run clippy with warnings as errors
cargo clippy -- -D warnings
# Auto-fix some issues
cargo clippy --fix# Check formatting
cargo fmt -- --check
# Auto-format code
cargo fmt# Run with cargo
cargo run -- --help
cargo run -- setup --docker
# Or build and run binary directly
cargo build
./target/debug/claude-vm --helpclaude-vm-rust/
├── bin/
│ └── setup # Development setup script
├── src/
│ ├── main.rs # Application entry point
│ ├── lib.rs # Library interface (for testing)
│ ├── cli.rs # CLI argument parsing
│ ├── config.rs # Configuration system
│ ├── error.rs # Error types
│ ├── project.rs # Project detection
│ ├── vm/ # VM management
│ │ ├── limactl.rs # Lima subprocess wrapper
│ │ ├── mount.rs # Mount computation
│ │ ├── session.rs # VM sessions with RAII
│ │ └── template.rs # Template operations
│ ├── commands/ # Command implementations
│ │ ├── setup.rs # Setup command
│ │ ├── run.rs # Run command
│ │ ├── shell.rs # Shell command
│ │ ├── list.rs # List command
│ │ ├── clean.rs # Clean command
│ │ └── clean_all.rs # Clean all command
│ ├── scripts/ # Script execution
│ │ ├── mod.rs # Embedded scripts
│ │ └── runner.rs # Script runner
│ └── utils/ # Utilities
│ ├── git.rs # Git operations
│ └── process.rs # Process helpers
├── scripts/ # Installation scripts (embedded)
│ ├── install_docker.sh
│ ├── install_node.sh
│ ├── install_python.sh
│ └── install_chromium.sh
├── tests/ # Test suite
│ ├── integration_tests.rs
│ └── integration/
│ └── cli_tests.rs
└── examples/
└── .claude-vm.toml # Example configuration
-
Create a branch
git checkout -b feature/my-feature
-
Write code with tests
- Add unit tests in the same file (in a
#[cfg(test)]module) - Add integration tests in
tests/if needed
- Add unit tests in the same file (in a
-
Run the test suite
cargo test -
Check formatting and linting
cargo fmt cargo clippy -- -D warnings
-
Commit your changes
git add . git commit -m "feat: add my feature"
- Write a failing test that reproduces the bug
- Fix the bug
- Verify the test passes
- Run full test suite
- Commit with clear description
- Create a new file in
src/commands/ - Implement the command logic
- Add the command to
src/commands/mod.rs - Add CLI definition in
src/cli.rs - Wire it up in
src/main.rs - Add tests in
tests/integration/
Example:
// src/commands/my_command.rs
use crate::error::Result;
use crate::project::Project;
pub fn execute(project: &Project) -> Result<()> {
println!("Executing my command for {}", project.root().display());
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_my_command() {
// Test logic
}
}- Follow Rust naming conventions (snake_case for functions/variables, CamelCase for types)
- Use meaningful variable names
- Add doc comments for public APIs
- Keep functions focused and small
- Prefer
Result<T>over panicking
// Good: Use Result and ? operator
pub fn do_something() -> Result<String> {
let value = some_operation()?;
Ok(value.to_string())
}
// Bad: Don't panic in library code
pub fn do_something() -> String {
some_operation().unwrap() // Don't do this!
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_feature() {
let result = my_function("input");
assert_eq!(result, expected);
}
#[test]
fn test_error_case() {
let result = my_function("bad");
assert!(result.is_err());
}
}Follow conventional commits:
feat: add new featurefix: resolve bug in Xdocs: update READMEtest: add tests for Yrefactor: simplify Z logicchore: update dependencies
-
Ensure all tests pass
cargo test --all -
Ensure code is formatted
cargo fmt
-
Ensure no clippy warnings
cargo clippy -- -D warnings
-
Update documentation if needed
-
Submit PR with clear description:
- What does this change?
- Why is it needed?
- How was it tested?
Some tests require Lima to be installed and running:
# Start Lima default VM (if needed)
limactl start
# Run integration tests
cargo test --test integration_tests
# Run a specific integration test
cargo test --test integration_tests -- test_name# Set RUST_LOG environment variable
RUST_LOG=debug cargo run -- setup --docker
# Or in code
env_logger::init(); // Add to main()cargo install cargo-expand
cargo expandInstall rust-analyzer extension in your editor (VS Code, Vim, etc.)
# Install flamegraph
cargo install flamegraph
# Profile the application
cargo flamegraph -- setup --docker# Generate documentation
cargo doc
# Open in browser
cargo doc --open
# Include private items
cargo doc --document-private-items- Check existing issues on GitHub
- Read the documentation in the
/docsdirectory - Review the implementation details in
IMPLEMENTATION.md - Ask questions by opening a GitHub issue
Be respectful, inclusive, and constructive in all interactions.
By contributing, you agree that your contributions will be licensed under the same license as the project (MIT OR Apache-2.0).