No description
Find a file
Armin Ronacher 0d09de1f28
feat(vm): Auto pause (#112)
This PR adds conservative QEMU auto-pause support for idle sandboxes. On
macOS/HVF, QEMU VMs now default to pausing after 30s of inactivity via
QMP, with a configurable `qemuIdlePauseMs` option to tune or disable the
behavior. The controller creates a short QMP socket path, issues
`stop`/`cont`, cleans up sockets, and disables idle pause if QMP becomes
unreliable.

The sandbox server now tracks guest activity across execs, queued work,
VFS requests, SSH/ingress TCP streams, and network sessions so VMs are
only paused when truly idle. Any new activity resumes the VM before
proceeding, including exec admission and filesystem handling, while
tests cover QMP pause/resume wiring, exec queue accounting during
pending resumes, and network activity preventing premature pause.

Fixes #109
2026-05-18 16:09:57 +02:00
.github ci: make krun runner publish release-blocking 2026-05-08 08:08:24 +02:00
.husky refactor(host): split ws server and add tooling 2026-02-03 17:48:57 +01:00
docs feat(http): support custom secret placeholders 2026-05-11 22:55:06 +02:00
guest Replace deprecated uv TLS env var 2026-05-07 15:05:00 +02:00
host feat(vm): Auto pause (#112) 2026-05-18 16:09:57 +02:00
images feat(rootfs): support runtime rootfs sizing (#107) 2026-05-11 10:24:55 +02:00
packages Release v0.10.0 2026-05-13 12:48:35 +02:00
scripts Replace setup-zig action with own install script (#102) 2026-05-07 11:55:09 +02:00
.gitignore fix(guest): drain TCP socket before closing on POLL.HUP in ingress forwarder (#87) 2026-04-21 09:57:37 +02:00
.prettierignore ref: Reformat with prettier 2026-02-15 14:16:59 +01:00
AGENTS.md Use sandbox helpers for build cmd, removing zig dep (#99) 2026-05-07 10:18:24 +02:00
builtin-image-registry.json chore(images): update registry for alpine-base:0.2.0 2026-04-21 10:14:19 +00:00
builtin-sandbox-helper-registry.json chore(helpers): update registry for gondolin:0.10.0 2026-05-13 10:51:20 +00:00
CHANGELOG.md Release v0.10.0 2026-05-13 12:48:35 +02:00
LICENSE docs: update READMEs with compelling intro and add Apache-2.0 license 2026-02-05 00:23:09 +01:00
Makefile chore: fix krun-runner build 2026-04-02 16:18:44 +02:00
package.json Experimental libkrun support (#70) 2026-03-06 18:58:19 +01:00
pnpm-lock.yaml Release v0.10.0 2026-05-13 12:48:35 +02:00
pnpm-workspace.yaml Experimental libkrun support (#70) 2026-03-06 18:58:19 +01:00
README.md feat(rootfs): support runtime rootfs sizing (#107) 2026-05-11 10:24:55 +02:00
zensical.toml docs(sdk): shorten nav labels and page titles 2026-02-16 22:58:39 +01:00

Gondolin Agent Sandbox

Local Linux micro-VMs with programmable network and filesystem control.

AI agents increasingly run generated code without human review. That code often needs network access and credentials, which creates exfiltration risk.

Gondolin runs that code inside a fast local Linux micro-VM (QEMU by default, with an optional experimental krun backend) while keeping network and filesystem access under host-side policy control. That policy layer can be customized via JavaScript.

Quick Example

import { VM, createHttpHooks } from "@earendil-works/gondolin";

const { httpHooks, env } = createHttpHooks({
  allowedHosts: ["api.github.com"],
  secrets: {
    GITHUB_TOKEN: {
      hosts: ["api.github.com"],
      value: process.env.GITHUB_TOKEN,
    },
  },
});

const vm = await VM.create({ httpHooks, env });

// String form runs in /bin/sh -lc "..."
const result = await vm.exec(`
  curl -sS -f \
    -H "Accept: application/vnd.github+json" \
    -H "Authorization: Bearer $GITHUB_TOKEN" \
    https://api.github.com/user
`);

console.log("exitCode:", result.exitCode);
console.log("stdout:\n", result.stdout);
console.log("stderr:\n", result.stderr);

await vm.close();

The guest only sees a placeholder token. The real secret is injected by the host only for allowed destinations (including Authorization: Basic ... flows).

CLI Quick Start

npx @earendil-works/gondolin bash

Useful session commands:

# List running sessions
npx @earendil-works/gondolin list

# Attach to an existing session
npx @earendil-works/gondolin attach <session-id>

# Snapshot a running session (stops it)
npx @earendil-works/gondolin snapshot <session-id>

# Resume from snapshot id/path
npx @earendil-works/gondolin bash --resume <snapshot-id-or-path>

Guest assets (kernel/initramfs/rootfs plus optional krun boot artifacts, ~200MB+) are resolved automatically on first use via builtin-image-registry.json and cached locally. When no image is specified, Gondolin uses GONDOLIN_DEFAULT_IMAGE (default: alpine-base:latest).

Requirements:

macOS Linux (Debian/Ubuntu)
brew install qemu node sudo apt install qemu-system-arm nodejs npm

Optional experimental libkrun backend setup:

make krun-runner

Published installs of @earendil-works/gondolin also include platform-specific optional runner packages for supported targets.

This stages libkrun under .cache/ (no global install) and builds the local runner helper at host/krun-runner/zig-out/bin/gondolin-krun-runner. On macOS, the build ad-hoc signs the runner with the com.apple.security.hypervisor entitlement so Hypervisor.framework access is allowed. When present, Gondolin auto-detects this runner for --vmm krun.

Linux prerequisites for make krun-runner (Ubuntu/Debian):

sudo apt install \
  build-essential curl git make pkg-config clang lld xz-utils \
  libclang-dev llvm-dev libcap-ng-dev

# libkrun requires a modern Rust toolchain (edition2024)
curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal
. "$HOME/.cargo/env"

# install Zig 0.16.0 for your Linux architecture

When vmm=krun is selected, Gondolin requires krun boot assets from the selected image manifest (assets.krunKernel and optional assets.krunInitrd). For custom kernels/initrds, provide an explicit sandbox.imagePath asset object.

Linux and macOS are supported. ARM64 is the most tested runtime path today. Linux x86_64 make krun-runner is covered by CI smoke builds.

Feature Highlights

  • Local disposable micro-VMs for agent turns/tasks
  • Programmable HTTP/TLS egress policy (allowlists + request/response hooks)
  • Secret injection without guest exposure via placeholders
  • Programmable VFS mounts that allow you to write custom file system behavior in JavaScript.
  • Ingress gateway to expose guest HTTP services on host (--listen, vm.enableIngress())
  • Attaching allows you to attach a shell to an already running VM
  • SSH support
    • host -> guest access (vm.enableSsh())
    • optional guest -> upstream allowlisted SSH egress (proxied, exec-oriented)
  • Disk checkpoints (snapshots) with resume support
  • Custom image builds (Alpine-based build pipeline, optional OCI rootfs source)
  • Configurable DNS behavior (synthetic, trusted, open), rootfs modes (readonly, memory, cow), and runtime rootfs sizing

Documentation

Repository Guides

  • Host package: installation, CLI usage, and SDK examples
  • Guest sandbox: Zig build and image/initramfs pipeline
  • images/: canonical image release build configs (used by image-release workflow)
  • Examples: end-to-end integration examples

Pi Extension

There is a Pi + Gondolin extension that runs pi tools inside a micro-VM and mounts your project at /workspace.

AI Use Disclaimer

This codebase has been built with the support of coding agents.