README.md

Range opens a shell in a container image, a Hugging Face repository, or an environment in S3 or on any HTTP server, without downloading it first. Only the bytes your program reads cross the network.

$ range shell python:3.12 $ range shell python:3.12 --mount hf://moonshotai/Kimi-K2-Instruct:/model $ range shell s3://<your-bucket>/dev.range

No Docker, no daemon and no pull. Linux runs it natively. On macOS, Range runs Linux in a small VM that it manages itself.

Measured on EC2 in us‑east‑1, with the image indexed once. See bench.log.

demo.txt

$ range run ghcr.io/ggml-org/llama.cpp:light-b11206 \

--mount hf://unsloth/gemma-3-270m-it-GGUF:/model -- \

llama-cli -m /model/gemma-3-270m-it-Q4_K_M.gguf -st \

-p "Why is the sky blue? Answer in one sentence."

The sky is blue because of a phenomenon called Rayleigh scattering,

where blue light is scattered more than other colors.

Range opens the llama.cpp image from its registry and mounts the model repository at

/model. The repository holds 6.38 GB in 24 files. Range reads one of them.

With the image indexed, the answer took 6.7 s from an empty cache.

docker pull plus hf download took 18.3 s. The very first run,

which also indexes the image, took 15.5 s.

$ range run python:3.12 --mount hf://moonshotai/Kimi-K2-Instruct:/model -- \

du -sh --apparent-size /model

959G /model

Kimi K2 is 1.03 TB in 61 shards. A Python script inside read its config, the header of one shard and one tensor. That took 3.4 s with the image indexed, and moved 9.5 MB of the model. The other 60 shards never left Hugging Face.

Range reads a file when a program opens it. A program that reads a whole model still downloads the whole model, once.

bench.log

The commands: import json and sqlite3, cargo --version, java -version, and a read of one Kimi K2 tensor. A first run reads each layer once to index it. The python:3.12 index is 4.1 MB. Medians of three, m6i.large, us‑east‑1, 28 September 2026. Every run starts empty, except "again". The bars replay at 3x speed.

problem.txt

A machine that needs a large environment downloads all of it, every time, to use a small part.

Range reads only the bytes each machine touches, and the next run fetches them before it asks.

design.txt

ReadAt(offset, length) -> bytes. Range turns a source into a disk, and turns

each read of that disk into a ranged request to the source.

install.txt

A release archive for macOS or Linux, x86-64 or arm64. On macOS, Range also needs Lima for its Linux VM. Then open a shell in any image:

$ curl -fsSL https://github.com/andreygrehov/range/releases/latest/download/range_$(uname -s)_$(uname -m).tar.gz | tar -xz $ brew install lima # macOS only $ ./range shell python:3.12

For your own environments, build once, and every first run reads lazily:

$ range build --from-oci python:3.12 -o py.range $ range publish py.range s3://<your-bucket>/py.range $ range shell s3://<your-bucket>/py.range

A published artifact needs no indexing. The go1.23 demo artifact was ready in 0.41 s on its first run, and moved 6 MB of 1.03 GB.

Or build from source, with Go 1.25 or newer:

$ git clone https://github.com/andreygrehov/range && cd range && make install

Linux needs root and the nbd, erofs and overlay kernel modules.

range doctor checks them. Windows works through WSL2, untested.

about_me.txt

I am a software engineer at AWS. Range is my personal project.