Quick start

Install the core, boot a sandbox, run commands, touch the filesystem, and snapshot a box.

Lifo ships as @lifo-sh/core — the same package works in a browser bundle and in Node.

Install

npm install @lifo-sh/core

Boot a box and run a command

Sandbox.create() returns a ready-to-use box. Run a command line with sandbox.commands.run() and you get back its stdout, stderr, and exit code.

import { Sandbox } from "@lifo-sh/core";

const sandbox = await Sandbox.create();

const result = await sandbox.commands.run("echo hello && ls -la /");
console.log(result.stdout);
console.log("exit:", result.exitCode);

run() accepts options for the working directory, environment, a timeout, an AbortSignal, streaming callbacks, and stdin:

await sandbox.commands.run("npm install", {
  cwd: "/home/user/my-app",
  env: { CI: "" },
  onStdout: (chunk) => process.stdout.write(chunk),
  onStderr: (chunk) => process.stderr.write(chunk),
});

Seed and read files

Pass files to pre-populate the disk, then use the fs API — an async, promise-based subset of node:fs.

const sandbox = await Sandbox.create({
  cwd: "/home/user/app",
  files: {
    "/home/user/app/index.js": "console.log('hi from a box')",
    "/home/user/app/package.json": JSON.stringify({ name: "app" }),
  },
});

await sandbox.fs.writeFile("/home/user/app/note.txt", "written at runtime");
const entries = await sandbox.fs.readdir("/home/user/app");
const src = await sandbox.fs.readFile("/home/user/app/index.js");

Run Node code

The node command runs real scripts through the Node compatibility layer — ESM or CommonJS, with npm/npx available.

await sandbox.commands.run("node index.js");
await sandbox.commands.run("npx create-vite@latest my-app -- --template react");

See The Node runtime for how this works under the hood.

Attach a terminal (browser)

In the browser, pass a container element or selector and Lifo mounts an xterm.js terminal wired to the box's shell:

const sandbox = await Sandbox.create({
  terminal: "#terminal", // or an HTMLElement, or an ITerminal
  persist: true, // persist the disk to IndexedDB
});

Snapshot and restore

A box's entire disk can be exported to a tar.gz and restored later — the basis for saving and cloning boxes.

const image = await sandbox.fs.exportSnapshot(); // Uint8Array (tar.gz)

const restored = await Sandbox.create();
await restored.fs.importSnapshot(image);

Tip

In Node you can also mount a real host directory into the VM with the mounts option, so a box reads and writes files on your machine. See Browser vs Node.

Next