upstream
upstream/README.md
01snapshot & fork

Sandboxes
that fork.

Every AI agent gets its own microVM. Set one up once, then fork it mid-task into as many copies as you need.

A parent's memory pages above three forks. Most of each fork's pages are hollow outlines, still shared with the parent; a few are solid gold, copied when the fork wrote to them.
shared with parent copied on write
02sharing

Forks share pages
until they write.

A fork maps its parent's memory instead of copying it. Each hollow page is still shared. A page turns gold when the fork writes to it, and only then is it copied.

copy-on-write4 KiB pages
Four sandbox disks contain 24 block references and 9 unique blocks. Matching content IDs converge on one stored block; four references to content 00 share one stored copy.
03deduplication

Identical blocks,
stored once.

Every disk is made of blocks named by their content. In this example, four sandboxes reference 24 disk blocks. Only 9 are different, so the store keeps 9.

sha-256512 KiB blocks
Two agents run in separate sandboxes with private writes and their own DNS and firewall controls. Both read the same read-only base image. Outbound traffic passes through each sandbox’s policy gate; access across the sandbox boundary is blocked.
04isolation

A wall around
every agent.

Each agent runs in its own microVM, with private memory, files and network. DNS and firewall rules control outbound access. Agents can read the shared base, but cannot change it or reach neighbouring sandboxes.

KVM boundaryDNS + firewalloutbound rules
05in code

Fork it from Python.

Prepare a repository once, then try one candidate fix per fork and keep whichever passes.

fork_and_test.pyopen
import os
from upstream import Upstream

REPO = "https://github.com/you/app"
SETUP = f"git clone {REPO} app && cd app && uv sync"
TEST = "cd app && git apply fix.patch && uv run pytest -q"

client = Upstream(api_key=os.environ["UPSTREAM_API_KEY"])


def try_fixes(patches):
    with client.sandbox(template="python") as base:
        base.exec(["sh", "-c", SETUP])

        # one prepared machine, one fork per candidate fix
        forks = [base.fork() for _ in patches]

        for sb, patch in zip(forks, patches):
            sb.write_file("/workspace/app/fix.patch", patch)
            r = sb.exec(["sh", "-c", TEST])
            print(sb.sandbox_id, "pass" if r.exit_code == 0 else "fail")
            sb.destroy()
snapshot

Capture the whole machine

Memory, CPU state and disk are captured together, so a fork resumes mid-flight instead of booting cold.

parent

The original keeps going

The parent pauses only while its state is captured, then carries on.

forks

Each fork stands alone

It has its own ID, token and network. You can keep it, fork it again or destroy it.

06uses

Anywhere an agent needs a real computer.

01

Coding agents

Run Claude Code, Codex or your own agent with a full shell and no risk to your laptop or production.

02

Code interpreter

Give an assistant its own Python machine to analyse uploaded files, run code and hand back results.

03

Evals & training

Start every rollout from the same machine state, so any difference in results comes from the model.

04

CI runners

Build and test every change, including agent-written ones, in a fresh VM restored from a warm template.

05

Live previews

Expose a port from inside a sandbox so a person or an agent can open the running app in a browser.

06

Debug from failure

Fork the machine the moment a test fails, then dig into the copy without re-running any setup.

07

Checkpoint & resume

Snapshot a long-running agent's machine and restore it later where it left off.

08

Untrusted code

Execute code from users, models or pull requests behind a VM boundary with controlled egress.

07how it's built

From the page fault to the browser.

Written mostly in Rust, on top of Firecracker and Kubernetes. It runs on dedicated bare-metal servers, and the same stack can run on your own hardware.

computeFirecracker microVMs on KVM · Rust guest agent as PID 1 · warm pool of restored VMs per template
memoryuserfaultfd copy-on-write across fork chains · per-page reverse index · lz4 spill for diverged pages
storagecontent-addressed block store · copy-on-write NBD overlays per sandbox · snapshot prefetch
networknamespace + TAP per VM · nftables egress policy · per-sandbox DNS
securityno inbound ports · OIDC at the edge, the proxy and the gateway · HMAC-scoped sandbox tokens · per-tenant rate limits
platformKubernetes on Talos Linux · bare metal · ingress only through an outbound Cloudflare tunnel
interfacesConnectRPC + REST API · WebSocket terminal · Python SDK · React console · metered per compute-second
One snapshot branches into three forks, then nine. Small synchronized pulses follow the branches to separate endpoints.
08start

Snapshot once.
Fork many times.

Capture a running machine, then branch it as often as you like through the API or the Python SDK.

Read the docs →