Skip to content

williamzujkowski/moltdown

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🦀 moltdown

Shed your VM state. Emerge fresh.

A reproducible, low-click workflow for creating and managing Ubuntu 24.04 Desktop VMs optimized for AI agent work. Run agents with full autonomy, then molt back to a pristine golden image.

Lint

Overview

This toolkit provides:

  • Automated OS Installation: Cloud-init/autoinstall for hands-free Ubuntu Desktop setup
  • Comprehensive Bootstrap: Security-hardened development environment with agent tooling
  • Snapshot Management: Pre/post agent-run snapshots for clean state management
  • Idempotent Operations: Re-runnable scripts with phase markers
  • Local Customization: Override defaults without modifying core scripts
  • Pre-authenticated AI CLIs: Claude Code, Codex, Gemini, and GitHub CLI ready to use

Quick Start (Pre-Authenticated Golden Image)

If you already have a golden image with authentication baked in:

# One command to spin up an agent VM and connect
./agent.sh

# That's it! You're now in a shell with all CLIs ready:
claude "explain this codebase"
codex "fix the tests"
gh pr create

Or using make:

make agent           # Spin up and connect
make agent-list      # List running clones
make agent-kill CLONE=moltdown-clone-xxx  # Clean up

No authentication needed - everything is inherited from the golden image.

Quick Start (New Setup)

One-Command Setup (Recommended)

git clone https://github.com/williamzujkowski/moltdown.git
cd moltdown
./setup_cloud.sh

This uses Ubuntu Cloud Images for fast VM creation (~8 minutes to desktop-ready).

Alternative: ISO Installer

./setup.sh

This uses the traditional Ubuntu ISO installer (slower, ~20 minutes).

Using Make

make install-deps    # Install host dependencies
make setup-cloud     # Create VM using cloud images (RECOMMENDED)
make setup           # Create VM using ISO installer
make golden          # Create golden snapshots after bootstrap
make gui             # Open VM desktop with virt-viewer
make ssh             # SSH into VM

Manual Installation

If you prefer more control:

# 1. Generate cloud-init seed ISO
./generate_nocloud_iso.sh --customize

# 2. Create VM with automated installation
./virt_install_agent_vm.sh --seed-iso ./seed.iso

# 3. Wait for installation (~10-15 min), then SSH in
ssh agent@<vm-ip>

# 4. Run bootstrap inside VM
./bootstrap_agent_vm.sh
gh auth login

# 5. Create golden snapshots
sudo shutdown -h now
./snapshot_manager.sh golden ubuntu2404-agent

Directory Structure

moltdown/
├── README.md                    # This file
├── CLAUDE.md                    # Development guidelines
├── RESOURCES.md                 # Memory planning for parallel agents
├── CHANGELOG.md                 # Release history
├── Makefile                     # Common operations
├── agent.sh                     # One-command agent VM creation
├── setup_cloud.sh               # One-command setup (cloud images, RECOMMENDED)
├── setup.sh                     # One-command setup (ISO installer)
├── update-golden.sh             # Update golden image CLIs and auth
├── sync-ai-auth.sh              # Sync AI CLI auth to VMs
├── code-connect.sh              # VS Code Remote SSH connection
├── generate_cloud_seed.sh       # Create seed ISO for cloud images
├── generate_nocloud_iso.sh      # Create seed ISO for ISO installer
├── virt_install_agent_vm.sh     # Create VM with virt-install
├── run_bootstrap_on_vm.sh       # Push bootstrap via SSH
├── snapshot_manager.sh          # Manage VM snapshots
├── clone_manager.sh             # Manage VM clones for parallel workflows
├── cloud-init/
│   ├── user-data                # Cloud-init config (for cloud images)
│   └── meta-data                # Cloud-init metadata
├── autoinstall/
│   ├── user-data                # Autoinstall config (for ISO installer)
│   └── meta-data                # Cloud-init metadata
├── guest/
│   └── bootstrap_agent_vm.sh    # Run inside VM (includes health check)
├── docs/
│   └── CLOUD_IMAGES.md          # Cloud image workflow docs
├── examples/
│   ├── bootstrap_local.sh       # Local customization template
│   └── user-data-custom.yaml    # Customized autoinstall example
└── .github/
    └── workflows/
        └── lint.yml             # ShellCheck + yamllint CI

GUI Access

VMs are created with SPICE graphics for full desktop access.

# Connect with virt-viewer (minimal)
virt-viewer ubuntu2404-agent

# Or use virt-manager for full GUI management
virt-manager

Install GUI tools: sudo apt install virt-viewer or sudo apt install virt-manager

Agent Workflow

Once you have a dev-ready snapshot, use this workflow for each agent run:

# Before agent work
./snapshot_manager.sh pre-run ubuntu2404-agent

# ... do agent work ...

# Export any artifacts from VM
scp agent@<vm-ip>:~/work/artifacts/* ./local-artifacts/

# Reset to clean state
./snapshot_manager.sh post-run ubuntu2404-agent

Parallel Agent Workflows

Run multiple agents simultaneously using VM clones:

# Create linked clones (instant, copy-on-write)
./clone_manager.sh create ubuntu2404-agent --linked
./clone_manager.sh create ubuntu2404-agent --linked
./clone_manager.sh create ubuntu2404-agent --linked

# Start clones
./clone_manager.sh start moltdown-clone-ubuntu2404-agent-20250201-143052

# List all clones
./clone_manager.sh list

# Connect to each clone
virt-viewer <clone-name>  # GUI
ssh agent@<clone-ip>      # SSH

# Cleanup when done
./clone_manager.sh cleanup ubuntu2404-agent

Clone types:

  • Linked clone (--linked): Instant creation, uses copy-on-write. Best for parallel work.
  • Full clone: Complete disk copy. Slower but fully independent.

Using Make:

make clone-linked    # Create linked clone
make clone           # Create full clone
make clone-list      # List all clones
make clone-cleanup   # Delete all clones

Syncing AI CLI Auth

After creating a clone, sync your AI CLI credentials and git config from your host:

# Get clone IP
./clone_manager.sh start moltdown-clone-xxx
VM_IP=$(virsh domifaddr moltdown-clone-xxx | grep -oE '192\.168\.[0-9]+\.[0-9]+')

# Sync all auth (Claude, Codex, Gemini, Git, SSH keys)
./sync-ai-auth.sh $VM_IP agent
# or
make sync-auth VM_IP=$VM_IP

# SSH in - CLIs are ready
ssh agent@$VM_IP
claude --version
codex --version
gemini --version

What Gets Synced

Tool Config Location Contains
Claude Code ~/.claude.json, ~/.claude/ Settings (auth via browser on first use)
Codex ~/.codex/ OAuth tokens, config
Gemini ~/.gemini/ OAuth tokens, settings
Git ~/.gitconfig Identity, signing config
SSH ~/.ssh/ Keys for git auth + commit signing
GPG Exported/imported Keys for commit signing (if used)

First-Time Auth

Some CLIs require browser-based authentication on first use:

  • Claude Code: Run claude and follow the browser prompt
  • GitHub CLI: Run gh auth login (token is in host keyring, not synced)

Security Note

These files contain authentication tokens. They are copied directly to the VM (which is local to your machine) and are NOT committed to git. The VM disk images stay in /var/lib/libvirt/images/ and are excluded by .gitignore.

Long-Running Sessions

VMs are hardened for multi-day or multi-week agent sessions:

  • Swap file: 8GB for memory pressure (Claude CLI can leak to 13GB+)
  • Journal limits: 100MB max, prevents disk fill
  • No auto-reboot: Security updates don't restart
  • Cloud-init disabled: Prevents reconfiguration
  • Memory watchdog: Auto-kills runaway Claude CLI processes at 13GB threshold
  • cgroups limits: Optional hard memory limits via run-claude-limited

Monitor health inside VM:

vm-health-check              # Quick status with Claude memory tracking
vm-health-check --watch      # Live monitoring (30s refresh)
vm-health-check --trend      # Memory trend analysis with OOM prediction
run-claude-limited           # Run Claude with 12GB memory limit
run-claude-limited 8G        # Run with custom limit
agent-session                # Persistent tmux session with auto-reattach

See RESOURCES.md for detailed memory planning and parallel agent deployment guidance.

Scripts Reference

bootstrap_agent_vm.sh

Transforms a fresh Ubuntu 24.04 Desktop into an agent-ready environment.

Features:

  • Phased execution with idempotent markers
  • Security hardening (SSH, firewall, fail2ban)
  • Development tools (git, gh, Node.js, Docker, Python)
  • Browser automation (Chrome, Playwright deps)
  • Agent tooling (Claude CLI, workspace structure)
  • VM performance optimization
  • Package manifest generation

Configuration flags (edit in script):

INSTALL_NODEJS="true"
INSTALL_DOCKER="true"
INSTALL_PLAYWRIGHT_DEPS="true"
INSTALL_CLAUDE_CLI="true"
REMOVE_DESKTOP_FLUFF="true"
ENABLE_UNATTENDED_UPGRADES="true"

snapshot_manager.sh

Manage libvirt snapshots for the golden image workflow.

# List all VMs
./snapshot_manager.sh vms

# List snapshots
./snapshot_manager.sh list ubuntu2404-agent

# Create snapshot (offline recommended)
./snapshot_manager.sh create ubuntu2404-agent my-snap --offline

# Revert to snapshot
./snapshot_manager.sh revert ubuntu2404-agent dev-ready

# Pre-agent-run workflow
./snapshot_manager.sh pre-run ubuntu2404-agent

# Post-agent-run (revert to dev-ready)
./snapshot_manager.sh post-run ubuntu2404-agent

# Interactive golden image creation
./snapshot_manager.sh golden ubuntu2404-agent

generate_nocloud_iso.sh

Generate cloud-init seed ISO for automated installation.

# Interactive mode
./generate_nocloud_iso.sh --customize

# Command-line customization
./generate_nocloud_iso.sh \
    --username myuser \
    --password mysecretpass \
    --hostname my-agent-vm \
    --ssh-key ~/.ssh/id_ed25519.pub

# Custom output path
./generate_nocloud_iso.sh /tmp/my-seed.iso

virt_install_agent_vm.sh

Create VMs with virt-install and automated installation.

# Default configuration
./virt_install_agent_vm.sh --seed-iso ./seed.iso

# Full customization
./virt_install_agent_vm.sh \
    --name my-agent-vm \
    --vcpus 8 \
    --memory 16384 \
    --disk-size 100 \
    --seed-iso ./seed.iso

# Dry run (show command without executing)
./virt_install_agent_vm.sh --seed-iso ./seed.iso --dry-run

run_bootstrap_on_vm.sh

Push and execute bootstrap script via SSH.

# Basic usage
./run_bootstrap_on_vm.sh 192.168.122.100 username

# Copy SSH key first
./run_bootstrap_on_vm.sh 192.168.122.100 username --copy-ssh-key

# Dry run
./run_bootstrap_on_vm.sh 192.168.122.100 username --dry-run

Security Considerations

The bootstrap script implements:

  1. SSH Hardening

    • Root login disabled
    • Password authentication disabled
    • Public key authentication only
    • Limited auth attempts
  2. Firewall (UFW)

    • Default deny incoming
    • Default allow outgoing
    • SSH allowed
  3. Fail2ban

    • SSH brute-force protection
    • 1-hour ban after 3 failures
  4. Unattended Upgrades

    • Automatic security patches
    • No automatic reboot

Customization

Local Overrides (Recommended)

Instead of modifying core scripts, use bootstrap_local.sh:

# Copy template to VM
scp examples/bootstrap_local.sh agent@vm:~/

# Edit to add your packages, dotfiles, etc.
ssh agent@vm vim ~/bootstrap_local.sh

# Run bootstrap - it will source your local config automatically
ssh agent@vm ./bootstrap_agent_vm.sh

Example bootstrap_local.sh:

# Additional packages
LOCAL_APT_PACKAGES=("zsh" "neovim" "tmuxinator")
LOCAL_NPM_PACKAGES=("@anthropic-ai/claude-code")
LOCAL_PIPX_PACKAGES=("pdm" "pre-commit")

phase_local_customizations() {
    # Clone dotfiles
    git clone https://github.com/myuser/dotfiles ~/.dotfiles
    ~/.dotfiles/install.sh
}

Adding Software

Edit bootstrap_agent_vm.sh and add to the appropriate phase function. For example, to add VS Code:

phase_dev_tools() {
    # ... existing code ...
    
    # VS Code
    log_info "Installing VS Code..."
    wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg
    sudo install -o root -g root -m 644 packages.microsoft.gpg /etc/apt/trusted.gpg.d/
    sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list'
    sudo apt update
    sudo apt install -y code
}

Changing Default User

Edit autoinstall/user-data:

identity:
    hostname: your-hostname
    username: your-username
    password: "your-password-hash"

Generate password hash:

echo 'yourpassword' | openssl passwd -6 -stdin

Adding SSH Keys

Option 1: Edit autoinstall/user-data:

ssh:
    authorized-keys:
      - ssh-ed25519 AAAA... your-key

Option 2: Use generate script:

./generate_nocloud_iso.sh --ssh-key ~/.ssh/id_ed25519.pub

Troubleshooting

VM won't start after revert

# Check VM state
sudo virsh domstate ubuntu2404-agent

# Force off and try again
sudo virsh destroy ubuntu2404-agent
sudo virsh snapshot-revert ubuntu2404-agent dev-ready
sudo virsh start ubuntu2404-agent

Can't SSH to VM

# Get VM IP
sudo virsh domifaddr ubuntu2404-agent

# Check if SSH is running in VM
sudo virsh console ubuntu2404-agent
# Then: systemctl status ssh

# Check firewall
sudo ufw status

Bootstrap fails mid-way

The script uses idempotent markers. Just re-run:

./bootstrap_agent_vm.sh

To force re-run a phase:

rm ~/.bootstrap_markers/05-browser-automation.done
./bootstrap_agent_vm.sh

Autoinstall not working

  1. Verify seed ISO is attached:
sudo virsh dumpxml ubuntu2404-agent | grep -A5 cdrom
  1. Check cloud-init logs in VM:
cat /var/log/cloud-init-output.log

Requirements

Host system:

  • libvirt + QEMU/KVM
  • virt-install (virtinst package)
  • virt-viewer (for GUI access)
  • genisoimage, mkisofs, or xorriso
  • SSH client

Install on Ubuntu/Debian:

sudo apt install \
    qemu-kvm \
    libvirt-daemon-system \
    libvirt-clients \
    virtinst \
    virt-manager \
    virt-viewer \
    genisoimage \
    cloud-image-utils \
    openssh-client

Or use: make install-deps

Security Notes

What's in the Git Repo vs Local Machine

Content Location In Git?
Shell scripts, docs This repo ✅ Yes
VM disk images (.qcow2) /var/lib/libvirt/images/ ❌ No
Cloud-init seed ISOs Generated locally ❌ No
Your SSH keys Inside VM disk + ~/.ssh/ ❌ No
Passwords/credentials Inside VM disk ❌ No

Your VM disk images never leave your machine. The golden image containing your SSH keys, user accounts, and any work done inside VMs is stored only in libvirt's local image directory.

The .gitignore explicitly excludes:

  • *.qcow2 - VM disk images
  • *.img - Disk images
  • *.iso - ISO images including cloud-init seeds

SSH Key Security

When you add your SSH public key to the golden image:

  • Only your public key is added (safe to share by design)
  • Your private key never leaves ~/.ssh/ on your host
  • The public key lives inside the VM's disk image (not in git)

Cloud-Init Credentials

The cloud-init/user-data template in this repo contains example credentials. When you run generate_cloud_seed.sh, you provide your own credentials which are written to a local seed.iso that is not committed to git.

Quick Reference

Agent Workflow Commands

Command Description
./agent.sh Create new agent VM and connect (one command!)
./agent.sh --list List all agent clones
./agent.sh --attach <name> Attach to existing clone
./agent.sh --stop <name> Stop a clone gracefully
./agent.sh --kill <name> Delete a clone completely
./agent.sh --gui <name> Open GUI viewer for clone
./agent.sh --health <name> Run health check on clone

Maintenance Commands

Command Description
./update-golden.sh Full update (packages + CLIs + auth)
./update-golden.sh --quick Quick update (CLIs only)
./update-golden.sh --auth-only Re-sync auth from host
./code-connect.sh Open VS Code connected to agent VM
./sync-ai-auth.sh <ip> Sync auth to specific VM

Shell Aliases (add to ~/.bashrc)

alias ma='~/git/moltdown/agent.sh'           # New agent
alias mal='~/git/moltdown/agent.sh --list'   # List agents
alias mak='~/git/moltdown/agent.sh --kill'   # Kill agent
alias mac='~/git/moltdown/code-connect.sh'   # VS Code connect

License

MIT License - feel free to adapt for your workflows.

About

A reproducible, low-click workflow for creating and managing Ubuntu 24.04 Desktop VMs optimized for AI agent work. Run agents with full autonomy, then molt back to a pristine golden image.

Resources

License

Stars

Watchers

Forks

Contributors