| 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, prefer templates over custom code when creating providers, and prefer structured or compact output before reading large logs.
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:
vx git add vx.lock
vx git commit -m "chore: update dependencies"
4. Keep Agent Work Small and Observable
When an AI agent uses vx, optimize for correctness, speed, judgment, and token
efficiency:
- Read enough surrounding code to understand the local pattern, then stop exploring.
- Prefer targeted searches, focused file sections, scoped diffs, selected JSON fields, and capped logs.
- Make the smallest maintainable change that solves the request.
- Reuse existing project helpers before creating new abstractions.
- Avoid single-use wrappers, speculative architecture, and unrelated cleanup.
- Validate according to risk: focused tests for narrow changes, broader checks for shared behavior.
- Preserve evidence from the actual command, CI job, or runtime surface when debugging.
For large or unknown output, scope first and filter through vx-managed tools:
vx rg -n -m 20 "SearchTerm" src
vx git diff --stat
vx git diff --name-only origin/main...HEAD
vx gh pr view 123 --json title,state,files
vx gh run view 456 --json status,conclusion,jobs --jq '.jobs[] | {name,conclusion}'
vx gh run view 456 --log | vx rg -n -m 50 "error|failed|panic|Traceback|FAILED"
vx --compact gh run view 456 --log
Use this priority order for token-heavy surfaces:
- Ask for semantic data:
--json, selected fields, --jq, --fields, --toon.
- Search the raw source with caps:
vx rg -n -m 80 ..., vx jq, vx yq.
- Use
vx --compact <tool> ... for broad subprocess output that still needs context.
- Read full raw output only after the smaller views fail to explain the issue.
The compact filter follows RTK-style principles: preserve high-signal lines,
strip presentation noise, collapse repetition, cap volume, and measure savings
with vx metrics tokens --json when comparing approaches. Do not make
transparent forwarding commands (vx git, vx gh, vx cargo, vx npm) compact
by default; agents should opt in explicitly with --compact so scripts and
humans keep the native tool contract.
Project Setup
Initial Setup
vx init
vx add node@22
vx add go
vx add just
vx lock
vx 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.