From 30ffa42a89d768ce83dae7250b1abf7e0e249e22 Mon Sep 17 00:00:00 2001 From: jbpenrath Date: Wed, 1 Apr 2026 23:27:54 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(agent-vm)=20allow=20to=20mount=20extr?= =?UTF-8?q?a=20folders?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 19 +++++++++++++++++++ agent-vm.sh | 44 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index eeadd9e..7d05164 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,25 @@ agent-vm --offline --readonly claude # Both ## Customization +### Extra host mounts: `~/.agent-vm/volumes` + +List host files or directories to mount **read-only** inside every VM. One path per line, `~` is expanded, `#` starts a comment. Uses Docker Compose-style `source:destination` syntax: + +```bash +# ~/.agent-vm/volumes + +# Mount at the same path in the VM +~/.gitconfig +~/.gitignore + +# Mount at a different path in the VM +~/.claude:/home/$USER.linux/.claude +``` + +When no destination is specified, the path is mounted at the same location inside the VM. Non-existent paths are skipped with a warning. Changes to this file take effect on new VMs (use `--reset` to re-apply to existing ones). + +Lima does not allow to mount files, only folders are supported as mount point. + ### Per-user setup: `~/.agent-vm/setup.sh` Create this file to install extra tools into the base VM template. It runs once during `agent-vm setup`, as the default VM user (with sudo available): diff --git a/agent-vm.sh b/agent-vm.sh index 9b0a442..001704b 100644 --- a/agent-vm.sh +++ b/agent-vm.sh @@ -77,6 +77,39 @@ _agent_vm_ensure_running() { esac done + # Build mounts JSON: project dir (writable) + extra mounts from ~/.agent-vm/volumes (read-only) + local mounts_json="[{\"location\": \"${host_dir}\", \"writable\": true}" + local mounts_file="$AGENT_VM_STATE_DIR/volumes" + if [[ -f "$mounts_file" ]]; then + while IFS= read -r line || [[ -n "$line" ]]; do + line="${line%%#*}" # strip comments + line="${line#"${line%%[![:space:]]*}"}" # trim leading whitespace + line="${line%"${line##*[![:space:]]}"}" # trim trailing whitespace + [[ -z "$line" ]] && continue + # Parse source:destination syntax (like docker compose volumes) + local src="$line" dst="" + if [[ "$line" == *:* ]]; then + src="${line%%:*}" + dst="${line#*:}" + fi + src="${src/#\~/$HOME}" # expand ~ + if [[ ! -e "$src" ]]; then + echo "Warning: Mount path '${src}' (from ~/.agent-vm/volumes) does not exist, skipping." >&2 + continue + fi + if [[ ! -d "$src" ]]; then + echo "Warning: Mount path '${src}' (from ~/.agent-vm/volumes) is not a directory, skipping. Lima only supports directory mounts." >&2 + continue + fi + if [[ -n "$dst" ]]; then + mounts_json+=", {\"location\": \"${src}\", \"mountPoint\": \"${dst}\", \"writable\": false}" + else + mounts_json+=", {\"location\": \"${src}\", \"writable\": false}" + fi + done < "$mounts_file" + fi + mounts_json+="]" + if ! limactl list -q 2>/dev/null | grep -q "^${AGENT_VM_TEMPLATE}$"; then echo "Error: Base VM not found. Run 'agent-vm setup' first." >&2 return 1 @@ -97,7 +130,7 @@ _agent_vm_ensure_running() { # Mount and memory/cpus are applied separately from disk, because # Lima rejects the entire edit if disk shrinking is attempted. local edit_args=() - edit_args+=(--set ".mounts = [{\"location\": \"${host_dir}\", \"writable\": true}]") + edit_args+=(--set ".mounts = ${mounts_json}") [[ -n "$memory" ]] && edit_args+=(--memory "$memory") [[ -n "$cpus" ]] && edit_args+=(--cpus "$cpus") (cd /tmp && limactl edit "$vm_name" "${edit_args[@]}") &>/dev/null @@ -128,7 +161,7 @@ _agent_vm_ensure_running() { fi echo "Updating VM resources..." local edit_args=() - edit_args+=(--set ".mounts = [{\"location\": \"${host_dir}\", \"writable\": true}]") + edit_args+=(--set ".mounts = ${mounts_json}") [[ -n "$memory" ]] && edit_args+=(--memory "$memory") [[ -n "$cpus" ]] && edit_args+=(--cpus "$cpus") local edit_output @@ -319,6 +352,7 @@ VMs are persistent and unique per directory. Running "agent-vm shell" or "agent-vm claude" in the same directory will reuse the same VM. Customization: + ~/.agent-vm/volumes Extra host paths to mount read-only in VMs (one per line) ~/.agent-vm/setup.sh Per-user setup (runs during "agent-vm setup") ~/.agent-vm/runtime.sh Per-user runtime (runs on each VM start) /.agent-vm.runtime.sh Per-project runtime (runs on each VM start) @@ -456,7 +490,7 @@ _agent_vm_claude() { _agent_vm_print_resources "$vm_name" local exit_code=0 - limactl shell --workdir "$host_dir" "$vm_name" claude --dangerously-skip-permissions "${args[@]}" + limactl shell --tty --workdir "$host_dir" "$vm_name" claude --dangerously-skip-permissions "${args[@]}" exit_code=$? [[ -n "$rm" ]] && { echo "Removing VM..."; _agent_vm_destroy; } return $exit_code @@ -522,7 +556,7 @@ _agent_vm_codex() { _agent_vm_print_resources "$vm_name" local exit_code=0 - limactl shell --workdir "$host_dir" "$vm_name" codex --full-auto "${args[@]}" + limactl shell --tty --workdir "$host_dir" "$vm_name" codex --full-auto "${args[@]}" exit_code=$? [[ -n "$rm" ]] && { echo "Removing VM..."; _agent_vm_destroy; } return $exit_code @@ -559,7 +593,7 @@ _agent_vm_shell() { echo "Type 'exit' to leave (VM keeps running). Use 'agent-vm stop' to stop it." fi local exit_code=0 - limactl shell --workdir "$host_dir" "$vm_name" zsh -l + limactl shell --tty --workdir "$host_dir" "$vm_name" zsh -l exit_code=$? [[ -n "$rm" ]] && { echo "Removing VM..."; _agent_vm_destroy; } return $exit_code