| name | vx-best-practices |
| description | Best practices for using vx effectively. Use when following recommended patterns for tool management, project setup, and team workflows with vx. |
VX Best Practices
Golden rule: Always prefix tool commands with vx in vx-managed projects. Use vx.toml for project-level tool versions, commit vx.lock for reproducibility, and prefer templates over custom code when creating providers.
General Principles
1. Always Use vx Prefix
In vx-managed projects, always prefix tool commands with vx:
vx npm install
vx cargo build
vx just test
npm install
cargo build
just test
2. Prefer Project-Level Configuration
Use vx.toml to ensure consistency across team members:
vx sync
vx install node@22
3. Commit Lock Files
Always commit vx.lock to ensure reproducible builds:
git add vx.lock
git commit -m "chore: update dependencies"
Project Setup
Initial Setup
vx init
vx add node@22
vx add go
vx add just
vx lock
git add vx.toml vx.lock
Team Onboarding
New team members only need to run:
git clone <repo>
cd <repo>
vx setup
CI/CD Configuration
Use the vx GitHub Action:
- uses: loonghao/vx@main
with:
setup: 'true'
cache: 'true'
Version Management
Version Selection Strategy
| Scenario | Constraint | Example |
|---|
| Development | Major version | node = "22" |
| CI/CD | Exact version | node = "22.0.0" |
| Library | Range | node = ">=18 <23" |
| Latest features | "latest" | uv = "latest" |
Avoid Over-Specification
[tools]
node = "22"
go = "1.22"
[tools]
node = "22.0.0"
go = "1.22.0"
LTS for Production
[tools]
node = "lts"
Scripts Organization
Naming Conventions
[scripts]
dev = "npm run dev"
test = "npm run test"
build = "npm run build"
lint = "npm run lint"
test:watch = "npm run test -- --watch"
test:coverage = "npm run test -- --coverage"
build:prod = "npm run build -- --mode production"
ci = "just ci"
ci:test = "cargo test --all-features"
Script Dependencies
[scripts]
lint = "eslint . && cargo clippy"
build = "go build ./..."
Environment Variables
Project-Level Defaults
[env]
NODE_ENV = "development"
DEBUG = "app:*"
API_KEY = { env = "API_KEY", required = true }
PORT = { default = "3000" }
Secrets Management
Never commit secrets. Use environment variables:
DATABASE_URL=postgresql://...
API_KEY=secret123
[env]
DATABASE_URL = { env = "DATABASE_URL" }
Performance Optimization
Cache Configuration
[cache]
enabled = true
ttl = 86400
dir = "~/.vx/cache"
Pre-install Common Tools
vx sync --parallel
Use Offline Mode
vx sync --offline
Cross-Platform Considerations
Platform-Specific Tools
[tools]
node = "22"
uv = "latest"
[tools.msvc]
version = "14.42"
os = ["windows"]
[tools.brew]
version = "latest"
os = ["macos", "linux"]
Cross-Platform Scripts
[scripts]
build = "just build"
test = "cargo test"
Security Best Practices
Verify Checksums
vx automatically verifies checksums. For additional security:
vx install node@22 --verify
Minimal Permissions
vx install node
Audit Dependencies
vx audit
vx npm audit
Team Workflows
Adding New Tools
vx add python@3.12
vx lock
git add vx.toml vx.lock
git commit -m "feat: add python 3.12"
Updating Tools
vx outdated
vx update node
vx update --all
git add vx.lock
Removing Tools
vx remove tool-name
vx sync --clean
git add vx.toml vx.lock
Monitoring & Maintenance
Regular Checks
vx outdated
vx cache clean
vx doctor
Health Check Script
[scripts]
doctor = "vx doctor"
check = "vx check"
audit = "vx npm audit && cargo audit"
Anti-Patterns to Avoid
1. Manual Tool Installation
npm install -g node
vx npm install
2. Ignoring Lock Files
git rm --cached vx.lock
git add vx.lock
3. Global vx.toml
~/.vx/vx.toml
./vx.toml
4. Hardcoded Paths
[env]
TOOL_PATH = "/Users/alice/.vx/tools/node"
[env]
TOOL_PATH = "${VX_ROOT}/tools/node"
Migration Guide
From nvm/fnm → vx
node --version > .nvmrc
vx init
vx add node@$(cat .nvmrc | tr -d 'v')
rm -rf ~/.nvm
From pyenv → vx
python --version
vx init
vx add uv
rm -rf ~/.pyenv
Provider Development Best Practices
Choose the Right Template
Decision tree for new providers:
- Tool releases on GitHub with Rust target triple? →
github_rust_provider (most common)
- Tool releases on GitHub with Go goreleaser? →
github_go_provider
- Single binary download (no archive)? →
github_binary_provider
- System package manager only? →
system_provider
- Custom download source? → Hand-write
download_url function
For most tools, use a template instead of writing custom functions:
# ✅ Good — Use template (10 lines)
_p = github_rust_provider("owner", "tool",
asset = "tool-{vversion}-{triple}.{ext}")
# ❌ Avoid — Custom download_url when template works
def download_url(ctx, version):
# 30+ lines of custom code...
Understanding the ctx Object
All provider.star functions receive a ctx object:
| Field | Example value | Description |
|---|
ctx.platform.os | "windows", "macos", "linux" | Current OS |
ctx.platform.arch | "x64", "arm64" | CPU architecture |
ctx.install_dir | ~/.vx/store/node/22.0.0 | Install path |
ctx.store_dir | ~/.vx/store | Global store root |
ctx.cache_dir | ~/.vx/cache | Cache directory |
Provider Naming
# ✅ Correct terminology
name = "ripgrep" # Provider name
runtimes = [runtime_def("rg")] # Runtime name (what user types)
# Common pattern: provider name = project name, runtime name = binary name
# ripgrep provider → rg runtime
# rust provider → cargo, rustc, rustup runtimes
Platform Constraints
Return None from download_url for unsupported platforms:
def download_url(ctx, version):
platform = platform_map(ctx, _PLATFORMS)
if not platform:
return None # Not supported on this platform
return "https://example.com/v{}/tool-{}.tar.gz".format(version, platform)
Bundled Runtimes
Use bundled_runtime_def for tools shipped inside another:
runtimes = [
runtime_def("node"), # Primary runtime
bundled_runtime_def("npm", "node"), # npm comes with node
bundled_runtime_def("npx", "node"), # npx comes with node
]
vx Development Best Practices
Quick Development Cycle
vx just quick
vx cargo check -p vx-cli
vx cargo test -p vx-starlark
Code Organization Rules
- Layer dependencies go downward only — Never import from higher layers
- Tests in
tests/ directories — Never inline #[cfg(test)]
- Use
rstest for parameterized tests
- Use
tracing for logging, never println! or eprintln!
- Use correct terminology — Runtime, Provider, provider.star
AI Agent Documentation Ecosystem
vx maintains a comprehensive set of AI agent configuration files for 15+ agents:
| File | Purpose | Audience |
|---|
AGENTS.md | Primary AI agent entry point — rules, architecture, quick reference | All AI coding agents (official standard) |
CLAUDE.md | Claude Code specific instructions with @-import support | Claude Code |
llms.txt | Concise LLM-friendly project index (llmstxt.org protocol) | LLMs discovering the project |
llms-full.txt | Detailed LLM documentation with full examples | LLMs needing deep context |
.github/copilot-instructions.md | GitHub Copilot-specific instructions | GitHub Copilot |
.cursor/rules/*.mdc | Modern Cursor IDE rules with YAML frontmatter (4 files) | Cursor AI (new format) |
.cursorrules | Cursor IDE agent rules (legacy format, still supported) | Cursor AI (legacy) |
.clinerules | Cline/Roo agent rules | Cline |
.windsurfrules | Windsurf AI IDE rules | Windsurf |
.kiro/steering/*.md | Kiro AI IDE steering documents | Kiro |
.trae/rules/*.md | Trae AI IDE project rules | Trae |
skills/ | Distributable skill files for 15+ AI agents | ClawHub, vx ai setup |
Best practice: When making changes that affect AI agent behavior (terminology, architecture, commands), update AGENTS.md first — it is the single source of truth. Other files derive from it.