> ## Documentation Index
> Fetch the complete documentation index at: https://docs.outerproduct.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Images

> Define the container, Python dependencies, and local files used by a Call.

Every OuterProduct Call runs inside a container. An `op.Image` describes that container’s operating system, Python runtime and dependencies, and local files. Images are:

* **Lazy**: OuterProduct prepares them when they are first used by a Call.
* **Immutable**: methods such as `with_uv_pip_install()` return a new Image instead of modifying the existing one.

> [!WARNING]
>
> `image` is a required keyword argument in `client.run()`. Omitting it raises a Python `TypeError`.

## Start from a container image

Create an Image from any compatible container registry reference. The base image supplies the operating system and Python interpreter.

```python theme={null}
import outerproduct as op

image: op.Image = op.Image.from_registry("python:3.12-slim")
```

You can also use an image from another registry:

```python theme={null}
image: op.Image = op.Image.from_registry("ghcr.io/my-organization/my-image:v1")
```

> [!WARNING]
>
> Registry references should not include an `https://` prefix.

## Install Python packages

Use `with_uv_pip_install()` to add packages to the environment:

```python theme={null}
image: op.Image = op.Image.from_registry("python:3.12-slim").with_uv_pip_install(
    "numpy",
    "pandas",
)
```

For a GPU workload, you can begin with a CUDA-enabled PyTorch image and add the libraries your application needs.

## Add local files and directories

An Image can include files from your local project. Use `add_local_file()` for an individual file and `add_local_dir()` for a directory:

```python theme={null}
image: op.Image = (
    op.Image.from_registry("python:3.12-slim")
    .with_uv_pip_install("pandas")
    .add_local_dir("./src", "/app/src")
    .add_local_file("./config.json", "/app/config.json")
)
```

The first argument is the local path. The second is the absolute path where the file or directory will appear inside the container.

OuterProduct uploads local files when the Image is used and mounts them over the container image. It uploads an Image's local files together, skipping the upload when none have changed; changing them does not rebuild the Image's dependency layers. When multiple additions write to the same path, the later addition takes precedence.

Local files added to an Image are part of the execution environment. For data that must persist across Calls or Runs, use a mounted Volume instead.

## Run with an Image

Pass the Image to `client.run()`:

```python theme={null}
run: op.Run[object] | op.Call[object] = client.run(
    fn=train_model,
    args=(training_data,),
    image=training_image,
    gpu_type="L4",
)

model: object = run.wait()
```

Each Call can use a different Image, allowing one application to combine functions with different dependencies and runtime environments.

> [!NOTE]
>
> If a nested Call uses an Image with local files, assign that Image to a variable outside any function, in the same file as the function you pass to `client.run()`. OuterProduct uploads the local files of those Images from your machine when the Run starts; Images created inside a function can't find their local files once they're running remotely.
>
> ```python theme={null}
> image = op.Image.from_registry("python:3.12-slim").add_local_dir(
>     "./data", "/data"
> )
>
> def parent(client) -> None:
>     client.run(fn=fn, image=image)  # not op.Image...add_local_dir(...) here
> ```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.