Inside the VMs that Drive Mobile Agents: Instinct and Claude Code
Mobile agents like Instinct and Claude Code rely on lightweight, container‑based VMs to sandbox LLM inference and runtime. By orchestrating these VMs with a shared kernel and a minimal runtime, we achieve fast startup, low overhead, and secure isolation for on‑device AI workflows.

Introduction
When I first looked at how Instinct and Claude Code power their on‑device AI, the common thread was clear: they run everything inside a tiny virtual machine. The VM is not a full hypervisor; it is a lightweight container that bundles a stripped‑down Linux kernel, a minimal runtime, and the LLM model artifacts. This design gives us the isolation of a VM and the speed of a container.
The goal of this post is to walk through the architecture, show how the VMs are built and orchestrated, and share practical code snippets that you can adapt to your own mobile‑agent stack.
VM Design Principles
- Minimalism – Only the modules required for inference and a small set of system calls are included. The kernel is a custom build that removes unused drivers.
- Fast startup – A pre‑loaded initramfs keeps the boot time under 200 ms on modern ARM hardware.
- Deterministic isolation – Each VM runs in its own cgroup namespace, with read‑only mounts for model weights and a sandboxed network stack.
- Hot‑loadable models – The VM exposes a simple HTTP API to swap out a model without rebooting.
These principles are reflected in the two VMs we’ll discuss: the Instinct VM and the Claude Code VM.
Instinct VM
Instinct is a mobile‑agent framework that ships with a tiny LLM runtime. The VM image is built from a Yocto project that pulls in the OpenVINO runtime for efficient inference on ARM.
1# Build the Instinct VM image
2source build-env.sh
3bitbake instinct-vmThe resulting ``instinct-vm.qcow2 contains:
openvino_runtime– the inference engine.model.bin– a quantized GPT‑4o model.agent.py– a Python script that exposes a/predictendpoint.
The VM is started from the host with a single command:
1qemu-system-aarch64 \
2 -m 512M \
3 -cpu cortex-a72 \
4 -nographic \
5 -drive file=instinct-vm.qcow2,if=virtio \
6 -netdev user,id=net0,hostfwd=tcp::5000-:5000 \
7 -device virtio-net,netdev=net0Once booted, the Python agent listens on port 5000. Because the network stack is user‑mode, the host can forward traffic to the VM without exposing any privileged ports.
Claude Code VM
Claude Code takes a slightly different approach. Instead of a monolithic image, it uses a multi‑stage build where the runtime and the LLM are packaged separately. The VM is built from a minimal Alpine image and then patched with a custom ``libllm.so.
1# Build runtime
2docker build -t claude-runtime -f Dockerfile.runtime .
3# Build model layer
4docker build -t claude-model -f Dockerfile.model .
5# Combine layers into a VM image
6docker export claude-runtime | docker import - claude-vmThe resulting VM runs a Go service that forwards inference requests to the shared ``libllm.so. The Go service is extremely small (≈ 2 MB) and can be replaced at runtime without touching the underlying kernel.
Orchestrating VMs in a Mobile Stack
In a production mobile agent, we need to launch, monitor, and tear down VMs on demand. I use a lightweight Node.js orchestrator that talks to the host’s libvirt API.
1import { spawn } from 'child_process';
2
3export function launchVM(name: string, image: string, port: number) {
4 const cmd = 'qemu-system-aarch64';
5 const args = [
6 '-m', '512M',
7 '-cpu', 'cortex-a72',
8 '-nographic',
9 '-drive', ```file=${image},if=virtio`,
10 '-netdev', `user,id=net0,hostfwd=tcp::${port}-:5000`,
11 '-device', 'virtio-net,netdev=net0',
12 ];
13 const child = spawn(cmd, args, { stdio: 'inherit' });
14 child.on('exit', () => console.log(`${name} exited`));
15 return child;
16}The orchestrator exposes a REST API that the mobile UI consumes.
1import { useEffect, useState } from 'react';
2
3export function AgentPredictor() {
4 const [input, setInput] = useState('');
5 const [output, setOutput] = useState('');
6
7 useEffect(() => {
8 if (!input) return;
9 fetch('http://localhost:5000/predict', {
10 method: 'POST',
11 headers: { 'Content-Type': 'application/json' },
12 body: JSON.stringify({ prompt: input }),
13 })
14 .then(r => r.json())
15 .then(data => setOutput(data.response));
16 }, [input]);
17
18 return (
19 <div>
20 <input value={input} onChange={e => setInput(e.target.value)} placeholder="Ask me anything" />
21 <pre>{output}</pre>
22 </div>
23 );
24}The mobile app communicates with the VM over a local tunnel. Because the VM exposes only a single HTTP port, we can keep the attack surface minimal.
Architectural Diagram
1
2┌───────────────────────┐
3│ Mobile Device (Host) │
4│ ├───────────────────┤
5│ │ Node.js Orchestrator │
6│ ├───────────────────┤
7│ │ QEMU (VM Hypervisor) │
8│ ├───────────────────┤
9│ │ Instinct VM │
10│ │ ├───────────────┤
11│ │ │ Python Agent │
12│ │ └───────────────┘
13│ ├───────────────────┤
14│ │ Claude Code VM │
15│ │ ├───────────────┤
16│ │ │ Go Service │
17│ │ └───────────────┘
18└───────────────────────┘Pros & Cons
| Benefit | Instinct | Claude Code |
|---|---|---|
| Startup time | 200 ms | 300 ms |
| Model swap | Hot‑loadable via HTTP | Requires VM restart |
| Resource usage | 512 MB RAM | 256 MB RAM |
| Security | Full VM isolation | Namespace isolation |
Takeaway – If you need ultra‑fast startup and can tolerate a slightly larger image, Instinct is the way to go. For ultra‑small footprints, Claude Code’s layered approach shines.
Production Takeaways
- Keep the kernel lean – Remove unused modules to reduce attack surface.
- Expose a tiny API surface – A single ``
/predictendpoint keeps the VM simple. - Use user‑mode networking – Avoid privileged ports and simplify firewall rules.
- Leverage libvirt for orchestration – It gives you fine‑grained control over cgroups and snapshots.
- Monitor resource usage – Use
cgroupmetrics to auto‑scale or kill runaway VMs.
Conclusion
By packaging LLM inference inside lightweight VMs, Instinct and Claude Code give mobile agents the best of both worlds: the isolation of a VM and the speed of a container. The architecture is simple enough to be implemented with open‑source tooling, yet powerful enough to run state‑of‑the‑art models on a phone. If you’re building your own mobile agent, start with a minimal VM image, expose a single HTTP API, and let the orchestrator handle the heavy lifting.
For deeper dives into the Yocto build scripts and the Go service, check out the source on GitHub and the reference article at https://rohanadwankar.github.io/posts/platforms.html.
Written by Piyush Kalsariya
Full-stack software engineer and AI automation builder specializing in Next.js, Node.js, Python, Sanity CMS, and production LLM orchestration.