Skip to main content

Specification

An Environment document is YAML or JSON, apiVersion: environments.datalayer.io/v1alpha1, kind: Environment. The models in code_sandboxes.environments.spec are the specification; the JSON Schema at schemas/environment-v1alpha1.json in the repository is exported from them with python -m code_sandboxes.environments schema --write, and other languages generate their types from it.

A document is refused with DL_ENV_SPEC_INVALID when a field is wrong, and with DL_ENV_CAPABILITY_UNSUPPORTED when it is valid but asks for something that cannot be built yet. Every finding is listed, each with the field it is in.

metadata​

FieldRules
nameUnique per owner. A DNS-1123 label: lowercase letters, digits and -, at most 63 characters. The prefixes datalayer-, dl-, kube- and system- are reserved.
titleFree text.
labelsString to string.

spec​

FieldDefaultRules
contractsandbox-contract/v1A supported sandbox contract.
language.namepythonOnly python.
language.version—major.minor, and one the base provides. It is checked against the base, never replaced.
base.ref—An approved base: datalayer/python-cpu or datalayer/python-cuda.
base.channel—The release channel, resolved to a digest per variant when the version is resolved.
platform.architecturelinux/amd64Only linux/amd64.
packages.python.manageruvuv or pip; both are resolved with uv. A conda packages list is not built yet — bring a conda environment.yml as a dependencyFile instead (see build.source).
packages.python.dependenciesnonePEP 508 requirements.
packages.python.constraintsnonePEP 508 requirements, applied under Datalayer's protected constraints, which win.
packages.python.indexeshttps://pypi.org/simplehttps URLs, with no credential in them.
packages.system.aptnonePackage names, optionally name=version.
filesnoneAt most 32 files. path is absolute and normalized, not under /opt/datalayer, and listed once; contentRef is a blob://, https:// or s3:// reference; sizeBytes is at most 1 MiB, 8 MiB for all files together; sha256 is required before a file is built.
envnoneVariable names only. Nothing that looks like a credential, by its name or its value: that belongs in buildSecrets.
commands.postInstallnoneAt most 32 non-empty commands, run after the packages are installed.
buildSecretsnoneid is a Datalayer secret id, dlsec_...; mountAs is env or file; name is the variable or file name. Ids and names are unique. Secrets are injected into the build step that needs them and never written into the artifact.
resources.sizeClasssmallsmall, medium, large, gpu-small or gpu-large. A GPU class needs an accelerator and a CUDA base; an accelerator needs a GPU class. Datalayer runs no GPU nodes yet, so a GPU class is built for Modal and Daytona, which bring their own GPUs; E2B has none.
resources.acceleratornonenone, or type, count and cuda. type is the provider's own name for the GPU (Modal: T4, L4, A10G, L40S, A100, A100-40GB, A100-80GB, H100, H200, B200; Daytona: H100, H200, RTX-PRO-6000, RTX-4090, RTX-5090), and a GPU a variant does not offer is refused for it at validate. cuda is the base's toolkit: datalayer/python-cuda:2026.09 carries 12.8, and another version is refused.
resources.hintsnonecpu, memoryGi, diskGi: positive numbers, within the size class.
compatibility.variants.required[datalayer]At least one of datalayer, e2b, daytona, modal.
compatibility.variants.optionalnoneThe same variants, none of them also required.
compatibility.regionsnoneRegion names.
build.sourcepackagespackages; dependencyFile (a requirements.txt; a pyproject.toml whose own uv.lock is checked against Datalayer's protected pins and exported rather than re-resolved; or a conda environment.yml, resolved in its own micromamba solve into an explicit lock with the protected pins merged over its pip: layer); dockerfile (build.dockerfile.content, inline: its FROM names an approved base with its channel as the tag, which is what resolves, and what its own instructions install is not locked, as the lock's header says); and image (an existing image from a bootstrap registry allowlist, replacing the approved base). packages, a requirements.txt, a pyproject.toml with its uv.lock, a conda environment.yml and dockerfile build on the Datalayer and Daytona variants. A pyproject.toml's uv.lock has to lock Datalayer's jupyter-server fork, which no package index serves: the project takes it by URL from the fork's release, in [tool.uv.sources], which is also what makes uv record its hash. image resolves but does not yet start as a sandbox, because the imported image has no Datalayer runtime layer; image from a private registry, and a COPY from a Dockerfile's build context, are refused.

The spec digest​

spec_digest is sha256: followed by the SHA-256 of the RFC 8785 serialization of spec, with its defaults written out. Two documents that say the same thing — whatever their key order or spacing, and whether or not they spell out a default — have the same digest; any change of value changes it. metadata is not part of it. The digest is one half of the build cache key, with the lock digest and the digest of the resolved base.

Status​

A version's status is written by the platform, never by a user: its number, the spec digest, the lock and its digest, the base resolved per variant, each variant's artifact and its state, and the version's own state.