I work on a Mac. Every now and then I need a quick Linux shell to test a script, try out a package, or run some untrusted code. The usual options are Docker, Lima, or spinning up a full VM. They all work, but none of them felt right for what I actually wanted.
Docker brings a lot of machinery for what is essentially "give me a shell I can throw away". Lima is nice but the defaults aren't what I want, and I don't like having to wonder whether I turned off the stuff I don't need. Full VMs are overkill.
I wanted something where I type one command and I am in a clean Linux environment. When I am done, everything disappears. No config files, no cleanup, no wondering what state things are in.
So I built Shuru.
What It Does
Shuru spins up lightweight Linux VMs on macOS using Apple's Virtualization.framework. It boots in about a second on Apple Silicon.
# That's it. You are in a Linux shell.
shuru run
# Run a command and exit
shuru run -- echo hello
# Need networking? Ask for it.
shuru run --allow-net
Everything is ephemeral by default. The rootfs resets on every run. Install anything, break anything, it's all gone when you exit. No networking unless you explicitly pass --allow-net. No shared directories with the host. Just a clean sandbox.
Defaults That Make Sense
This was the core design decision. I did not want to build another tool where you spend time configuring things before you can actually use it.
- Ephemeral by default. Every run starts from a clean rootfs. Nothing persists unless you explicitly checkpoint.
- No networking by default. The VM doesn't even get a network device unless you ask for it. Not "networking is on but firewalled," there is literally no network hardware in the VM.
- No host filesystem access. No shared directories, no mounted volumes. The sandbox is completely isolated.
-
Sensible resource defaults. 2 CPUs, 2GB RAM. Override with
--cpusand--memoryif you need to.
The philosophy is: everything is off unless you turn it on. If you are running untrusted code from an AI agent, these are the defaults you want. You shouldn't have to think about whether you accidentally left something enabled.
I think of it like the Rails approach to defaults. Make opinionated choices so the user doesn't have to make them. And the choices should be safe ones.
Checkpoints
Sometimes you need to persist state. Maybe you have installed Python and a bunch of packages, and you don't want to redo that every time.
# Install stuff and save the state
shuru checkpoint create myenv --allow-net -- sh -c 'apk add python3 gcc'
# Run from that checkpoint (still ephemeral, changes are discarded)
shuru run --from myenv -- python3 script.py
# Branch from an existing checkpoint
shuru checkpoint create myenv2 --from myenv --allow-net -- sh -c 'pip install numpy'
Checkpoints work like git commits for your environment. You can branch from them, and runs from a checkpoint are still ephemeral. The checkpoint itself is preserved, but any changes during the run disappear on exit.
Under the hood this uses APFS copy-on-write clones, so creating a checkpoint is instant and takes almost no extra disk space.
Port Forwarding Without Networking
This one is fun. You can expose ports from the guest to the host without giving the VM any network access.
shuru run -p 8080:8000 -- python3 -m http.server 8000
# curl http://127.0.0.1:8080/ from your Mac
It works because port forwarding goes over vsock (a direct hypervisor channel between host and guest), not through a network stack. So you can run a web server inside the sandbox, access it from your Mac, but the sandbox itself has zero internet access.
Directory Mounts (Without Touching Your Files)
You can share host directories into the sandbox. But here's the thing: the host directory is read-only under the hood. There's a tmpfs overlay on top, so the guest can read and modify files freely, but all writes stay in memory. Your host files are never touched.
# Mount a directory (guest can write, host is untouched)
shuru run --mount ./src:/workspace -- ls /workspace
# Multiple mounts
shuru run --mount ./src:/workspace --mount ./data:/data -- sh
This is useful when you want an AI agent to work on your codebase without risking it messing up your actual files. The agent sees the full repo, can make changes, run tests, whatever. When the VM exits, your checkout is exactly how you left it.
Why VMs and Not Containers?
Containers share the host kernel. The isolation is done with Linux namespaces and cgroups, which are basically the kernel saying "pretend you can't see the other stuff". If someone finds a kernel vulnerability, they can escape the container and access the host.
VMs run their own kernel. The isolation is enforced by the hypervisor at the hardware level. The guest can't even see the host kernel, let alone exploit it.
For running code I didn't write, especially code generated by AI agents, VM isolation felt like the right tradeoff. The guest can be root, install anything, break anything. Worst case, it trashes its own VM, which gets deleted on exit anyway.
On macOS you need a Linux VM to run containers anyway (there's no native Linux kernel). Shuru just talks to the hypervisor directly and skips the container runtime entirely.
How It's Built
Shuru is written in Rust. Five crates:
-
shuru-cli: the
shurucommand, orchestrates everything - shuru-vm: builds the VM config, handles vsock communication
- shuru-darwin: low-level Objective-C bindings to Virtualization.framework
-
shuru-guest: PID 1 inside the VM, cross-compiled to
aarch64-unknown-linux-musl - shuru-proxy: network proxy engine (WIP)
The guest OS is Alpine Linux (3.21, linux-virt kernel 6.12). The initramfs is a custom ~55 line shell script that loads VirtIO drivers, resizes the filesystem, and hands off to the Rust guest binary. No systemd, no cloud-init, no SSH daemon. That's a big part of why it boots so fast.
Communication between host and guest is entirely over vsock, a kernel-enforced hypervisor channel. No network-level attack surface.
What Happened When I Open Sourced It
I built Shuru for myself. Wasn't planning to make a big deal out of it. Posted it as a Show HN and it hit #3 on the front page (#1 on the show page). 468 GitHub stars in 4 days. 211 upvotes on Hacker News.
What surprised me most was that the thing people responded to wasn't some technical feature. It was the defaults. People kept saying "this is exactly what I wanted but didn't want to configure Lima/Docker for." One commenter said they'd had the same experience with Lima, that the defaults weren't what they wanted and they didn't like having to wonder whether they'd turned off the stuff they didn't need.
That was validating. I built Shuru because I had a specific opinion about how these tools should work by default, and it turns out a lot of other people shared that opinion.
What's Next
Keeping it minimal. Shuru is not trying to be Lima or Docker or OrbStack. It's a small, opinionated tool that does one thing well: give you a clean, isolated Linux environment in one command. There's a lot I could add, but the hard part is knowing what to leave out.
curl -fsSL https://shuru.run/install.sh | sh
shuru run
Source: github.com/superhq-ai/shuru
Shuru requires macOS on Apple Silicon.


Top comments (0)