CLI tool
jingkaihe/matchlock avatar
jingkaihe/matchlock

Matchlock: running AI agents inside ephemeral Linux microVMs

Matchlock secures AI agent workloads with a Linux-based sandbox.

621 stars38 forksGoMIT

At a glance

What is it?
Matchlock is a Go CLI and SDK that boots a disposable Linux VM for agent workloads, with network allowlisting and host-side secret injection. It is experimental, and it needs KVM or Apple Silicon.
Who is it for?
Adopt Matchlock if you are already running agents that execute shell commands or install packages and you want a disposable Linux VM with an explicit egress allowlist and credentials that never enter the guest. Do not adopt it if you need Windows or Intel Mac hosts, or a stable interface: the README labels the project experimental and subject to breaking changes, and the last push was on 2026-07-26.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem Matchlock solves for agent operators

An agent that can run code needs a machine to run it on. Handing it your laptop means handing it your SSH keys, your cloud credentials and your home directory. The README frames the trade-off plainly: agents need to run code, but unrestricted access to your machine is a risk. Matchlock's answer is a full Linux environment that boots in under a second, according to the README, and disappears afterwards.

The audience is narrow and specific. You are running an agent that executes shell commands, installs packages or writes files, and you want that work to happen somewhere that cannot reach your real filesystem or your real API keys. The README describes volume overlay mounts as isolated snapshots that vanish when you are done. If your agent only produces text and never executes anything, this is more machinery than you need.

How the VM, the network seal and the MITM proxy fit together

The isolation boundary is a microVM, not a container namespace. On macOS the dependency list points at github.com/Code-Hex/vz/v3, the Virtualization.framework bindings, which is consistent with the README's Apple Silicon requirement. On Linux the same repository pulls github.com/google/nftables and gvisor.dev/gvisor, so packet filtering and a user-space network stack are part of the host-side machinery.

The network model is deny-by-default once you opt in. The README states that when you pass --allow-host or --secret, Matchlock seals the network and only traffic to explicitly allowed hosts gets through. Secret injection is the part worth understanding: the real credential is injected in-flight by the host, and the sandbox only ever sees a placeholder. The Go SDK example prints SANDBOX_SECRET_a1b2c3d4... when the agent echoes the environment variable, which is what a placeholder looks like from inside.

Interception is not a one-shot decision. The README shows --network-intercept keeping interception enabled even with an empty allowlist, so hosts can be added or removed at runtime with matchlock allow-list add and matchlock allow-list delete against a running VM ID. That is a different posture from baking the allowlist into the launch command.

The Go SDK also exposes request and response mutation through NetworkInterceptionConfig, with phases before and after, header setting and body replacements. That is more than an allowlist; it is a small proxy rule engine. The README does not document what happens to a request whose body does not match a replacement rule, so treat that surface as something to probe rather than trust.

Installing Matchlock and running a first sandbox

The README points at docs/install.md for full details and offers a quick script that detects the OS and installs through Homebrew on macOS or rpm/deb packages on Debian and RHEL flavoured distributions. You can pin a release with the --version flag.

bash
curl -fsSL https://raw.githubusercontent.com/jingkaihe/matchlock/main/scripts/install.sh | bash

# Or install a specific release
curl -fsSL https://raw.githubusercontent.com/jingkaihe/matchlock/main/scripts/install.sh | bash -s -- --version 0.2.4

Homebrew works on both macOS and Linux through the project's tap. On Debian or Ubuntu, the README shows installing the .deb and then running diagnose to check host setup.

bash
sudo dpkg -i ./matchlock_<version>_linux_amd64.deb
sudo apt-get install -f
matchlock diagnose

If diagnose reports missing host setup, the README says to run setup for Linux, and to enroll a specific user explicitly with the user subcommand.

bash
sudo matchlock setup linux
sudo matchlock setup user <name>

A first real run is one line. This boots Alpine and prints the OS release from inside the guest.

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

The more interesting first run adds the two features that distinguish the project. This allows api.openai.com and injects the key only for that host, so the agent process sees a placeholder.

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

export ANTHROPIC_API_KEY=sk-xxx
matchlock run --image python:3.12-alpine \
  --secret [email protected] python call_api.py

For work that outlives a single command, --rm=false prints a VM ID you can attach to later, and detached mode does the same thing. Port forwarding is a separate command against that ID.

bash
matchlock run --image alpine:latest --rm=false
matchlock run --image nginx:latest -d
matchlock exec vm-abc12345 -it sh
matchlock port-forward vm-abc12345 8080:8080

Lifecycle is handled by list, kill, rm and prune. Images can be pre-built from a registry reference to cache for faster startup, and imported from a docker save tarball.

Where Matchlock stops being the right tool

The host requirements are the first wall. Linux needs KVM support and macOS needs Apple Silicon. An Intel Mac or a Linux box without nested virtualization or KVM access is out, and the README offers no fallback path.

The second wall is stability. The README carries an explicit experimental notice: the project is still in active development and subject to breaking changes. A CLI whose flags you script into CI is a liability if those flags move. The last push was on 2026-07-26, so the code is recent, but recency is not a compatibility promise.

Private IP handling is a trap worth naming. In the Go SDK, private ranges 10/8, 172.16/12 and 192.168/16 are blocked by default whenever a network config is sent. If your agent talks to an internal service, you must call AllowPrivateIPs() or WithBlockPrivateIPs(false), and if you bypass the builder and call client.Create directly you must also set BlockPrivateIPsSet to true. The README does not explain what error surfaces when the default silently blocks a call, which is exactly the kind of thing that costs an afternoon.

Finally, Matchlock is not a general container runtime. It runs one workload in one VM with an opinionated network path. If you want long-lived services, orchestration or multi-tenant scheduling, this is the wrong layer.

Matchlock against running the agent in a plain container

The obvious alternative is a container runtime such as Docker with a restricted network and mounted secrets. The difference in approach is where the boundary sits. A container shares the host kernel, so a kernel-level escape is a host compromise. Matchlock's boundary is a virtual machine, which the README describes as VM-level isolation. That costs boot time and memory, and buys a separate kernel.

The second difference is secret handling. A container typically receives the real credential as an environment variable or a mounted file, so anything that can read the process environment has the key. Matchlock's MITM proxy injects the real credential in-flight on the host and gives the guest a placeholder, per the README. That is a materially different threat model for the same convenience.

The third difference is portability of the interface. The README claims the same CLI and same behaviour whether you are on a Linux server or a MacBook. A container setup usually leans on a daemon that behaves differently across platforms. Note that examples/ in the repository includes docker-in-sandbox, so running Docker inside the sandbox is a supported pattern rather than a competing one.

Maintenance, releases and what the MIT licence means here

Matchlock ships tagged releases rather than a rolling main branch, with v0.2.17 on 2026-07-26, v0.2.16 on 2026-06-28 and v0.2.15 on 2026-06-13. The cadence is roughly monthly, and the version numbers are still in 0.2.x, which is consistent with the experimental label. The repository has a .goreleaser.yaml and a packaging/ directory, so the release artefacts are produced by tooling rather than by hand.

Upgrade cost is the thing to budget for. An experimental project at 0.2.x can change CLI flags and SDK method names between minor versions. The Go SDK surface is wide: builders, network interception rules, private IP overrides and MTU settings. Each of those is a place where a bump could require a code change. The README does not document a deprecation policy or a compatibility guarantee, so pin a version in your build and read the release notes before moving.

The licence is MIT. That permits commercial use, modification and redistribution with the licence and copyright notice preserved. It offers no patent grant and no warranty, and it is not legal advice; if you redistribute Matchlock inside a product, have counsel review the notice requirements.

Editorial conclusion

Adopt Matchlock if you are already running agents that execute shell commands or install packages and you want a disposable Linux VM with an explicit egress allowlist and credentials that never enter the guest. Do not adopt it if you need Windows or Intel Mac hosts, or a stable interface: the README labels the project experimental and subject to breaking changes, and the last push was on 2026-07-26. Before committing, run matchlock diagnose on every target host and confirm what it reports, then check that --allow-host and --secret behave as you expect against the API your agent calls.

Frequently asked questions

What is Matchlock and who is it for?

Matchlock is a CLI tool for running AI agents in ephemeral microVMs, written in Go and distributed under the MIT licence. The README describes it as aimed at anyone who needs an agent to run code without giving it unrestricted access to the host machine.

How do I install Matchlock on Linux or macOS?

The README offers an install script that detects the OS and uses Homebrew on macOS or rpm/deb packages on Debian and RHEL flavoured distributions, plus a Homebrew tap for both platforms. After installing, run matchlock diagnose and, if it reports missing host setup, sudo matchlock setup linux.

Does Matchlock need KVM?

Yes on Linux: the README lists Linux with KVM support as a system requirement. On macOS the requirement is Apple Silicon, and the dependency list includes the Virtualization.framework bindings.

How does Matchlock keep API keys out of the sandbox?

When you pass --secret, the README states that the real credential is injected in-flight by the host through a MITM proxy and the sandbox only ever sees a placeholder. The Go SDK example prints a SANDBOX_SECRET_ value when the agent echoes the environment variable.

Can I add allowed hosts after the sandbox has started?

Yes. The README shows launching with --network-intercept to keep interception enabled even with an empty allowlist, then using matchlock allow-list add and matchlock allow-list delete against the VM ID at runtime.

Official sources

  1. Issues
  2. jingkaihe/matchlock on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jingkaihe-matchlock.svg)](https://hysenlabs.com/projects/jingkaihe-matchlock)