Containers, like [Docker](https://www.docker.com/), are a way to package software and its dependencies into a standardized unit for software development. Containers are lightweight, standalone, and executable software packages that include everything needed to run an application: code, runtime, system tools, system libraries, and settings.

:::caution[Untrusted Code Execution]

If you are planning to execute code generated by an LLM, you **should** treat it as **untrusted** and use containers to isolate the execution environment.

:::

## Requirements

GenAIScript uses Docker to orchestrate the containers.

-   [Install docker](https://docs.docker.com/engine/install/)

## Start a container

Start by creating and starting a new container. GenAIScript will pull the container image on demand,
removing the container when it is no longer needed.

```js
const container = await host.container()
```

### Custom image

By default, the container uses the [python:alpine](https://hub.docker.com/_/python/) image, which provides a minimal python environment. You can change the image using the `image` option.

```js 'image: "python:3"'
const container = await host.container({ image: "node:20" })
```

### Building images

Use [docker build](https://docs.docker.com/build/) to create reusable images.

You can build a custom image from a GitHub repository with a single command in your scripts.

```js
const repo = "codelion/optillm" // GitHub repository = image name
const branch = "main"
const dir = "."
await host.exec(
    `docker build -t ${repo} https://github.com/${repo}.git#${branch}:${dir}`
)
```

Then use the repo as your image name

```js
const container = await host.container({ image: repo, ... })
```

### Disable auto-purge

By default, the container is removed when it is no longer needed. You can disable this behavior using the `persistent` option.

```js "persistent"
const container = await host.container({ persistent: true })
```

### Enable network

By default, the container network is disabled, and web requests won't work. This is the safest solution;
if you need to install additional packages, it is recommended to create an image with all the necessary software included.

You can enable network access using `networkEnabled`.

```js
const container = await host.container({ networkEnabled: true })
```

### Port bindings

You can bind container ports to host ports and access web servers running in the container.

For example, this configuration will map the host `8088` port to `80` on the container
and you will be able to access a local web server using `http://localhost:8088/`.

```js "ports"
const container = await host.container({
    networkEnabled: true,
    ports: {
        containerPort: "80/tcp",
        hostPort: 8088,
    }, // array also supported
})
```

Then

## Run a command

You can run a command in the container using the `exec` method. It returns the exit code, standard output and error streams.

```js
const { stdout } = await container.exec("python", ["--version"])
```

## Read and write files

The container has a volume mounted in the host file system, allowing reading and writing files to the container.
```js
await container.writeText("hello.txt", "Hello, world!")
const content = await container.readText("hello.txt")
```

## Copy files to container

You can also copy files from the host to the container.

```js
// src/* -> ./src/*
await container.copyTo("src/**", ".")
```

## Disconnect network

If you created the container with network enabled, you can disconnect the network to isolate the container.

```js
await container.disconnect()
```

## Using containers in tools

The [containerized tools](/genaiscript/guides/containerized-tools) guide shows how to use containers in tools to handle untrusted text securely.