# Zero-Tax Virtualization: Running AI Agents Safely in Velo Workspaces

> Source: <https://dev.to/wango/zero-tax-virtualization-running-ai-agents-safely-in-velo-workspaces-4mfa>
> Published: 2026-09-16 17:24:00+00:00

Running autonomous AI coding agents natively on your primary macOS machine introduces severe security liabilities. Modern agents execute terminal commands, install unverified dependencies via `pip` and `npm`, modify arbitrary files, and can be coerced through prompt injection attacks into exfiltrating environment variables, dotfiles, or macOS Keychain secrets.

The standard industry remedy is sandboxing agents inside a Linux virtual machine or container. On Apple Silicon, however, this immediately collides with a hypervisor-level barrier:

`Virtualization.framework` does not expose the host Metal GPU to Linux guests. Linux VMs receive only a 2D paravirtualized framebuffer (`virtio-gpu`).
[Velo Workspaces](https://www.veloworkspaces.com) resolves this trade-off by separating the **agent execution environment** from the **model inference engine**:

This guide covers **both** engines side by side. Pick one in Section 5 — everything downstream (VM setup, the vsock bridge, agent configuration) works identically either way, substituting the port your chosen engine listens on.

|  | **MLX** | **Ollama** | 
|---|---|---|
| Default port | `8080` | `11434` | 
| Model source | [huggingface.co/models?library=mlx-lm](https://huggingface.co/models?library=mlx-lm) | [ollama.com/library](https://ollama.com/library) | 
| Best for | Apple Silicon-native performance, the widest current selection of day-one MLX-quantized releases | The simplest one-command setup and model management ( `ollama pull` ,`ollama run` ) | 

*Note: Inside the VM, the agent's traffic is forwarded over a VirtIO-vsock channel to the AI Bridge on the macOS host, which relays it to the host's inference server (Ollama or MLX). A separate Caddy port forward lets an external LAN client reach the VM's optional web UI.

`127.0.0.1:<PORT>` inside the VM — `8080` for MLX, `11434` for Ollama. The local `socat` proxy routes this payload across vsock to the host. The Swift AI Bridge receives the connection and relays it to whichever engine you selected as the workspace's Host Provider.`http://<VM_IP>:4096` over the standard hypervisor bridge.`8081`) to the guest's Web UI port (` 4096`). Port Both engines use macOS Unified Memory dynamically. Because the OS, display compositor, and the model's KV cache share this pool, reserve at least 20–25% of total host RAM for operating overhead.

Model identifiers below are verified as of this writing — always confirm current availability and exact tags at [huggingface.co/models?library=mlx-lm](https://huggingface.co/models?library=mlx-lm) (MLX) or [ollama.com/library](https://ollama.com/library) (Ollama) before pulling, since libraries change.

| Mac Unified RAM | MLX (Hugging Face) | Ollama ( `ollama pull ...` ) | Quantization | Use Case | 
|---|---|---|---|---|
| **16 GB** | `mlx-community/Qwen2.5-Coder-7B-Instruct-4bit` | `qwen2.5-coder:7b` | 4-bit | Fast code completion, lightweight script generation, single-file edits. | 
| **24 GB / 32 GB** | `mlx-community/Qwen2.5-Coder-32B-Instruct-4bit`` mlx-community/Mistral-Small-24B-Instruct-4bit` | `qwen2.5-coder:32b`` mistral-small` | 4-bit | Multi-file reasoning, refactoring, and debugging complex logic. | 
| **36 GB / 48 GB** | `mlx-community/Qwen3.8-27B-4bit` * | `qwen3.8:27b` * | 4-bit | Advanced agentic tasks, architectural design, repository-wide indexing. | 
| **64 GB / 96 GB** | `mlx-community/Llama-3.3-70B-Instruct-4bit` | `llama3.3:70b` | 4-bit | Deep reasoning, zero-shot full repository synthesis, complex planning. | 
| **128 GB+** | `mlx-community/Qwen3.8-2.4T-A95B-*bit` *`deepseek-ai/DeepSeek-V3`* | `deepseek-v3` * | 1-bit to 4-bit | Full-scale autonomous pipelines, heavy concurrent agent swarms. | 

* These are very recent (2026) or very large releases — check the library link for the exact current tag/quantization before pulling; MLX and Ollama conversions can lag a new release by days to weeks.

Because the heavy LLM weights and KV caches stay in macOS unified memory, the Linux VM only needs enough resources to execute the code generated by the agent.

**Important (Session Longevity):** Long-running autonomous sessions gradually leak resources. Agents continuously generate temporary files, compile dependencies, bloat `pip`/` npm` caches, and retain execution logs. Allocate extra memory buffers for long-lived environments to keep the Linux Out-Of-Memory (OOM) killer from terminating tasks.

| Scenario | vCPUs | Memory | Storage | Primary Workloads & Rationale | 
|---|---|---|---|---|
| **Ephemeral / Light Automation** | 2 vCPUs | 2 GB – 3 GB | 15 GB – 20 GB | CLI automation and simple scripts. Ideal for short-lived, disposable tasks. | 
| **Full-Stack Web Development** | 4 vCPUs | 4 GB – 6 GB | 30 GB – 40 GB | Node.js, Django, SQLite, Vite. Accommodates build tools and background servers. | 
| **Long-Running Agent Sessions** | 4 – 6 vCPUs | 8 GB – 12 GB | 50 GB – 60 GB | Continuous autonomous loops. Buffers memory against cached artifacts and logs. | 
| **System Programming & Docker** | 6 – 8 vCPUs | 12 GB – 16 GB | 60 GB – 80 GB | Rust/Go/C++ compilation, Docker-in-VM services. Prevents compilation lockups. | 

Pick **one** engine. All steps in this section run in the **macOS Terminal** on the host.

Install the official Apple MLX language model package using Python (3.10+):

```
# Create and activate an isolated virtual environment
python3 -m venv ~/.mlx-env
source ~/.mlx-env/bin/activate

# Install the MLX LM server package
pip install --upgrade mlx-lm
```

Launch the server bound to loopback (`127.0.0.1`) on port `8080`. It downloads the model from Hugging Face automatically on first run. `mlx-community/Qwen2.5-Coder-7B-Instruct-4bit` below is just an example — swap in whichever tag you picked for your RAM tier in **Section 3**:

```
mlx_lm.server \
  --model mlx-community/Qwen2.5-Coder-7B-Instruct-4bit \
  --host 127.0.0.1 \
  --port 8080
```

In a second macOS terminal, verify it's responding to OpenAI-compatible requests:

```
curl -s http://127.0.0.1:8080/v1/models | grep "id"
```

Install Ollama from [ollama.com](https://ollama.com) (or `brew install ollama`). `qwen2.5-coder:7b` below is just an example — pull whichever tag you picked for your RAM tier in **Section 3** instead:

```
brew install ollama
ollama serve &          # or just launch the Ollama app — it runs this for you
ollama pull qwen2.5-coder:7b
```

Ollama listens on `127.0.0.1:11434` by default. Verify it's responding:

```
curl -s http://127.0.0.1:11434/v1/models | grep "id"
```

*Example: AI Sandbox profile with AI Bridge enabled and Host Provider set to MLX. Pick Ollama here instead if that's what you started in Section 5.*

All steps in this section run in the **Ubuntu Linux Terminal** inside the VM. Throughout, `<PORT>` is `8080` for MLX or `11434` for Ollama — whichever you picked in Section 5.

Rather than typing this by hand, open the running workspace's **AI Bridge** tab in Velo Workspaces — it shows your exact port already filled in, with a Copy button on each command block. Run **step 1**, then either **step 2** (forwards for the life of this terminal session — simplest, good for a quick test) or **step 3** (installs it as a systemd service that survives reboots — better for anything you'll come back to):

```
# 1. Install socat
sudo apt-get install -y socat

# 2. Forward the port for this session
socat -d -d TCP-LISTEN:<PORT>,fork,reuseaddr,bind=127.0.0.1,nodelay VSOCK-CONNECT:2:<PORT>
```

**— or, to keep it running across reboots —**

```
# 3. Install as a systemd service instead of step 2
sudo tee /etc/systemd/system/velo-ai-bridge.service >/dev/null <<'EOF'
[Unit]
Description=Velo Workspaces AI Bridge (127.0.0.1:<PORT> to the host over the high speed channel)
After=network.target

[Service]
ExecStart=/usr/bin/socat TCP-LISTEN:<PORT>,fork,reuseaddr,bind=127.0.0.1,nodelay VSOCK-CONNECT:2:<PORT>
Restart=always
RestartSec=2

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable velo-ai-bridge
sudo systemctl restart velo-ai-bridge
```

Then, either way, verify guest-to-host connectivity across the vsock boundary:

```
# 4. Check it from inside the workspace
curl -sS http://127.0.0.1:<PORT>/v1/models
```

If that returns your model's info, the bridge is live — every agent below points at `http://127.0.0.1:<PORT>/v1`, and each one configures that itself in the next section, so there's no separate global environment-variable setup needed here.

OpenCode provides both an automated CLI agent and an interactive web workspace.

```
   sudo apt install -y curl git build-essential
   curl -fsSL https://opencode.ai/install | bash
   source ~/.bashrc
```

`~/.config/opencode/opencode.json`:

```
   mkdir -p ~/.config/opencode
   nano ~/.config/opencode/opencode.json
```

Paste this, substituting `<PORT>` and the model name for your chosen engine (from Section 3):

```
   {
     "$schema": "https://opencode.ai/config.json",
     "provider": {
       "local": {
         "npm": "@ai-sdk/openai-compatible",
         "name": "Local Server",
         "options": {
           "baseURL": "http://127.0.0.1:<PORT>/v1"
         },
         "models": {
           "<model-name>": {
             "name": "<Display Name>"
           }
         }
       }
     },
     "model": "local/<model-name>"
   }
```

`--auto` auto-approves tool execution inside the sandbox:

```
   opencode run --auto "Write a python script to benchmark disk I/O, execute it, and print the results."
opencode
```

Inside the TUI, type `/connect`, select **Local Server**, and when prompted for an API key, type anything (e.g. `local`) — the local server doesn't check it.

`0.0.0.0` so it's reachable across the hypervisor network:

```
   opencode web --port 4096 --hostname 0.0.0.0
```

From your Mac's browser: `http://<VM_IP>:4096`.

**Accessing the Web UI from another PC on your LAN:** external machines can't route directly into the VM's private subnet, so forward a port on the host. On the **macOS host**:

```
   brew install caddy
   caddy reverse-proxy --from :8081 --to <VM_IP>:4096
```

Any machine on the LAN can then navigate to `http://<HOST_IP>:8081`.

Open Interpreter provides a direct terminal agent loop designed for code execution.

```
   pip install open-interpreter
```

`-y` auto-approves code execution without a confirmation prompt each time:

```
   interpreter \
     --api_base http://127.0.0.1:<PORT>/v1 \
     --model <model-name> \
     --api_key local \
     -y
```

Aider is designed specifically for Git-integrated pair programming and repository modifications. It reads the endpoint from environment variables rather than dedicated CLI flags, and needs the `openai/` prefix on the model name so it routes through its OpenAI-compatible path:

```
   python3 -m pip install aider-chat
cd /path/to/project
   export OPENAI_API_BASE=http://127.0.0.1:<PORT>/v1
   export OPENAI_API_KEY=local
   aider --model openai/<model-name>
```

Goose is an extensible open-source autonomous agent developed by Block.

```
   curl -fsSL https://github.com/block/goose/releases/download/stable/download_cli.sh | CONFIGURE=false bash
   export PATH="$HOME/.local/bin:$PATH"
goose configure
   # Select: Add Provider → Custom / OpenAI-compatible
   # Base URL: http://127.0.0.1:<PORT>/v1
   # API Key:  local
   # Model:    <model-name>
bash
   goose run --text "Audit this directory, find security misconfigurations in JSON files, and correct them."
```


