Kobako: Building a Sandbox for the AI Era
This article is translated by AI, if have any corrections please let me know.
I’ve been working on Kobako for a few months now, and I’ll also be presenting the project at COSCUP. The process has been interesting enough that I think it deserves a series of posts about how I set out to build a sandbox for the AI era.
By the time of writing, there have been around 20 releases. From here on I’ll walk through Kobako’s evolution as close to chronological order as I can, along with the decisions made along the way.
What Will We Need?
In April 2026, right before heading to Japan for RubyKaigi, Harness Engineering was picking up steam. It covers a lot of different topics, and sandbox technology is one that gets relatively little attention, even though every major company has quietly built something for it.
There are plenty of existing approaches: Virtual Machines, microVMs, and Containers are all options. The biggest difference is what they demand from the environment: the closer to a virtual machine, the better the isolation, but the more constraints on small projects and on development. WebAssembly is far lighter by comparison, and it also counts as one of the options, which is what made me take note of it.
Talking with people at RubyKaigi about this topic reminded me of my own read on where things are heading: sandboxes and Virtual File Systems are probably going to be one of the keys. Both exist to run untrusted code, both isolate effectively, and both make safety easier to guarantee.
Does Ruby Have a Sandbox?
I started thinking about this question during RubyKaigi, and the conclusion was that when it comes to AI safety, ruby.wasm is probably the only thing that qualifies. Among the candidates I saw in Harness Engineering, nearly all of them have relatively strong isolation, so WebAssembly fits the criteria better: it is memory-isolated from the host program and runs its own virtual machine inside.
As it happened, that year’s Code Party (sponsors provide the food and the venue, and you work alongside open source project authors) had the author of dRuby walking everyone through drb, a long-standing part of the standard library. This gem cleverly leverages Ruby’s language features, giving Ruby RPC (Remote Procedure Call) in only a few hundred lines.
1# Client
2class Proxy
3 def method_missing(method, *args, **kwargs)
4 raise if @target.respond_to(method)
5
6 @server.send(method, *args, **kwargs)
7 end
8end
9
10# Server
11server = Server.new
12object = Hash.new
13server.bind(object) # Use `object` to handle remote callIn principle, when we listen on TCP, we receive requests along the lines of “call this method for me.” dRuby then calls the method on the Proxy object, and because the method doesn’t exist, method_missing catches it and forwards it to the real object.
There are quite a few details in how this actually works; this only demonstrates the concept and is not the real dRuby implementation
The mechanism is clever: we barely have to define interfaces on the Server and Client sides. We only need Ruby’s ability to handle unknown methods dynamically, and objects can work remotely. That’s what inspired me to start thinking about how to make Ruby and ruby.wasm interact easily.
A Different Expectation
ruby.wasm is currently built on WASI Preview 1 (WebAssembly System Interface), but that version locks down all I/O capabilities. Communicating directly through CRuby’s native dRuby simply stops working, and there’s no way to interact through the WASI stdio interface either, so the original idea was completely out of reach. The one option that met the isolation requirements happened to be stuck on the communication ability I needed most, which left building my own as the only path.
This makes sense, really. Most solutions on the market, such as virtual machines and containers, weren’t designed to deal with AI-generated, untrusted code. They mostly assume code that is trusted, or at least controllable.
The biggest difference is that the path I want to take is closer to Cloudflare’s Code Mode, which is itself an application of sandbox technology: code written by an LLM runs inside V8’s isolated environment, and built-in services extend into it quite naturally. For a sandbox that is easy to extend and easy to use, the Ruby inside WebAssembly has to be able to call the Ruby outside.
During RubyKaigi I was also thinking about what alternatives could get me there. After gathering some information, I chose to work with WebAssembly’s Host Linker (which lets the Guest environment call functions registered by the Host), and set Kobako’s goals as “lightweight” and “easy to use.”
This comes from what I expect out of building software with Ruby, along with the best fit given where things stand today. WebAssembly with mruby can be extremely lightweight, the Host Linker works easily alongside mruby’s C API, and because both Host and Guest use Ruby, it also becomes very easy to use for developers already familiar with Ruby.
What’s left to solve is keeping the interface simple and staying lightweight (smooth startup, smooth calls), and that’s what kicked off these months of Kobako development.
Looking back, there’s nothing wrong with any of those options, and other companies still use them. It’s just that once I filtered by the conditions I wanted, WebAssembly with mruby was what fit best.
Enjoyed this article? Buy me a milk tea 🧋