Dev VM bootstrap

Info

Builds the agent development environment on devvm (see dev-vm). Replicates the workstation-VM environment, minus desktop-only bits (X11, libvirt tooling). vim + YouCompleteMe are installed — see Python for the no-root build trick. Credentials are not scripted — provision them by hand after.

Base OS

Ubuntu Server 26.04.1 (installed — same release as the workstation VM, exact tool parity), minimal install, openssh-server, static 10.0.2.10/24, gw 10.0.2.2 (vpngw — not the host), interface MTU 1200 (below the udp2tcp tunnel MTU), DNS 10.64.0.1 (Mullvad’s in-tunnel resolver — public resolvers are hijacked at the exit; set it in netplan post-install).

Installer creates user devvm (sudo) — that is the operator/admin account. The agent workspace is a separate devin user created below — deliberately no sudo, so the agent can’t escalate. Root stays locked (installer default).

System packages

apt update
apt install -y \
  git curl wget ca-certificates openssh-server \
  build-essential cmake pkg-config \
  python3 python3-venv \
  podman uidmap slirp4netns fuse-overlayfs \
  jq unzip dos2unix \
  vim ranger \
  && apt autoremove -y

User

useradd -m -s /bin/bash devin
loginctl enable-linger devin        # user services survive logout
usermod -aG systemd-journal devin   # read journals without sudo

Rootless podman works out of the box for devin (subuid/subgid auto-assigned). Optional but recommended:

systemctl --user --machine=devin@ enable --now podman.socket   # as root; targets devin's systemd manager
# add to ~devin/.profile:
#   export DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock

User-local tools (~devin/.local/bin)

su - devin
mkdir -p ~/.local/bin

# uv (python envs/tools)
curl -LsSf https://astral.sh/uv/install.sh | sh

# tldr — user-local, via uv (pipx equivalent). apt's python3-tldr also
# works but uv matches the workstation convention.
uv tool install tldr

# github cli — NOT installed: the account is suspended, remotes are
# local bare repos. Skip this on rebuilds unless GitHub comes back.

# ripgrep / fd / bat / fzf — release binaries or cargo/apt as preferred
# (workstation: rg 15.2.0, fd 10.5.0, bat 0.26.1, fzf 0.74.3).
# Not currently installed on devvm — install on demand.

Python

  • python3-pip deliberately not installed — uv covers all python package/venv/tool work (a stray pip install would create an env uv can’t see).
  • python3-dev absent too: compiling C extensions against system python fails on missing Python.h. Build under a uv python install’d interpreter matching the embedder’s ABI instead — this is how YouCompleteMe’s ycm_core was built (uv python 3.14, matching vim’s libpython3.14). The ycmd server also runs under that uv interpreter — removing it breaks YCM.

devin CLI

curl -fsSL https://cli.devin.ai/install.sh | bash
# lands in ~/.local/share/devin/cli + symlink at ~/.local/bin/devin
# then: devin auth login   (manual — see Credentials)

Optional (install if needed)

  • Node 24 LTS — merged into ~/.local on the old VM (tarball install)
  • .NET SDK — ~/.dotnet
  • kubectl / helm / k9s / kind — only if cluster work happens here
  • Dotfiles: .bash_aliases, .vimrc, .tmux.conf — vm-bootstrap
  • Node 24 → enables YCM --ts-completer; .NET → --cs-completer (re-run install.py in ~/.vim/plugged/YouCompleteMe under the uv python after installing)

Credentials (manual, never scripted)

  • devin auth login
  • Operator pubkey into ~devvm/.ssh/authorized_keys and ~devin/.ssh/authorized_keys — the guest never initiates outbound ssh, so it needs no keypairs of its own.
  • No gh — GitHub account suspended; git remotes are local bare repos.

Post-checks

  • ssh devin@10.0.2.10 via ProxyJump «HOSTNAME»
  • podman run hello-world (rootless)
  • devin auth status shows logged in
  • Isolation re-verified from inside the VM — see dev-vm