A lightweight VM tool for development and testing. Create isolated environments, run commands, and experiment safely without affecting your host system.
Using AI commandline tools can require allowing some scary permissions (ex: "allow model to rm -rf?"), I wanted to isolate commands using a VM that could be ephemeral (erased each time), or persistent, as needed. So instead of the AI trying to "reason out" math, it can write a little program and run it to get the answer directly. This VASTLY increases good output. This was also an experiment to use claude to create what I needed, and I'm very happy with the result.
This is a Virtual Machine image being run through QEMU. You can prep the image with packages you need (I've been using Ubuntu), then have your tool call into the VM directly to run commands.
- Ephemeral by default: Changes are discarded unless explicitly saved
- Persistent mode: Save changes when you want to build up a VM
- Fast startup: Pre-built VM images with cloud-init
- Work directory mounting: Access your local files inside the VM
- Multiple VMs: Create specialized environments for different projects
- Flexible output: Direct, minimal, or verbose output modes
- Non-interactive support: Install packages without prompts
- Linux (Ubuntu/Debian, RHEL/CentOS/Fedora, Arch) or macOS
- QEMU/KVM (for virtualization)
- Node.js 14+ and npm
- SSH client tools
- ISO creation tools (genisoimage/mkisofs)
- Clone or download this repository
- Run the installer:
./install.sh
- Follow the prompts - the installer will:
- Install system dependencies (QEMU, etc.)
- Install Node.js dependencies
- Set up global CLI commands
- Create necessary directories
After installation, you can use scratchpad and scratchpad-prepare commands globally.
-
Prepare a VM with your desired packages:
scratchpad-prepare --name dev nodejs python3 git
-
Run commands in the VM:
scratchpad run --vm dev "node --version" -
Start an interactive shell:
scratchpad shell --vm dev
Use scratchpad-prepare to create VMs with pre-installed software:
scratchpad-prepare [options] [packages...]-n, --name <name>- VM name (default: 'default')-b, --base <image>- Base image: ubuntu, alpine, debian (default: 'ubuntu')-m, --memory <size>- Memory allocation (default: '1G')-d, --disk <size>- Disk size (default: '10G')-v, --verbose- Show detailed output-h, --help- Show help
# Create a VM with Node.js and development tools
scratchpad-prepare --name nodedev nodejs npm git vim
# The VM will be created with all packages installed and ready to useUse scratchpad to run commands or start shells in prepared VMs:
scratchpad run [options] <command> # Execute a command
scratchpad shell [options] # Start interactive shell
scratchpad [options] <command> # Execute command (shorthand)| Option | Description |
|---|---|
--vm <name> |
Use specific VM (default: 'default') |
-m, --memory <size> |
Memory allocation (default: '512M') |
-d, --dir <path> |
Directory to mount (default: current) |
-k, --keep-alive |
Keep VM running after command |
-n, --non-interactive |
Run in non-interactive mode |
-p, --persistent |
Save changes to VM disk |
-v, --verbose |
Show startup/connection details |
--direct |
Show only command output |
--debug |
Show debug information |
-h, --help |
Show help |
Ephemeral (default): Changes are discarded when VM stops
scratchpad run "sudo apt-get install git" # Test installation, changes lostPersistent: Changes are saved permanently
scratchpad run -p "sudo apt-get install git" # Install permanentlyDirect (--direct): Pure command output only - perfect for scripting
scratchpad run --direct "node --version"
# Output: v18.17.0Default: Minimal VM messages + command output
scratchpad run "node --version"
# Output: Starting VM... connecting... ready.
# v18.17.0Verbose (-v): Full VM details + command output
scratchpad run -v "node --version"
# Output: 🚀 Starting VM 'default'...
# ⏳ Connecting to VM...
# ✓ Connected to VM
# v18.17.0
# 🛑 Stopping VM...# 1. Create a Node.js development VM
scratchpad-prepare --name nodedev nodejs npm git
# 2. Check the installed version (direct output)
scratchpad run --vm nodedev --direct "node --version"
# Output: v18.17.0
# 3. Test npm (minimal output)
scratchpad run --vm nodedev "npm --version"
# Output: Starting VM... connecting... ready.
# 9.6.7
# 4. Install a package temporarily (ephemeral)
scratchpad run --vm nodedev "npm install -g typescript"
# 5. Install a package permanently
scratchpad run --vm nodedev -p "npm install -g typescript"
# 6. Interactive development session
scratchpad shell --vm nodedev# Create VM with Python and data tools
scratchpad-prepare --name datascience python3 python3-pip
# Install packages permanently
scratchpad run --vm datascience -p -n "pip3 install pandas numpy jupyter"
# Run analysis script with direct output
scratchpad run --vm datascience --direct "python3 analysis.py"
# Start Jupyter notebook (persistent session)
scratchpad run --vm datascience -p -k "jupyter notebook --ip=0.0.0.0"# Quick test in default VM (ephemeral)
scratchpad run "python3 -c 'print(\"Hello VM!\")'"
# Test with more memory
scratchpad run -m 2G "python3 memory_intensive_script.py"
# Debug with verbose output
scratchpad run -v "python3 problematic_script.py"
# Work with local files (automatically mounted)
scratchpad run "ls -la" # Shows your current directory files
# Install something just for testing (changes discarded)
scratchpad run "sudo apt-get install -y htop && htop"
# Install something permanently
scratchpad run -p -n "sudo apt-get install -y htop"# Get command output for scripts (direct mode)
VERSION=$(scratchpad run --direct "python3 --version")
echo "VM Python version: $VERSION"
# Run tests quietly
scratchpad run --direct "pytest tests/ -v" > test_results.txt
# Batch processing with different VMs
scratchpad run --vm nodedev --direct "npm test" > node_results.txt
scratchpad run --vm python --direct "python3 test.py" > python_results.txt
# Check if a package is available
if scratchpad run --direct "which docker" > /dev/null 2>&1; then
echo "Docker is available in the VM"
fi# Create specialized VMs
scratchpad-prepare --name frontend nodejs npm yarn
scratchpad-prepare --name backend python3 postgresql-client redis-tools
scratchpad-prepare --name tools git docker.io curl
# Use different VMs for different tasks
scratchpad run --vm frontend "npm run build"
scratchpad run --vm backend "python3 manage.py test"
scratchpad run --vm tools "docker ps"
# Compare versions across VMs
echo "Frontend Node: $(scratchpad run --vm frontend --direct 'node --version')"
echo "Backend Python: $(scratchpad run --vm backend --direct 'python3 --version')"# Start VM and keep it running
scratchpad run -k "echo 'VM started'"
# Run more commands on the same VM instance (faster)
scratchpad run --vm default "python3 script1.py"
scratchpad run --vm default "python3 script2.py"# Install packages without prompts
scratchpad run -n -p "sudo apt-get update && sudo apt-get install -y nginx"
# Configure system settings non-interactively
scratchpad run -n -p "sudo dpkg-reconfigure -f noninteractive tzdata"# Alpine Linux VM (smaller, faster)
scratchpad-prepare --base alpine --name minimal python3
# Debian VM
scratchpad-prepare --base debian --name stable nodejs
# Use the different VMs
scratchpad run --vm minimal "python3 --version"
scratchpad run --vm stable "node --version"# Install packages permanently, non-interactively, with direct output
scratchpad run --vm myvm -p -n --direct "sudo apt-get install -y git vim curl"
# Debug a failing command with full verbosity
scratchpad run --vm problematic -v -p "failing_command_here"
# Test in ephemeral mode, then install permanently
scratchpad run --vm dev "npm install lodash" # Test first
scratchpad run --vm dev -p "npm install lodash" # Install permanentlyscratchpad listOutput:
Available VMs:
• default
Base: ubuntu, Packages: python3
• nodedev
Base: ubuntu, Packages: nodejs, npm, git
• datascience
Base: ubuntu, Packages: python3, python3-pip
- Start with ephemeral mode to test things safely
- Create specialized VMs for different projects/languages
- Use persistent mode sparingly - keep VMs minimal and rebuild when needed
- Name your VMs descriptively (
--name frontend,--name datascience)
- Use
--directfor scripting to get clean output - Use default mode for interactive work - shows progress without clutter
- Use
--verbosefor debugging when things go wrong
- Use
--keep-alivewhen running multiple commands on the same VM - Allocate appropriate memory with
-mfor memory-intensive tasks - Use Alpine base for lightweight, fast-starting VMs
- Test installations in ephemeral mode first
- Use
-nflag for automated package installation - Group related installations together in single commands
Permission denied on /dev/kvm
# Add yourself to kvm group and re-login
sudo usermod -aG kvm $USER
# Then log out and back in, or run:
newgrp kvmCommand not found: scratchpad
# Check if ~/.local/bin is in your PATH
echo $PATH | grep -q "$HOME/.local/bin" || echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrcVM won't start
# Check QEMU installation
qemu-system-x86_64 --version
# Check if VM exists
scratchpad list
# Try with verbose mode
scratchpad run -v "echo test"SSH connection fails
# Try with verbose mode to see connection details
scratchpad run -v --vm myvm "echo test"
# Check if VM disk exists
ls ~/.scratchpad/vms/myvm/disk.qcow2Package installation prompts
# Use non-interactive mode
scratchpad run -n "sudo apt-get install package"
# For persistent installation
scratchpad run -p -n "sudo apt-get install package"Use --debug to see detailed parsing and execution information:
scratchpad run --debug --vm myvm "python3 --version"This shows:
- Argument parsing steps
- VM startup details
- SSH connection process
- Command execution details
Need help?
scratchpad --help- CLI helpscratchpad-prepare --help- VM preparation helpscratchpad list- Show available VMs