Matchlock – Secures AI agent workloads with a Linux-based sandbox

Published: (February 8, 2026 at 03:07 AM EST)
5 min read

Source: Hacker News

Matchlock

Matchlock is a CLI tool for running AI agents in ephemeral microVMs. It provides:

  • Network allow‑listing – only explicitly permitted connections are allowed.
  • Secret injection via MITM proxy – secrets are injected safely without ever touching the VM’s filesystem.
  • Secure defaults – everything else (network, storage, etc.) is blocked out‑of‑the‑box.

Your secrets never enter the VM, keeping your workloads isolated and secure.

Why Matchlock?

AI agents need to run code, but giving them unrestricted access to your machine is risky. Matchlock provides a full Linux environment that:

  • Boots in under a second – isolated, disposable, and locked down by default.
  • Injects real credentials in‑flight when the agent calls an API; the sandbox only ever sees a placeholder.
  • Seals the network by default – nothing can leave the sandbox unless you explicitly allow it.
  • Protects your secrets – even if the agent is tricked into running malicious code, your keys never leak and there’s nowhere for data to escape.

Inside the sandbox the agent gets a complete Linux environment where it can:

  • Install packages
  • Write files
  • Create any temporary mess it needs

Outside, your host machine remains untouched. Each sandbox runs on its own copy‑on‑write filesystem that vanishes when you’re done. The experience is identical whether you’re on a Linux server or a MacBook—same CLI, same behavior.

Quick Start

System Requirements

  • Linux – KVM support required
  • macOS – Apple Silicon

Install

brew tap jingkaihe/essentials
brew install matchlock

Usage

Basic

matchlock run --image alpine:latest cat /etc/os-release
matchlock run --image alpine:latest -it sh

Network allow‑list

matchlock run --image python:3.12-alpine \
  --allow-host "api.openai.com" python agent.py

Secret injection (never enters the VM)

export ANTHROPIC_API_KEY=sk-xxx
matchlock run --image python:3.12-alpine \
  --secret ANTHROPIC_API_KEY@api.anthropic.com python call_api.py

Long‑lived sandboxes

# Create a persistent VM (prints the VM ID)
matchlock run --image alpine:latest --rm=false

# Attach to an existing VM
matchlock exec vm-abc12345 -it sh

Lifecycle commands

matchlock list          # list running VMs
matchlock kill          # stop a VM
matchlock rm            # remove a VM
matchlock prune         # clean up stopped VMs

Build from a Dockerfile (uses BuildKit‑in‑VM)

matchlock build -f Dockerfile -t myapp:latest .

Pre‑build a rootfs from a registry image (caches for faster startup)

matchlock build alpine:latest

Image management

# List all images
matchlock image ls

# Remove a local image
matchlock image rm myapp:latest

# Import an image from a tarball
docker save myapp:latest | \
  matchlock image import myapp:latest

SDK

Matchlock ships with Go and Python SDKs that let you embed sandboxes directly in your application. You can programmatically launch VMs, execute commands, stream output, and write files.

Go

package main

import (
	"fmt"
	"os"

	"github.com/jingkaihe/matchlock/pkg/sdk"
)

func main() {
	// Create a client with the default configuration.
	client, _ := sdk.NewClient(sdk.DefaultConfig())
	defer client.Close()

	// Define the sandbox.
	sandbox := sdk.New("alpine:latest").
		AllowHost("dl-cdn.alpinelinux.org", "api.anthropic.com").
		AddSecret("ANTHROPIC_API_KEY", os.Getenv("ANTHROPIC_API_KEY"), "api.anthropic.com")

	// Launch the sandbox and install curl.
	client.Launch(sandbox)
	client.Exec("apk add --no-cache curl")

	// The VM only ever sees a placeholder – the real key never enters the sandbox.
	result, _ := client.Exec("echo $ANTHROPIC_API_KEY")
	fmt.Print(result.Stdout) // prints "SANDBOX_SECRET_a1b2c3d4..."

	// Stream a request to Anthropic's API.
	curlCmd := `curl -s --no-buffer https://api.anthropic.com/v1/messages \
  -H "content-type: application/json" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -d '{"model":"claude-haiku-4-5-20251001","max_tokens":1024,"stream":true,
       "messages":[{"role":"user","content":"Explain TCP to me"}]}'`

	client.ExecStream(curlCmd, os.Stdout, os.Stderr)
}

Python (PyPI)

pip install matchlock
# or
uv add matchlock
import os
import sys

from matchlock import Client, Config, Sandbox

# Define the sandbox.
sandbox = (
    Sandbox("alpine:latest")
    .allow_host("dl-cdn.alpinelinux.org", "api.anthropic.com")
    .add_secret(
        "ANTHROPIC_API_KEY", os.environ["ANTHROPIC_API_KEY"], "api.anthropic.com"
    )
)

curl_cmd = """curl -s --no-buffer https://api.anthropic.com/v1/messages \
  -H "content-type: application/json" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -d '{"model":"claude-haiku-4-5-20251001","max_tokens":1024,"stream":true,
       "messages":[{"role":"user","content":"Explain TCP/IP."}]}'"""

# Use the client to launch the sandbox and run commands.
with Client(Config()) as client:
    client.launch(sandbox)
    client.exec("apk add --no-cache curl")
    client.exec_stream(curl_cmd, stdout=sys.stdout, stderr=sys.stderr)

Full examples

  • Go:
  • Python:

Architecture

graph LR
    subgraph Host
        CLI["Matchlock CLI"]
        Policy["Policy Engine"]
        Proxy["Transparent Proxy + TLS MITM"]
        VFS["VFS Server"]

        CLI --> Policy
        CLI --> Proxy
        Policy --> Proxy
    end

    subgraph VM["Micro‑VM (Firecracker / Virtualization.framework)"]
        Agent["Guest Agent"]
        FUSE["/workspace (FUSE)"]
        Image["Any OCI Image (Alpine, Ubuntu, etc.)"]

        Agent --- Image
        FUSE --- Image
    end

    Proxy -- "vsock :5000" --> Agent
    VFS   -- "vsock :5001" --> FUSE

The diagram shows the relationship between the Matchlock CLI, Policy Engine, Transparent Proxy, and VFS Server on the host side, and the Guest Agent, FUSE workspace, and OCI image inside a micro‑VM (Firecracker or Virtualization.framework). Communication between host and VM occurs over vsock ports 5000 and 5001.

Network Modes

PlatformModeMechanism
LinuxTransparent proxynftables DNAT on ports 80/443
macOSNAT (default)Virtualization.framework built‑in NAT
macOSInterceptiongVisor userspace TCP/IP at L4 (--allow-host / --secret)

Docs

See the full developer reference in AGENTS.md.

License

MIT

0 views
Back to Blog

Related posts

Read more »

Claude Code Is Being Dumbed Down

!Am I out of touch? No, it's the users who are wrong.https://symmetrybreak.ing/images/dont-worry-about-claude/am-i-out-of-touch.webp !Am I out of touch? No, it'...

NetNewsWire Turns 23

Release History NetNewsWire 1.0 for Mac shipped 23 years ago today! 🎸🎩🕶️ Current Work We just shipped 7.0 for Mac and iOS, and now we’re working on NetNewsW...