Beyond the built-in tools, you can install custom system packages in your template VM. This guide covers package installation, version management, and custom repositories.
- Basic Package Installation
- Version Management
- Custom Repositories
- Package Features
- Examples
- Troubleshooting
Install additional Ubuntu/Debian packages using the [packages] section:
[packages]
system = [
"postgresql-client",
"redis-tools",
"jq",
"htop",
"curl"
]Run claude-vm setup to install packages during template creation.
- Packages are installed via
apt-get - All packages install in a single batch operation
- Installation happens during template creation
- Packages are available in all cloned sessions
- Simple names:
"jq","curl","vim" - With versions:
"python3=3.11.0-1" - With wildcards:
"nodejs=22.*" - With architecture:
"libc6:amd64"
Pin to a specific version:
[packages]
system = [
"python3=3.11.0-1",
"postgresql-client=14.5-1"
]Use wildcards for flexible versioning:
[packages]
system = [
"nodejs=22.*", # Any 22.x version
"postgresql-client=14.*" # Any 14.x version
]Omit version to get the latest:
[packages]
system = [
"jq", # Latest available
"curl" # Latest available
]Specify architecture when needed:
[packages]
system = [
"libc6:amd64", # 64-bit version
"libstdc++6:i386" # 32-bit version
]For packages not in Debian repositories, add custom repos using a setup script:
[packages]
system = ["terraform", "kubectl"]
setup_script = """
#!/bin/bash
set -e
# Add HashiCorp repository
curl -fsSL https://apt.releases.hashicorp.com/gpg | \
sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/hashicorp.list
# Add Kubernetes repository
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | \
sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] \
https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /" | \
sudo tee /etc/apt/sources.list.d/kubernetes.list
"""Must be idempotent:
# Good: Check if already added
if [ ! -f /etc/apt/sources.list.d/hashicorp.list ]; then
# Add repository
fi
# Bad: Always tries to add (fails on reruns)
curl ... | sudo tee /etc/apt/sources.list.d/repo.listMust use set -e:
#!/bin/bash
set -e # Exit on any errorAll packages install in one operation for efficiency:
[packages]
system = ["pkg1", "pkg2", "pkg3"]
# Runs: apt-get install -y pkg1 pkg2 pkg3Package names are validated to prevent injection:
[packages]
system = [
"jq", # ✓ Valid
"postgresql-14", # ✓ Valid
"pkg; rm -rf /" # ✗ Rejected (invalid characters)
]Dependencies are automatically installed:
[packages]
system = ["postgresql-client"]
# Automatically installs: libpq5, postgresql-client-common, etc.[packages]
system = [
"postgresql-client",
"mysql-client",
"redis-tools",
"mongodb-clients"
][packages]
system = [
"build-essential",
"cmake",
"pkg-config",
"libssl-dev",
"git-lfs"
][packages]
system = [
"htop",
"ncdu",
"jq",
"curl",
"wget",
"vim",
"tmux"
][packages]
system = [
"ffmpeg",
"imagemagick",
"pandoc",
"graphviz"
][packages]
system = ["awscli"]
setup_script = """
#!/bin/bash
set -e
# Install Azure CLI (installer handles repository setup)
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
"""[packages]
system = ["terraform", "packer", "vault"]
setup_script = """
#!/bin/bash
set -e
if [ ! -f /etc/apt/sources.list.d/hashicorp.list ]; then
curl -fsSL https://apt.releases.hashicorp.com/gpg | \
sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/hashicorp.list
fi
"""[packages]
system = [
"ruby-full",
"golang-go",
"openjdk-17-jdk",
"php-cli"
]Search Ubuntu packages:
# On host or in VM
apt-cache search <keyword>
apt-cache show <package-name>Check package versions:
apt-cache policy <package-name>List files in package:
dpkg -L <package-name>| Tool | Package Name |
|---|---|
| PostgreSQL client | postgresql-client |
| MySQL client | mysql-client |
| Redis CLI | redis-tools |
| MongoDB tools | mongodb-clients |
| JSON processor | jq |
| YAML processor | yq |
| HTTP tool | curl, wget, httpie |
| Process viewer | htop, glances |
| Disk usage | ncdu |
| Text editor | vim, nano, emacs |
| Build tools | build-essential, cmake |
Error: Package 'xyz' not found
Solutions:
-
Check package name:
apt-cache search xyz
-
Add repository:
[packages] system = ["xyz"] setup_script = """ # Add the repository providing 'xyz' """
-
Install from source in setup script:
# .claude-vm.setup.sh curl -L https://example.com/xyz.tar.gz | tar xz cd xyz && make install
Error: Version '1.2.3-4' not found for package 'xyz'
Solutions:
-
Check available versions:
apt-cache policy xyz
-
Use wildcard:
system = ["xyz=1.2.*"] # Any 1.2.x version
-
Use latest:
system = ["xyz"] # No version constraint
Error: GPG error: repository is not signed
Solution: Add repository key in setup script:
setup_script = """
#!/bin/bash
curl -fsSL https://example.com/key.gpg | \
sudo gpg --dearmor -o /usr/share/keyrings/example.gpg
"""Error: Unmet dependencies
Solution: Let apt resolve dependencies automatically or specify all required packages:
[packages]
system = [
"package-a",
"package-b", # Required by package-a
"package-c" # Also required
]Error: Setup script exited with code 1
Debug:
# Run setup with verbose output
claude-vm --verbose setup --git
# Check script manually
bash -x .claude-vm.setup.shCommon causes:
- Script not idempotent (fails on rerun)
- Missing
set -e - Network errors (use retries)
- Permission errors (use
sudowhere needed)
Packages requiring interaction will hang. Ensure non-interactive installation:
# In setup script
export DEBIAN_FRONTEND=noninteractive
sudo apt-get install -y <packages>Claude VM automatically sets DEBIAN_FRONTEND=noninteractive.
# Good: Logical grouping
[packages]
system = [
# Database tools
"postgresql-client",
"redis-tools",
# Utilities
"jq",
"curl"
]# .claude-vm.toml
[packages]
system = [
"imagemagick", # For image processing in scripts
"pandoc", # For markdown to PDF conversion
"jq" # For JSON parsing in CI
][packages]
system = [
"nodejs=20.*", # Pin major version
"jq" # Latest is fine
]# Create template
claude-vm setup --git
# Verify packages
claude-vm shell which jq
claude-vm shell postgresql-client --versionFor repositories requiring multiple steps, use setup scripts instead of inline:
# .claude-vm.setup.sh
#!/bin/bash
set -e
source ./scripts/add-custom-repos.sh- Tools - Understand built-in tools
- Configuration - Configure custom packages
- Templates - Understand template creation
- Troubleshooting - Debug package issues