/environments.md. The full docset is at /llms-full.md and the index is at /llms.md.Environments
Every job runs your script as Bash on a fresh machine. The environment mode decides what C3 installs first.
| Your project | Use | C3 prepares |
|---|---|---|
Python with a pyproject.toml | python: | A uv virtualenv from uv.lock, cached across jobs |
| Anything with system packages, other languages, custom CUDA | docker: | A public Docker Hub or GitHub Container Registry image, your script runs inside it |
| Self-contained binaries or scripts with no setup | neither | Nothing. The script runs directly on the machine |
python: and docker: cannot be combined. Setup done inside the script itself runs again on every job.
Python
project: python-example
script: run.sh
hardware: l40
time: "02:00:00"
python:
project: ./
output:
- ./results
# run.sh
#!/bin/bash
set -euo pipefail
python3 train.py --output "$C3_ARTIFACTS_DIR"
# pyproject.toml
[project]
name = "python-example"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = ["jax[cuda12]", "numpy"]
C3 runs uv sync before your script and caches the environment by the lock file, so repeat jobs skip the install. Create or refresh the lock file locally:
uv lock
If you only have a requirements.txt, create a pyproject.toml with uv init and uv add -r requirements.txt, then uv lock. If the project is in a subdirectory, point python.project at it.
Docker
project: docker-example
script: run.sh
hardware: l40
time: "02:00:00"
docker:
image: pytorch/pytorch:2.4.0-cuda12.4-cudnn9-runtime
requires_accelerator: cuda
output:
- ./results
C3 pulls the image on the machine and runs bash /workspace/run.sh inside it, with your workspace, datasets and $C3_ARTIFACTS_DIR mounted.
Images on the GitHub Container Registry work the same way:
docker:
image: ghcr.io/my-lab/trainer:1.4
requires_accelerator: cuda
Requirements:
- A public image on Docker Hub or
ghcr.io.ubuntu:24.04,user/image:tag,docker.io/...andghcr.io/<owner>/<image>:<tag>are accepted, with a tag or a digest. Other registries are rejected before anything is uploaded. - The package must be public. C3 pulls anonymously and does not support private images on either registry. On GHCR, set the package visibility to public in GitHub package settings; GitHub reports a private or missing package as denied.
- C3 reuses an image already present on the machine. Pin a digest if you need a specific build rather than a mutable tag such as
latest. - The image must contain
bash. Alpine and distroless images often do not. - Set
requires_accelerator: cudafor GPU images andnonefor CPU images. C3 stops before running the script if the machine does not match. - The image keeps its own
PATH,HOMEandENV. C3 adds only the job variables below.
For a CPU job, request a CPU profile and set requires_accelerator: none. See CPU jobs.
Bash
project: bash-example
script: run.sh
hardware: l40
time: "00:30:00"
output:
- ./results
# run.sh
#!/bin/bash
set -euo pipefail
mkdir -p results
./bin/my-simulation --output results/output.dat
Whatever the script installs is installed again on every job. Move that setup into python: or docker: when startup time matters.
What is on the machine
Jobs run on Ubuntu virtual machines managed by C3's agent. C3 stages your workspace and prepares the configured Python or Docker environment for each job. Machines may be reused between jobs; do not rely on setup from a previous job.
| GPU machines | CPU machines | |
|---|---|---|
| Ubuntu | 22.04 or 24.04, depending on the provider | 24.04 |
| NVIDIA driver and CUDA toolkit | Yes. CUDA 12.2 or 13.0, depending on the provider | No |
| Python | The Ubuntu system python3 (3.10 or 3.12). pip and venv are not guaranteed; use uv | Same |
uv | Yes, on the PATH | Yes |
| Docker | Yes, with the NVIDIA container runtime | Yes |
| Also present | bash, curl, tar, gzip, zstd | Same |
Nothing else is guaranteed. Do not rely on git, a compiler or conda being present. In Python mode, put dependencies in pyproject.toml. In Docker mode, put them in the image. In Bash mode, install them in the script and accept the startup cost.
Variables available to your script
| Variable | Value |
|---|---|
C3_JOB_WORKDIR | Absolute path of your uploaded workspace, the working directory |
C3_ARTIFACTS_DIR | Directory whose contents are collected as results. Always exists |
C3_HARDWARE_PROFILE | Exact profile of the machine, such as l40s or cpu-d3-96vcpu-384gb |
C3_HARDWARE_KIND | gpu or cpu |
C3_ACCELERATOR_KIND | cuda or none |
PYTHONUNBUFFERED | 1, so Python output streams to the logs promptly |
VIRTUAL_ENV | Set in Python mode |
TMPDIR | Per-job temporary directory, Python and Bash modes |
The environment is sanitised: no C3 credentials or storage keys are visible to your script. .env files in your workspace are uploaded but not loaded; load them yourself if you need them.