andreygrehov/range

Go

0

2 commits

updated Sep 28, 2026

See the code

See what people are saying

README

Range

Use a remote environment before downloading it.

Range opens a shell inside a container image, a Hugging Face repository, or an environment in S3, on an HTTP server or in a local file, without downloading it first. It reads only the bytes your program touches, caches them, and remembers which ones the next run will need. No Docker, no daemon and no pull.

Try it

Any image from a container registry:

range shell python:3.12

A chat model, from nothing, in one line. Range opens the llama.cpp image from its registry and mounts the model repository at /model:

$ 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.

A 1 TB model, open in seconds:

$ 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 in 3.4 s, and moved 9.5 MB of the model. The other 60 shards never left Hugging Face. The chat answer took 6.7 s, where docker pull plus hf download took 18.3 s. Both runs are on EC2 in us-east-1, from an empty cache, with the image indexed once (see Numbers).

Install

A release archive, for macOS or Linux on x86-64 or arm64:

curl -fsSL https://github.com/andreygrehov/range/releases/latest/download/range_$(uname -s)_$(uname -m).tar.gz | tar -xz
./range doctor

On macOS, environments run in a small Linux VM managed by Lima (brew install lima). Range creates the VM on first use and installs nothing in it but a Linux build of itself, which ships in the archive as range-linux-<arch>. Keep it next to range.

From source, with Go 1.25 or newer:

git clone https://github.com/andreygrehov/range && cd range
make install    # into ~/.local/bin

Make your own

range build --from-oci golang:1.23 -o go.range     # no container runtime needed
range publish go.range s3://<your-bucket>/go.range
range shell s3://<your-bucket>/go.range
range run s3://<your-bucket>/go.range -- go test ./...

range build also takes a directory. --platform linux/amd64 builds for another architecture, so a Mac can build for an x86 fleet.

How it works

image / Hugging Face / S3 / HTTP / file  ->  block cache  ->  /dev/nbdN  ->  EROFS  ->  overlay  ->  your shell
                                                  ^
                                          learned working set

A container image stays in its registry. The first run reads each layer once to index it: where every file starts in the layer, and the points to resume gzip or zstd decompression from. For python:3.12 the index is 4.1 MB, 1% of the image. After that, reading a file costs one ranged request to the registry, checked against a SHA-256 for every 64 KiB. A Hugging Face repository works the same way, with the file list from the Hub API pinned to one commit.

An artifact is one object: an EROFS filesystem in 1 MiB chunks, each compressed on its own and checked against its SHA-256 when read. Range does not store chunks of zeroes and stores identical chunks once. Range serves it to the kernel as a network block device, mounts it read-only under a writable overlay, and starts your command in fresh namespaces. Writes stay local, and Range discards them when the session ends, unless you ask to keep them.

Each session records the blocks it needed. The next session fetches them in the background before they are asked for, without ever delaying a real read.

Numbers

From an empty cache to the command's output, on an m6i.large in us-east-1, 28 September 2026. Medians of three. "Indexed" means Range indexed the image once before. "Again" keeps the cache of the run before.

Workloaddocker pullRange, first runRange, indexedRange, again
Chat demo (llama.cpp + Gemma 270M)18.3 s, 579 MB15.5 s, 590 MB6.7 s, 317 MB4.3 s, 0 MB
python:3.12, import json and sqlite315.8 s, 435 MB16.5 s, 415 MB2.8 s, 48 MB1.2 s, 0 MB
rust:1.82, cargo --version19.6 s, 569 MB22.4 s, 546 MB8.0 s, 125 MB1.6 s, 0 MB
eclipse-temurin:21, java -version7.9 s, 232 MB9.2 s, 225 MB2.9 s, 49 MB1.0 s, 0 MB
Kimi K2 (1.03 TB), read one tensornot tried17.6 s, 433 MB3.4 s, 56 MB1.3 s, 0 MB

The first run of an image reads its layers whole, as docker pull does. Here it took from 15% less to 16% more time than docker pull. The gain starts with the second run of an image.

With a Range artifact, on 23 September 2026: the workload is go build ./... in a Go repository inside a 2.1 GB dev image. Every arm ran on the same fresh EC2 host with nothing cached. Each value is the median of five runs.

ApproachTimeNetwork
Pull the image, then run21.46 s652 MB
SOCI9.23 s202 MB
eStargz10.71 s102 MB
eStargz with prioritized files7.59 s101 MB
Range, first run7.33 s89 MB
Range, learned2.88 s90 MB

Shipping a one-dependency change to five fresh workers took 1172 s by re-baking an AMI and 100 s by rebuilding the artifact. Setup, method and the rest of the measurements are in docs/BENCHMARKS.md.

Requirements

  • Linux: root, the nbd, erofs and overlay kernel modules, and mount and unshare from util-linux.
  • macOS: Lima.
  • Windows: the Linux build inside WSL2, untested.

range doctor checks all of it and says what is missing.

Limitations

  • The first run of a container image reads its layers whole to index them. Private registries and gated Hugging Face models are not supported yet.
  • An environment is not a security boundary. It runs as root in namespaces on the host's network. Run untrusted code inside a VM.
  • One architecture per artifact, as with container images.
  • Artifacts are immutable. A changed object is a new artifact, and a session that sees its object change fails instead of mixing the two.
  • Chunks are deduplicated within an artifact, not across artifacts yet.

Documentation

License

Apache 2.0. See LICENSE and NOTICE.

andreygrehov/range

Go

0

2 commits

updated Sep 28, 2026

See the code

See what people are saying

README

Range

Use a remote environment before downloading it.

Range opens a shell inside a container image, a Hugging Face repository, or an environment in S3, on an HTTP server or in a local file, without downloading it first. It reads only the bytes your program touches, caches them, and remembers which ones the next run will need. No Docker, no daemon and no pull.

Try it

Any image from a container registry:

range shell python:3.12

A chat model, from nothing, in one line. Range opens the llama.cpp image from its registry and mounts the model repository at /model:

$ 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.

A 1 TB model, open in seconds:

$ 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 in 3.4 s, and moved 9.5 MB of the model. The other 60 shards never left Hugging Face. The chat answer took 6.7 s, where docker pull plus hf download took 18.3 s. Both runs are on EC2 in us-east-1, from an empty cache, with the image indexed once (see Numbers).

Install

A release archive, for macOS or Linux on x86-64 or arm64:

curl -fsSL https://github.com/andreygrehov/range/releases/latest/download/range_$(uname -s)_$(uname -m).tar.gz | tar -xz
./range doctor

On macOS, environments run in a small Linux VM managed by Lima (brew install lima). Range creates the VM on first use and installs nothing in it but a Linux build of itself, which ships in the archive as range-linux-<arch>. Keep it next to range.

From source, with Go 1.25 or newer:

git clone https://github.com/andreygrehov/range && cd range
make install    # into ~/.local/bin

Make your own

range build --from-oci golang:1.23 -o go.range     # no container runtime needed
range publish go.range s3://<your-bucket>/go.range
range shell s3://<your-bucket>/go.range
range run s3://<your-bucket>/go.range -- go test ./...

range build also takes a directory. --platform linux/amd64 builds for another architecture, so a Mac can build for an x86 fleet.

How it works

image / Hugging Face / S3 / HTTP / file  ->  block cache  ->  /dev/nbdN  ->  EROFS  ->  overlay  ->  your shell
                                                  ^
                                          learned working set

A container image stays in its registry. The first run reads each layer once to index it: where every file starts in the layer, and the points to resume gzip or zstd decompression from. For python:3.12 the index is 4.1 MB, 1% of the image. After that, reading a file costs one ranged request to the registry, checked against a SHA-256 for every 64 KiB. A Hugging Face repository works the same way, with the file list from the Hub API pinned to one commit.

An artifact is one object: an EROFS filesystem in 1 MiB chunks, each compressed on its own and checked against its SHA-256 when read. Range does not store chunks of zeroes and stores identical chunks once. Range serves it to the kernel as a network block device, mounts it read-only under a writable overlay, and starts your command in fresh namespaces. Writes stay local, and Range discards them when the session ends, unless you ask to keep them.

Each session records the blocks it needed. The next session fetches them in the background before they are asked for, without ever delaying a real read.

Numbers

From an empty cache to the command's output, on an m6i.large in us-east-1, 28 September 2026. Medians of three. "Indexed" means Range indexed the image once before. "Again" keeps the cache of the run before.

Workloaddocker pullRange, first runRange, indexedRange, again
Chat demo (llama.cpp + Gemma 270M)18.3 s, 579 MB15.5 s, 590 MB6.7 s, 317 MB4.3 s, 0 MB
python:3.12, import json and sqlite315.8 s, 435 MB16.5 s, 415 MB2.8 s, 48 MB1.2 s, 0 MB
rust:1.82, cargo --version19.6 s, 569 MB22.4 s, 546 MB8.0 s, 125 MB1.6 s, 0 MB
eclipse-temurin:21, java -version7.9 s, 232 MB9.2 s, 225 MB2.9 s, 49 MB1.0 s, 0 MB
Kimi K2 (1.03 TB), read one tensornot tried17.6 s, 433 MB3.4 s, 56 MB1.3 s, 0 MB

The first run of an image reads its layers whole, as docker pull does. Here it took from 15% less to 16% more time than docker pull. The gain starts with the second run of an image.

With a Range artifact, on 23 September 2026: the workload is go build ./... in a Go repository inside a 2.1 GB dev image. Every arm ran on the same fresh EC2 host with nothing cached. Each value is the median of five runs.

ApproachTimeNetwork
Pull the image, then run21.46 s652 MB
SOCI9.23 s202 MB
eStargz10.71 s102 MB
eStargz with prioritized files7.59 s101 MB
Range, first run7.33 s89 MB
Range, learned2.88 s90 MB

Shipping a one-dependency change to five fresh workers took 1172 s by re-baking an AMI and 100 s by rebuilding the artifact. Setup, method and the rest of the measurements are in docs/BENCHMARKS.md.

Requirements

  • Linux: root, the nbd, erofs and overlay kernel modules, and mount and unshare from util-linux.
  • macOS: Lima.
  • Windows: the Linux build inside WSL2, untested.

range doctor checks all of it and says what is missing.

Limitations

  • The first run of a container image reads its layers whole to index them. Private registries and gated Hugging Face models are not supported yet.
  • An environment is not a security boundary. It runs as root in namespaces on the host's network. Run untrusted code inside a VM.
  • One architecture per artifact, as with container images.
  • Artifacts are immutable. A changed object is a new artifact, and a session that sees its object change fails instead of mixing the two.
  • Chunks are deduplicated within an artifact, not across artifacts yet.

Documentation

License

Apache 2.0. See LICENSE and NOTICE.

Languages

Go

99.5%