runno: running other languages in the browser through a WASI sandbox
Sandboxed runtime for programming languages and WASI binaries. Works in the browser, on your server, or via MCP.
At a glance
- What is it?
- Runno is a set of JavaScript packages that run code in a sandbox, in the browser, in Node, or through an MCP server. It emulates the WASI interface so a fake operating system and file system can exist entirely inside JavaScript, and the browser path is a web component that needs two cross-origin isolation headers before it will run at all.
- Who is it for?
- runno fits a documentation site, a tutorial, or an education product that needs to show code running rather than describe it, and a Node service that needs to execute a snippet in an isolated runtime. It does not fit a user who cannot serve the two cross-origin isolation headers, since the browser path will not start without them, and it does not fit a deployment that needs the chosen language to be a specific version, because the runtimes are not version pinned.
- 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 84 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Four packages for four places to run code
Runno is a collection of JavaScript packages for running code in various languages inside a sandbox, and the four packages map onto four different hosts.
The runtime package, @runno/runtime, provides web components and headless tools for running code examples in the browser.
The sandbox package, @runno/sandbox, is a secure sandbox for running code examples in Node and other JavaScript runtimes.
The wasi package, @runno/wasi, is an isomorphic package for running WebAssembly WASI binaries inside a sandbox.
The mcp package, @runno/mcp, is an MCP server for running code using the sandbox package, which is what puts the whole thing in front of an AI assistant.
There is also a deprecated Python package called runno that works like the sandbox package, and the deprecation is worth noting because it is the sort of thing that catches people out when they follow an older tutorial.
The project is MIT licensed, written in TypeScript, and its home is runno.dev with the documentation on the same site. The repository is a lerna monorepo with the website, the runtime, and the other packages, plus an examples directory, a langs directory, a firebase configuration for the site, and a .nvmrc.
The three goals are stated in the repository description in one sentence: it works in the browser, on your server, or via MCP. That last option is the one that changes who the audience is, because a Model Context Protocol server turns the sandbox into a tool that an assistant can call.
Emulating WASI is what makes it possible in JavaScript
The technical idea underneath the whole project is stated in the README and it is worth understanding before you look at any API.
The project is powered by WASI, the WebAssembly System Interface, which provides a standard way for programs to interact with an operating system. By emulating this interface, Runno can provide a fake file system and operating system, all running within JavaScript.
That is the whole trick, and it explains the design choices that would otherwise look odd. A program compiled to WebAssembly and expecting WASI does not care what is underneath it, so the same binary can run against a real Linux filesystem on a server, against a virtual one in the browser, or against an in-memory structure your Node code passes in.
The mechanism is described in the how does it work section. Runno uses WebAssembly to run code from JavaScript, and the code runs in a unix-like sandbox that connects to a web-based terminal emulator. The README is honest about the fidelity, saying this means it behaves a lot like running code natively on a linux terminal, and that it is not perfect, but it is handy for making code examples run.
The terminal emulator connection is a deliberate choice about the user experience. A code example that produces a prompt, a directory listing, or a coloured error is not the same as one that prints a line of text, and connecting the sandbox to a terminal means the output looks like the output a learner would see on a real machine.
The consequence for you is that the languages you can run are the ones someone has already compiled to WebAssembly with a WASI target, which is what the runtime list reflects.
The browser path, and the two headers that gate it
The runtime package is the one aimed at documentation sites and education, and its selling point is stated plainly: it is very handy for programming education.
Three consequences follow, and they are the reason to use this rather than a hosted code runner. Newbies do not need to install complex programming tools to run code. Programming examples can be made runnable in the browser with no server at all. And simple programs can be tested for correctness inside a sandbox on the user's own machine, which is a meaningful privacy property for a tutorial.
The quickstart is three steps. Install the package.
npm install @runno/runtimeImport it once, in whatever file you use as the entry point, such as main.ts or index.ts.
import "@runno/runtime";And then use the runno elements on the page, where the element carries the runtime name, whether an editor and controls are shown, and the code itself as its content, for example a runno-run element with runtime set to python.
Then comes the part that stops most first attempts. For the code to run, you have to set some HTTP headers, and they are not optional.
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corpThese create a cross-origin isolated context, which allows the use of SharedArrayBuffer, and SharedArrayBuffer is what is used to implement standard input. The reason standard input needs shared memory is that the code runs in a WebAssembly instance on a worker thread while the terminal and the browser side are on the main thread, and a shared buffer is how the two communicate.
So the deployment requirement is real: a page that hosts a runno element has to be served with those two headers, and a site that cannot set them cannot use this path. There is also a separate component for running WASI binaries directly, a runno-wasi element that takes a source and can autorun.
The runtime list, and why it is tied to Runno
The supported runtimes are listed with a version floor rather than a version pin, and the README explains what that means for the future.
The system supports a number of runtimes based on existing packages published to WAPM. These runtimes are tied to Runno and will be supported by Runno going forward.
That sentence is the commitment. The runtimes are not fetched from an arbitrary registry at run time, they are the ones the project has committed to maintaining, which means you can rely on them continuing to work rather than hoping an upstream build stays available.
The list itself is a mix of interpreters, compilers, and tools. Python runs Python 3 code, not pinned to a particular version but at least 3.6. Ruby runs standard Ruby, not pinned but at least 3.2.0. QuickJS runs JavaScript code using the QuickJS engine, and it is the fastest path to a small script. SQLite runs SQLite commands, which makes it a query engine rather than a language. Clang compiles and runs C code, and clangpp compiles and runs C++ code, so those two are full compile and run cycles rather than interpreters. And php-cgi runs PHP CGI compiled by VMWare.
The distinction between the interpreters and the two compilers is the one to keep in mind for performance and for how the examples are written. An interpreter runtime takes the source and runs it, while the clang entry points take C or C++ source, compile it, and run the result, which is slow and heavy but is the only way to demonstrate a language that has no WebAssembly interpreter of its own.
The examples directory in the repository contains more examples of how to use Runno and how to configure it to run, and the full documentation for the runtime package is in its own directory.
The sandbox package, and the MCP server in front of it
The sandbox package is the one you reach for on a server, and its API is deliberately small.
Install it with npm install @runno/sandbox, then call the exported runCode function with a runtime name and a string of code, and inspect the result.
import { runCode } from "@runno/sandbox";
const result = await runCode("ruby", "puts 'Hello, world!'");
if (result.resultType === "complete") {
console.log(result.stdout);
} else {
console.log("Oh no!");
}The resultType check is the important part of that snippet. A run can complete or it can fail or be cut short, and the two cases are distinguished by the field rather than by an exception, so a caller that does not check will happily print an empty stdout and call it success.
For anything that needs a file system, there is runFS, which takes a runtime, an entry path, a WASIFS file system, and optional options for standard input and a timeout.
function runFS(
runtime: Runtime,
entryPath: string,
fs: WASIFS,
options?: {
stdin?: string;
timeout?: number;
},
): Promise<RunResult>;The timeout is what you want in a server context, since a sandboxed program that loops forever is a resource leak, and the standard input option is what lets you feed a program input without a terminal.
The MCP package sits on top of the sandbox and exposes the same capability to an assistant. Configuring it is a matter of adding a server entry, where the command is npx and the arguments name the package.
{
"mcpServers": {
"runno": {
"command": "npx",
"args": ["@runno/mcp"]
}
}
}That is a small and interesting addition to the picture. The same sandbox that powers a tutorial page can be offered to an assistant as a tool, and the constraint that makes it safe is the same one that makes it useful: the code runs inside an emulated operating system rather than on the host.
The wasi package, for completeness, is the low level path. WASI.start sets up everything and runs the Wasm binary directly, with args, env, stdout, stderr, stdin, and a virtual file system. The README warns that this runs on the main thread and not inside a worker, so it will interrupt any interactive use of the browser until it completes, and that the args should start with the name of the binary, the way you would type cat before a file name in a terminal.
Maintenance, the package format change, and what the monorepo needs
The project is not archived and the last push was on 2026-08-01. The release history shows a recent round of consolidation rather than steady feature work, with v0.10.0 in May 2025 introducing the sandbox and MCP packages, v0.10.2 a few hours later fixing dependency issues, and v0.8.0 in April 2025 removing support for umd and cjs.
That last one is the release to notice, because it is a breaking change for consumers. Dropping the universal module definition and the CommonJS builds means the packages are now distributed as ES modules only, and any project still loading them with require will break on upgrade.
The monorepo configuration is straightforward and gives you the environment requirements. The root package is private, named runno, with the version at 0.1.0, the licence MIT, and the engines field requiring Node 22 or newer. The workspaces are the packages directory, and the scripts chain the build in dependency order, building the wasi and runtime packages, then the docs, then the website, then the node sandbox, then the MCP server, with the publish script running the build and then lerna publish.
There is a separate bootstrap script for the node sandbox, which is the one worth noticing, since it suggests that package has a build step of its own rather than being pure TypeScript.
The test scripts are chained the same way, with separate test targets for the wasi, runtime, and node sandbox packages, and the wasi test target has a prepare step before the test run. The overall shape is a project that ships four packages with different build requirements, one website, and a documentation pipeline that copies the package docs into the website directories.
Editorial conclusion
runno fits a documentation site, a tutorial, or an education product that needs to show code running rather than describe it, and a Node service that needs to execute a snippet in an isolated runtime. It does not fit a user who cannot serve the two cross-origin isolation headers, since the browser path will not start without them, and it does not fit a deployment that needs the chosen language to be a specific version, because the runtimes are not version pinned. Verify first that your server can send Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers on the page that hosts the component, that the language you need is one of the listed runtimes, and that the WASI binaries you want to run are compatible with the interface the package emulates.
Frequently asked questions
What are the four packages in the Runno project?
The runtime package provides web components and headless tools for running code examples in the browser, the sandbox package is a secure sandbox for running code in Node and other JavaScript runtimes, the wasi package runs WebAssembly WASI binaries inside a sandbox, and the mcp package is an MCP server that uses the sandbox. There is also a deprecated Python package called runno that behaves like the sandbox package.
Why do I need Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers for Runno?
Those two headers create a cross-origin isolated context, which allows SharedArrayBuffer, and SharedArrayBuffer is what Runno uses to implement standard input. Without them the code in the browser will not run.
Which programming languages can Runno execute?
Python at least version 3.6, Ruby at least 3.2.0, JavaScript through the QuickJS engine, SQLite commands, C and C++ through the clang and clangpp entry points, and PHP CGI. The runtimes are based on packages published to WAPM and are tied to Runno, so they will be supported going forward.
How do I run code with the Runno sandbox package in Node?
Install @runno/sandbox and call the exported runCode function with a runtime name and a string of code, then check the result type before using the stdout. For a virtual file system there is runFS, which takes a runtime, an entry path, a WASIFS file system, and optional stdin and timeout options.
How do I expose Runno as an MCP server?
Add the runno entry to your MCP configuration, with the command set to npx and the arguments naming the @runno/mcp package. The MCP package is a server for running code using the sandbox package, and there is an introduction article on the project site.
Official sources
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.
[](https://hysenlabs.com/projects/taybenlor-runno)Was this useful?