Skip to content
smol-machinesPublic

About

Manage lifecycle of smol machines, locally and remote, or embedded in your node|python application.

Resources

Contributing

Security policy

Stars

30 stars

Watchers

0 watching

Forks

Repository files navigation

smol machines

CLI release License npm PyPI

smol

Run code in isolated microVM sandboxes — from the command line, or embedded directly in your Node or Python app.

The same code runs on your laptop and in the cloud. One Machine API, two transports: local boots a microVM on the machine you are sitting at (bundled engine, no server, no account), cloud runs the identical calls on smol cloud. Develop and test against a real VM offline, then move the same program to managed capacity by changing where it connects — not what it does:

const spec = { image: 'alpine', network: true };

const dev  = await Machine.create(spec);                       // local: this machine
const prod = await Machine.create(spec, { target: 'cloud' });  // smol cloud

Create, exec, files, state, stop, delete — and branching — behave the same on both. (A handful of local-only concepts, such as host bind mounts, are rejected up front on cloud rather than silently dropped.)

┌──────────────┐     ┌──────────────────────────── one Machine API ┐
│   smol CLI   │     │  LocalTransport  ──▶ embedded smolvm microVM  │
│  (Rust)      │     │  CloudTransport  ──▶ smol cloud /v1 (REST)    │
└──────────────┘     └──────────────────────────────────────────────┘

Install

SDK

npm install smolmachines      # Node
pip install smolmachines      # Python
cargo add smolmachines        # Rust

The Rust crate does not bundle an engine: its local transport runs an installed smolvm with the same major.minor version (and at least the crate's patch), or downloads that smolvm release on first use.

Prebuilt packages bundle everything the local transport needs — the libkrun libraries, a code-signed boot helper, and the guest rootfs — so Machine.create() boots a microVM with no separate install (macOS Apple Silicon and Linux x86_64/arm64, glibc ≥ 2.34). The SDK is in your process; the VMM is not — the engine runs as a separate smol-vmm helper, confined by seccomp and Landlock on Linux, so a guest escape lands there rather than in your application. The cloud transport is pure-language and runs anywhere. Booting a local microVM needs hardware virtualization (macOS Hypervisor.framework or Linux /dev/kvm).

CLI

The standalone smol CLI (create / run / exec, pack .smolmachine artifacts, container registry, cloud deploy) installs with a self-contained bundle — no SDK or separate engine required:

curl -sSL https://raw.githubusercontent.com/smol-machines/smol/main/scripts/install.sh | bash

The script auto-detects your platform, downloads the matching release bundle (which carries its own libkrun runtime + guest agent), verifies its checksum, extracts it to ~/.smol, and symlinks smol onto your PATH (~/.local/bin). Pin a release with SMOL_VERSION=v1.3.7; override locations with PREFIX / BIN_DIR. Supports macOS Apple Silicon and Linux x86_64/arm64.

Components

Path What
sdk/node Node SDK — NAPI native core + TypeScript. Local (embedded) or cloud.
sdk/python Python SDK — pyo3 native core + pure-Python layer. Same API.
sdk/rust Rust SDK — drives a version-matched smolvm locally, or smol cloud over REST. Same API.
src/ The smol CLI (Rust): create / run / exec / files / logs, plus cloud deploy + a container registry.
docs/cli.md CLI command reference.

Branching

Set a machine up once — toolchain, repo, dependencies, warm caches — then branch it copy-on-write. A child inherits the source's RAM and disks, so nothing re-installs: node_modules is there, caches are warm, a process mid-request keeps running.

const source = await Machine.create({ image: 'alpine', network: true, branchable: true });
// ... install deps and warm the caches, once ...
const b = await source.branch('b1');          // typically under 200ms
await b.exec(['npm', 'test']);                // full speed, isolated
const fleet = await source.branchBatch({ count: 8, namePrefix: 'run' });

Branches are the unit of work for agents and CI: a fresh, VM-isolated machine per task without paying boot + setup each time. They work on both transports — locally against the machine in front of you, and on smol cloud, where a batch is atomic (all N branches or none). A branch is always node-local: it lives on the same host as its parent, because it shares that parent's memory pages.

Quickstart — Node

import { Machine } from 'smolmachines';

// Local: no server, no config.
const m = await Machine.create({ resources: { cpus: 2, memoryMb: 1024, network: true } });
try {
  const r = await m.run('python:3.12', ['python', '-c', 'print(2 ** 10)']);
  console.log(r.stdout);            // 1024
  await m.writeFile('/tmp/in.txt', 'hi');
  console.log((await m.readFile('/tmp/in.txt')).toString());
} finally {
  await m.delete();
}

// Cloud: same API, just point at smol cloud.
const c = await Machine.create(
  { image: 'alpine:3.20' },
  { target: 'cloud' }, // uses SMOL_CLOUD_TOKEN
);
try {
  // create() waits for "ready"; cloud state "started" only means VM launched.
  console.log((await c.exec(['echo', 'ready for work'])).stdout);
} finally {
  await c.delete();
}

Quickstart — Python

from smol import Machine, MachineConfig, ResourceSpec, ConnectOptions

# Local (embedded microVM) — context-managed, auto-deletes on exit.
with Machine.create(MachineConfig(resources=ResourceSpec(cpus=2, memory_mb=1024, network=True))) as m:
    r = m.run("python:3.12", ["python", "-c", "print(2 ** 10)"]).assert_success()
    print(r.stdout)                  # 1024

# Cloud — create() waits until the guest agent is reachable. A cloud state of
# "started" means only that the VM launched, not that it is ready for work.
m = Machine.create(
    MachineConfig(image="alpine:3.20"),
    ConnectOptions(target="cloud"),  # uses SMOL_CLOUD_TOKEN
)
try:
    print(m.exec(["echo", "ready for work"]).stdout)
finally:
    m.delete()

Quickstart — CLI

smol run python:3.12 -- python -c "print(2**10)"   # ephemeral one-shot
smol machine create --name mybox --image alpine:3.20 --net   # persistent machine
smol machine start --name mybox
smol machine exec --name mybox -- apk add curl
smol machine ls                                    # lists local + cloud
smol machine rm --name mybox

# smol cloud
smol auth login
smol cloud deploy --image alpine:3.20
smol machine ls --cloud

See docs/cli.md for the full command reference, and run smol <command> --help for flags.

Fused policy rollouts

On a CUDA rollout node, smol rollout declaratively registers a loopback vLLM backend and publishes immutable LoRA versions without exposing vLLM's adapter loader directly. Python and Node training loops use the matching RolloutClient to submit cross-policy cohorts at their generation boundary; unsupported work can retain an ordinary isolated fork pool as the fallback.

smol rollout executor ensure qwen --endpoint http://127.0.0.1:8000 \
  --adapter-root /var/lib/smol/adapters --fallback-pool isolated-rollouts
smol rollout policy publish --executor qwen --policy experiment-a \
  --version step-40 --adapter /var/lib/smol/adapters/experiment-a/step-40

The command connects to the node API at http://127.0.0.1:8080/api/v1 by default; override it with --api-url when the loopback listener uses another port.

Building from source / the engine core

This repository is the open smol SDK + CLI (Apache-2.0). The microVM engine it links — smolvm, which wraps libkrun — is also open source (Apache-2.0), in its own repository: smol-machines/smolvm. The published packages bundle prebuilt engine binaries so you don't have to build it yourself.

The Rust crates here (src/ CLI and the sdk/*/src native cores) declare a path dependency on the engine (smolvm = { path = ".." }), so a native build needs the smolvm repo checked out alongside this one — a checkout of just this repo does not build standalone. You can still read and modify the SDK/CLI source, the TypeScript/Python layers, tests, and docs without it; full native builds are produced by maintainers' CI. Most contributions don't need a native build — see CONTRIBUTING.md. To report a security issue, see SECURITY.md.

License

Apache-2.0.

About

Manage lifecycle of smol machines, locally and remote, or embedded in your node|python application.

Resources

Contributing

Security policy

Stars

30 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages