I’ve started to play with Claude Code, but, being paranoid, I’ve not just run it in a terminal. Here are some brief notes about what I did do.
The basic idea is to run Claude in a VM. There’s nothing new here: it’s a path many have trodden.
It took me a little while to find an approach that felt both safe and reasonably ergonomic. The general idea is to have three directory trees:
The first lives on the VM and is seen by Claude. This isn’t under version control.
The second lives on my main machine and is a dedicated Git branch, which I canonically call
claude.The third is the main branch of the project.
I’m using Git worktrees1 to have two branches of the same repo in the file system at once.
Copying files in and out of the VM is done with rsync over SSH, and I’ve found these two scripts to be useful:
push
#! /bin/sh
. git-guards.sh
require_git_branch claude || exit 1
rsync \
--verbose \
--recursive \
--checksum \
--itemize-changes \
--exclude='/.git' \
--exclude='/tmp' \
--exclude='/push' \
--exclude='/pull' \
--delete \
./ toy-vf.local:claude/foo/pull
#! /bin/sh
. git-guards.sh
require_git_branch claude || exit 1
rsync \
--verbose \
--recursive \
--checksum \
--itemize-changes \
--exclude='/.git' \
--exclude='/tmp' \
--exclude='/push' \
--exclude='/pull' \
--delete \
mjo@toy-vf.local:claude/foo/ ./git-guards.sh
# Shared git guard helpers.
# Source this file; do not execute it directly.
require_git_branch() {
required_branch="$1"
repo_dir="${2:-.}"
if [ -z "$required_branch" ]; then
echo "Usage: require_git_branch <branch> [repo_dir]" >&2
return 2
fi
if ! command -v git >/dev/null 2>&1; then
echo "Error: git is not installed or not on PATH" >&2
return 127
fi
current_branch="$(git -C "$repo_dir" branch --show-current 2>/dev/null)" || {
echo "Error: '$repo_dir' is not a git repository" >&2
return 1
}
if [ -z "$current_branch" ]; then
echo "Error: '$repo_dir' is in detached HEAD state; expected branch '$required_branch'" >&2
return 1
fi
if [ "$current_branch" != "$required_branch" ]; then
echo "Error: expected branch '$required_branch', currently on '$current_branch'" >&2
return 1
fi
}A few comments:
The git-guards code ensures that these scripts only work on the
claudebranch.The long list of excluded directories stops Claude from messing with their contents.
I compare file contents because I found timestamps to be unreliable.
Typical workflow
Use Claude Code to make changes to the code in the VM.
Use the
pullscript to copy the code into theclaudebranch of the repo. Carefully check the code.Use
gitor filesystem commands to copy the changes into the main branch of the repo.
References
- 1. https://git-scm.com/docs/git-worktree
![Atom Feed [ Atom Feed ]](../../atom.png)