Physical AI Studio is a framework for training and deploying Vision-Language-Action (VLA) models for robotic imitation learning. This guide covers running Physical AI Studio as a Docker container with support for CPU, Intel XPU, and NVIDIA CUDA hardware.
- Docker Engine 24+ with Docker Compose v2
- A supported hardware backend:
- CPU — any x86_64 system (default)
- Intel XPU — Intel discrete/integrated GPU with Level Zero drivers on the host
- NVIDIA CUDA — NVIDIA GPU with the NVIDIA Container Toolkit installed
- Robot hardware (optional): USB serial ports (
/dev/ttyACM*), USB cameras (/dev/video*), or Intel RealSense cameras
All commands should be run from the application/docker/ directory.
# 1. Create your local environment file
cp .env.example .env
# 2. (Optional) Set your hardware profile in .env
# Edit COMPOSE_PROFILES to: cpu (default), xpu, or cuda
# 3. (Optional) Auto-detect host device GIDs for non-Debian systems
./setup-devices.sh
# 4. Start Physical AI Studio
docker compose upPhysical AI Studio will be available at http://localhost:7860.
The hardware backend is selected via the COMPOSE_PROFILES variable in .env.
To override it on the command line without editing .env:
# Intel XPU
docker compose --profile xpu up
# NVIDIA CUDA
docker compose --profile cuda upTo run in the background, add the -d flag:
docker compose up -dAll configuration is done through the .env file. Copy .env.example to get started.
| Variable | Default | Description |
|---|---|---|
COMPOSE_PROFILES |
cpu |
Hardware profile: cpu, xpu, or cuda |
PORT |
7860 |
Host port to expose the web UI and API |
REGISTRY |
ghcr.io/open-edge-platform/ |
Container image registry |
IMAGE_TAG |
latest |
Image version tag |
APP_UID |
1000 |
UID for the in-container user (match your host user) |
APP_GID |
1000 |
GID for the in-container user (match your host user) |
VIDEO_GID |
video (group name) |
Host GID for the video group (cameras) |
DIALOUT_GID |
dialout (group name) |
Host GID for the dialout group (serial ports) |
PLUGDEV_GID |
plugdev (group name) |
Host GID for the plugdev group (USB devices) |
RENDER_GID |
render (group name) |
Host GID for the render group (Intel GPU, XPU only) |
HTTP_PROXY |
(empty) | HTTP proxy for builds and runtime |
HTTPS_PROXY |
(empty) | HTTPS proxy for builds and runtime |
NO_PROXY |
(empty) | Proxy exclusion list |
The Docker image is built in multiple variants, one per hardware backend.
The correct variant is selected automatically via Docker Compose profiles
(COMPOSE_PROFILES in .env or --profile on the command line).
| Profile | Service name | Additional system packages |
|---|---|---|
cpu |
physical-ai-studio-cpu |
None |
xpu |
physical-ai-studio-xpu |
Intel GPU runtime (Level Zero, OpenCL, VA) |
cuda |
physical-ai-studio-cuda |
CUDA 12.8 runtime (cudart, cuBLAS, cuDNN) |
The container needs access to host devices (serial ports, cameras, USB) to communicate with robots and capture data. There are two modes:
The default docker-compose.yaml runs the container in privileged mode. This
grants full access to all host devices with zero configuration:
privileged: trueThis is the easiest option and is recommended for development and prototyping.
For production or shared environments, you can restrict the container to only
the specific devices it needs. Edit the relevant service in docker-compose.yaml:
- Comment out
privileged: truein thex-commonanchor - Uncomment the
devicessection and adjust the device paths to match your hardware:
privileged: false
devices:
# Servo USB connections
- /dev/ttyACM0:/dev/ttyACM0
- /dev/ttyACM1:/dev/ttyACM1
# USB cameras
- /dev/video0:/dev/video0
- /dev/video2:/dev/video2
# Intel RealSense (uncomment if needed)
# - /dev/bus/usb:/dev/bus/usbFor Intel XPU in non-privileged mode, you also need to uncomment the
group_add and devices overrides in the physical-ai-studio-xpu service
to grant access to /dev/dri/renderD* render nodes:
group_add:
- "${DIALOUT_GID:-dialout}"
- "${PLUGDEV_GID:-plugdev}"
- "${VIDEO_GID:-video}"
- "${RENDER_GID:-render}" # Intel GPU render nodes
devices:
- /dev/dri:/dev/dri # Intel GPU device nodesDocker resolves group names like video and dialout against the
container's /etc/group, not the host's. On Debian/Ubuntu, the GIDs
typically match. On other distros (Arch Linux, Fedora, etc.) they may differ,
which means the container process won't have permission to access devices.
Run the setup script to auto-detect your host's GIDs and write them to .env:
# Detect GIDs and write to .env
./setup-devices.sh
# Check GIDs without modifying .env
./setup-devices.sh --checkThe script detects VIDEO_GID, DIALOUT_GID, and PLUGDEV_GID, checks
whether your user is a member of each group, and warns you if you need to
add yourself. For Intel XPU, also ensure your user is in the render group:
sudo usermod -aG video $USER
sudo usermod -aG dialout $USER
sudo usermod -aG render $USER # Intel XPU only
# Log out and back in for group changes to take effectThe compose file defines two named volumes and one bind mount:
| Volume | Container path | Purpose |
|---|---|---|
physical-ai-studio-data |
/app/data |
Application database and runtime data |
physical-ai-studio-storage |
/app/storage |
Trained models, datasets, and other artifacts |
| (bind mount) | ~/.cache/huggingface/lerobot/calibration (read-only) |
Shared robot calibration data from the host |
To inspect volume contents:
# List files in a volume
docker run --rm -v docker_physical-ai-studio-data:/data alpine ls -la /data
# Back up a volume
docker run --rm -v docker_physical-ai-studio-storage:/storage -v $(pwd):/backup alpine \
tar czf /backup/physical-ai-studio-storage-backup.tar.gz -C /storage .Note
Docker Compose prefixes volume names with the project name (the directory name
by default). When running from application/docker/, the actual volume names
are docker_physical-ai-studio-data and docker_physical-ai-studio-storage.
You can verify the exact volume names with docker volume ls | grep physical-ai-studio.
To reset all data:
docker compose down -vWarning:
docker compose down -vremoves the named volumes and all data they contain (database, models, datasets). This cannot be undone.
To build the Docker image locally instead of pulling a pre-built image:
# Build for CPU (default profile)
docker compose build
# Build for Intel XPU
docker compose --profile xpu build
# Build for NVIDIA CUDA
docker compose --profile cuda buildThe Dockerfile uses a multi-stage build. The build context is the repository
root. Each profiled service targets the corresponding Dockerfile stage
(e.g. physical-ai-studio-cuda). Proxy environment variables from .env
are passed as build arguments automatically.
Ensure your host user is in the required device groups:
groups # Check your current groups
sudo usermod -aG dialout,video,plugdev $USER
# Log out and back inOn non-Debian systems, also run ./setup-devices.sh to set numeric GIDs
in .env.
This error only applies to the cuda profile. The NVIDIA Container Toolkit
is not installed or not configured. Follow the
installation guide
and restart the Docker daemon. If you are not using an NVIDIA GPU, make sure
COMPOSE_PROFILES is set to cpu or xpu in your .env file.
The default configuration uses ipc: host, which shares the host's
/dev/shm (typically 50% of system RAM on Linux). This should be sufficient
for most workloads. If you cannot use ipc: host (e.g. in a multi-tenant
environment), comment it out and set an explicit shm_size instead:
# ipc: host
shm_size: 16g # adjust based on available RAMSet the proxy variables in .env:
HTTP_PROXY=http://proxy.example.com:8080
HTTPS_PROXY=http://proxy.example.com:8080
NO_PROXY=localhost,127.0.0.1These are passed to both the Docker build process and the running container.