Skip to slide 1
01 / 16
Vibe Coding Nights #43
Off the Leash

PETS
CATTLE.

Spin your agent a throwaway micro-VM. Run the task inside it. Destroy the box.

Wed 22 Jul 2026 19:00 to 22:00 Frontier Tower, Floor 10 Annex $10 early / $20 door · FT members free
The problem
1 of 2

You have one machine you babysit.

  • The agent runs on it. It leaves files, mutates state, installs junk.
  • You clean up after every run, so cleanup is now part of the job.
  • You hesitate before letting it run wide, because the blast radius is your actual work.
  • That box is a pet. It has a name, a history, and a bad day ruins your week.

Tonight: stop nursing one box.

The container half-answer

A container sandbox keeps the agent off your laptop, and that is a genuine improvement. It is not the whole answer.

It still shares your kernel, and the boundary is fuzzy at the edges. Escape, resource bleed, and "works in my container" all live in that gap.

The problem
2 of 2

Why a whole VM, and not just a container.

Container

  • Shared kernel, namespaced.
  • Fast and light. This is the reason it won.
  • The isolation boundary IS the host kernel's attack surface.

Full VM

  • Its own kernel. Its own everything.
  • A hostile or runaway agent is contained at the hardware virtualization line, not at a namespace.
  • Historically the cost was boot time and weight.

That cost is what changed. microVMs plus snapshot and restore make a full VM cheap enough to throw away. The isolation you wanted is now as disposable as the container you settled for.

The concept
pick one, they share a shape

Three tools. Same lifecycle.

Firecracker

AWS · the microVM monitor

The thing under Lambda and Fargate. Minimal device model, one process per VM. Built for exactly this: one short lived VM per task.

Lima

limactl · the local on-ramp

Linux VMs on macOS and Linux from a YAML template, with a shared mount and cloud-init built in. Easiest way in.

Multipass

Canonical · tonight's default

One command Ubuntu VMs. multipass launch, cloud-init native, snapshot support, a CLI you can hold in your head.

On boot times: AWS publishes roughly 125ms to userspace for Firecracker's own minimal device model on their hardware. Treat that as the floor of what the technology can do, not as a promise about your laptop. Nested virtualization on a Mac will be slower, and the number that actually matters tonight is restore-from-snapshot, which you will measure yourself on slide 10.

The concept
bootstrap once, thaw forever

cloud-init bootstraps it. The snapshot makes it instant.

cloud-init is the bootstrap contract

One YAML file the VM reads on first boot: install packages, write files, drop your agent and its keys, run a command. The same file works across Firecracker, Lima and Multipass, which is why you learn it once and keep it when you change backend.

snapshot and restore is the speed

Bootstrap once, snapshot the warm box, then restore from that snapshot per task. Spin-up stops being "install everything" and becomes "thaw a box that is already ready".

base image ubuntu 24.04 cloud-init deps + agent golden baked, once clone task-a runs, then gone clone task-b runs, then gone clone task-c runs, then gone the clones are cattle the snapshot is the only thing you keep

Architecture, illustrative

The pattern
this is the whole night

One ephemeral VM per agent task.

01

spin

Restore a clone from the golden snapshot. No install, no wait.

02

inject

cloud-init drops the task and the agent. Secrets arrive as env, now.

03

run

The agent works inside the box. Full isolation while it does.

04

collect

Copy out only the artifact you asked for. The diff, the file. Not the home dir.

05

destroy

Kill the VM. Nothing leaks back, nothing accumulates.

Repeat that and the boxes stop being individuals. Every agent task is cattle. The value moved out of the machine and into two files you can rebuild from: the cloud-init and the script.

Demo
live, on the stopwatch

Watch one box live and die.

phasewhat you seetimed
spinthe box appears in multipass listboot
runthe agent does a real task inside itrun
collectone artifact lands on the host
destroymultipass list goes emptyteardown

Timings read off the live run, not from this slide

The aha

The host filesystem is untouched. Check it after: no new deps, no stray files, no half-finished edit.

Only the one artifact you asked for came back. That is not a side effect of the tooling. It is the design.

Lab 01
pick ONE backend

Set up your VM tool.

Pick one and stay on it

Multipass is the default tonight because it is one command to a working Ubuntu box and it has snapshots built in.

Lima is the same shape if you prefer YAML templates: limactl start --name=agentbox template://ubuntu-lts.

Do not try both in the hands-on hour. You want a baked snapshot by 21:00, not two half-installs.

brew install --cask multipass

multipass version
multipass find                  # available images, look for 24.04
sudo snap install multipass

multipass version
multipass find                  # available images, look for 24.04
# Multipass on Windows needs a hypervisor: Hyper-V (Windows Pro or
# Enterprise) or VirtualBox. Windows Home has neither by default.
#
# If you have Hyper-V:
winget install Canonical.Multipass
multipass version

# Otherwise use WSL2 and run the Linux tab inside it. This is the
# path that works on every Windows laptop in the room:
wsl --install -d Ubuntu-24.04
# then, inside the WSL shell, follow the Linux tab.
# Crostini does not expose nested virtualization on most Chromebooks,
# so Multipass will not start a VM locally. Do not fight it tonight.
#
# Use a remote Ubuntu box and run the whole lab there over SSH:
ssh you@your-box
# then follow the Linux tab on that machine.
#
# Everything after this slide is identical: the cloud-init file, the
# snapshot, and the script do not care that the host is remote.
Lab 02
one file, every backend

Write the cloud-init bootstrap.

# cloud-init.yaml  -  runs on FIRST boot only
#cloud-config
package_update: true
packages:
  - git
  - curl
  - python3-pip
runcmd:
  # install the agent runtime into the image
  - [ bash, -lc, "curl -fsSL https://claude.ai/install.sh | bash" ]
  # NOTE: no keys here. Secrets ride in at spin time, see below.
# cloud-init.yaml  -  runs on FIRST boot only
#cloud-config
package_update: true
packages:
  - git
  - curl
  - python3-pip
runcmd:
  # install the agent runtime into the image
  - [ bash, -lc, "curl -fsSL https://claude.ai/install.sh | bash" ]
  # NOTE: no keys here. Secrets ride in at spin time, see below.
# Identical file. cloud-init is read by the GUEST, so the host OS is
# irrelevant. Save it with LF line endings, not CRLF, or cloud-init
# will fail to parse the YAML inside the VM.
#cloud-config
package_update: true
packages:
  - git
  - curl
  - python3-pip
runcmd:
  - [ bash, -lc, "curl -fsSL https://claude.ai/install.sh | bash" ]
# Identical file on your remote box.
#cloud-config
package_update: true
packages:
  - git
  - curl
  - python3-pip
runcmd:
  - [ bash, -lc, "curl -fsSL https://claude.ai/install.sh | bash" ]

The rule that matters

Secrets ride in at spin time as env. They are never baked into the snapshot.

The snapshot is code and deps only. That way a leaked or shared snapshot is worthless to whoever gets it, and you can rebuild it in public.

Tonight the agent is Claude Code pointed at z.ai, and the labs run on Nebius Token Factory credits. Both arrive as environment variables on the spin, on slide 11.

Lab 03
bake once, clone forever

Bake a golden snapshot.

# launch ONCE with the bootstrap and let cloud-init finish
multipass launch 24.04 --name golden \
  --cloud-init cloud-init.yaml --memory 2G --disk 10G

# block until the bake is actually done, do not eyeball it
multipass exec golden -- cloud-init status --wait

# a snapshot requires the instance to be stopped
multipass stop golden
multipass snapshot golden --name baked

multipass list --snapshots           # golden.baked should be listed
# launch ONCE with the bootstrap and let cloud-init finish
multipass launch 24.04 --name golden \
  --cloud-init cloud-init.yaml --memory 2G --disk 10G

# block until the bake is actually done, do not eyeball it
multipass exec golden -- cloud-init status --wait

# a snapshot requires the instance to be stopped
multipass stop golden
multipass snapshot golden --name baked

multipass list --snapshots           # golden.baked should be listed
# Inside WSL2, or on Windows Pro with Hyper-V. Same commands.
multipass launch 24.04 --name golden `
  --cloud-init cloud-init.yaml --memory 2G --disk 10G

multipass exec golden -- cloud-init status --wait
multipass stop golden
multipass snapshot golden --name baked
multipass list --snapshots
# On your remote Ubuntu box. Same commands as Linux.
multipass launch 24.04 --name golden \
  --cloud-init cloud-init.yaml --memory 2G --disk 10G

multipass exec golden -- cloud-init status --wait
multipass stop golden
multipass snapshot golden --name baked
multipass list --snapshots

golden.baked is now your reusable warm box.

Every task gets a fresh clone of it. Not a fresh install. This is the step that turns a two minute spin-up into a few seconds.

cloud-init status --wait is not optional. Snapshot too early and you bake a half-installed box, then every clone inherits the same half-install.

Time the next slide's spin with and without the snapshot. That difference is the number this whole pattern is built on, and it is yours, not a vendor's.

Lab 04
the whole pattern, one file

The spin-and-destroy script.

Clone from the snapshot, inject the task, run the agent, collect the artifact, destroy the box. This file is the deliverable.

#!/usr/bin/env bash
# run-in-throwaway.sh <task-file>
set -euo pipefail
TASK="${1:?usage: run-in-throwaway.sh <task-file>}"
BOX="task-$(date +%s)"

# 1. SPIN: a fresh box cloned from the baked snapshot
multipass clone golden --name "$BOX" && multipass start "$BOX"

# 2. INJECT: the task, plus secrets as env (never in the snapshot)
multipass transfer "$TASK" "$BOX":/home/ubuntu/task.md
multipass exec "$BOX" -- bash -lc "
  export ANTHROPIC_BASE_URL='$ZAI_BASE_URL'
  export ANTHROPIC_AUTH_TOKEN='$ZAI_KEY'
  mkdir -p ~/out && cd ~
  claude -p \"\$(cat task.md)\" --dangerously-skip-permissions
"

# 3. COLLECT: ONLY the artifact. Not the home dir.
multipass transfer -r "$BOX":/home/ubuntu/out ./out-"$BOX" || true

# 4. DESTROY: the box is cattle
multipass delete "$BOX" && multipass purge
echo "box $BOX gone; host untouched"
#!/usr/bin/env bash
# run-in-throwaway.sh <task-file>
set -euo pipefail
TASK="${1:?usage: run-in-throwaway.sh <task-file>}"
BOX="task-$(date +%s)"

# 1. SPIN: a fresh box cloned from the baked snapshot
multipass clone golden --name "$BOX" && multipass start "$BOX"

# 2. INJECT: the task, plus secrets as env (never in the snapshot)
multipass transfer "$TASK" "$BOX":/home/ubuntu/task.md
multipass exec "$BOX" -- bash -lc "
  export ANTHROPIC_BASE_URL='$ZAI_BASE_URL'
  export ANTHROPIC_AUTH_TOKEN='$ZAI_KEY'
  mkdir -p ~/out && cd ~
  claude -p \"\$(cat task.md)\" --dangerously-skip-permissions
"

# 3. COLLECT: ONLY the artifact. Not the home dir.
multipass transfer -r "$BOX":/home/ubuntu/out ./out-"$BOX" || true

# 4. DESTROY: the box is cattle
multipass delete "$BOX" && multipass purge
echo "box $BOX gone; host untouched"
# Run this INSIDE WSL2 as the Linux tab. A PowerShell port works but
# the quoting around the agent invocation is the part that bites, and
# you do not want to debug quoting during the hands-on hour.
wsl -d Ubuntu-24.04
# then: bash run-in-throwaway.sh my-task.md
# On your remote Ubuntu box, identical to the Linux tab.
bash run-in-throwaway.sh my-task.md
Stretch
optional, not required

Firecracker, one level deeper.

# one microVM = one firecracker process + an API socket
firecracker --api-sock /tmp/fc-$BOX.sock &

# configure the boot source over the socket
curl --unix-socket /tmp/fc-$BOX.sock -X PUT \
  'http://localhost/boot-source' \
  -d '{"kernel_image_path":"vmlinux",
       "boot_args":"console=ttyS0 reboot=k panic=1 pci=off"}'

# ... drives and network interfaces configured the same way ...

curl --unix-socket /tmp/fc-$BOX.sock -X PUT \
  'http://localhost/actions' \
  -d '{"action_type":"InstanceStart"}'

# destroy is: kill the process.
kill %1

The point, made not required

Same lifecycle. Spin, run, destroy. The difference is that there is no CLI doing it for you: you drive a REST API over a unix socket, and the VM is one process you can kill.

That is why it is the layer under Lambda and Fargate. It is also why you would not hand-roll it for a workshop.

In production you use something that wraps the socket: firecracker-containerd, Fly.io machines, or Modal sandboxes. You are then buying the same pattern you just built by hand.

Gotchas
read before you trust it

Where this bites.

Secrets

Never bake z.ai or Nebius keys into the snapshot. They ride in as env per spin, so a leaked snapshot is worthless. This is the whole reason the bake and the run are separate steps.

The collect step is the only door back

Be deliberate about what you copy out. If you copy the whole home directory, you defeated the isolation and reintroduced everything you were avoiding.

--dangerously-skip-permissions

Safe here ONLY because the box is disposable. Full autonomy inside, zero blast radius outside. That trade is the point. Never run it on a pet.

Networking

A fully sandboxed box can still phone home. Filesystem isolation is not network isolation. Cap egress if the task is untrusted, and skip shared mounts.

Snapshot drift

Rebuild the golden snapshot when deps move. A stale baked box slowly becomes its own pet, which is the failure mode this pattern exists to prevent.

Disk

multipass delete without purge leaves the box recoverable and the disk used. The script pairs them for a reason. Check multipass list --snapshots occasionally.

Leave-with
working, before you go

What you have at 22:00.

Spin. Run. Destroy.
Nothing accumulates.

Resources
the stack tonight used

Run it tonight, and after.

Your ticket includes z.ai plus Claude Code for the session, and Nebius Token Factory credits to run the labs.

In the room

  • z.ai + Claude Code drives the agent INSIDE the throwaway box, provisioned for the workshop.
  • Nebius Token Factory credits are the compute for the hands-on hour, scoped per event.

The tools, and their docs

  • Firecracker the microVM monitor under Lambda and Fargate.
  • Multipass tonight's on-ramp, from Canonical.
  • Lima the YAML-template alternative.
  • cloud-init the bootstrap contract all three share.

Where this goes in production

  • Fly.io machines and Modal sandboxes sell the same pattern as a service. Once you have built it by hand, you know exactly what you are buying.
Vibe Coding Nights
#43 · Cattle, Not Pets

You built it. Now join the series.

VCN is SF's builder night for people who code with agents. One real thing each session, working before you leave.

Hosted by Rayyan Zahid (Immersive Commons) · Michalis Vasileiadis (Hacker Bob) · Eric Mockler (AI Geneticist) · Devinder Sodhi (Learning Layer Labs)
Facilitator: Rayyan Zahid