# Configuration (oakapp.toml)

Within each app's directory, there must be a oakapp.toml file that contains static app's metadata and build steps. Metadata
includes the app's identifier and version. Build steps are commands that are executed in the container to build or run the app.
Example oakapp.toml file:

```toml
# (Required) App Identifier
identifier = "com.luxonis.python_demo"
# (Required) App Entrypoint
entrypoint = ["bash", "-c", "python3 /app/main.py"]

# (Optional) Prepare container commands
# Here is the place where you can install all the dependencies that are needed at run-time
prepare_container = [
    { type = "COPY", source = "requirements.txt", target = "requirements.txt" },
    { type = "RUN", command = "apt-get update" },
    { type = "RUN", command = "apt-get install -y python3-pip" },
    { type = "RUN", command = "pip3 install -r /app/requirements.txt --break-system-packages" },
]

# (Optional) Prepare build dependencies
# Here is the place where you can install all the dependencies that are needed at build-time
prepare_build_container = [
    # Example: npm, gcc, ...
]

# (Optional) Additional commands after all the app files are copied to the container
build_steps = []
```

## Configuration Fields

### App Metadata

 * identifier - name of the app in Java-like format (with dots as separators; e.g., com.my_company.my_app)
   * com.luxonis namespace is reserved for official apps
   * com.example namespace is not recommended for production apps
 * app_version - version of the app in format major.minor.patch (e.g., 1.0.0)

### App Build and Runtime Configuration

 * entrypoint - array of strings (a command in argv format)
 * cwd - (optional, default is / ) current working directory for the container
 * shell - (optional, default is ["/bin/bash", "-c"] ) shell to use for executing build_steps, entrypoint, and RUN commands in
   prepare_container and prepare_build_container sections
 * app_dir_name (optional/advanced; default is app ) - directory inside the container where the app files are copied; use only if
   you already use this directory name for something else

> **Shell Form vs Executable Form**
> Similarly to Docker, all the commands can be specified in executable form (array of strings) or in shell form (single string).
For
> `entrypoint`
> we strongly recommend using executable form.

### App Layers

Similar to Docker, an app is built in multiple layers:

 1. Base Image layer (specified in base_image section)
 2. Runtime layer (built in prepare_container section)
 3. Build layer (built in prepare_build_container section; this layer is disconnected from runtime layer after build)
 4. App layer (all the files from the app's directory and the build_steps are executed here)

> **Note**
> In Docker terminology, each of these layers corresponds to a single
> `RUN`
> instruction in a Dockerfile. This allows for efficient caching while avoiding common pitfalls.

Next to App layer, there are two additional parallel layers:

 * Static Frontend layer (if specified in static_frontend section)
 * DepthAI Models Cache layer (if specified in depthai_models section)

If any of these layers change, all the subsequent layers are rebuilt. Parallel layers are rebuilt independently of each other as
they do not have mutual dependencies.

#### Base Image

Base image for the container needs to be debian based. The current default is debian/bookworm-slim, see example below:

```toml
[base_image]
api_url = "https://registry-1.docker.io" # Service https address
service = "registry.docker.io" # Name of Image Registry Service
oauth_url = "https://auth.docker.io/token" # address to oauth 2.0 token for this service
auth_type = "repository" # scope type
auth_name = "library/debian" # name of resource

image_name = "library/debian"
image_tag = "bookworm-slim"
```

> **Recommendation**
> For DepthAI OAK Apps, we recommend our
> [Base Image](https://docs.luxonis.com/software-v3/oak-apps/base-image.md)
> that includes most of the dependencies you may need.

If you need a different Docker image as a base layer, you just need to define this image in oakapp.toml using:

```toml
[base_image]
image_name = "library/debian"
image_tag = "bookworm-slim"
```

By default, it downloads images from Docker Hub, but you can specify a different repository. There are several limitations for the
Docker image you can use:

 * It must be a Debian 12-based image
 * It must support ARM architecture
 * It must be compatible with Docker's Manifest V2

Alternatively, you can use a locally running registry and configure the [base_image] setting in oakapp.toml as follows:

```toml
[base_image]
 api_url = "http://localhost:5000" # Service http address visible from the device
 image_name = "my-base"
 image_tag = "local"
```

Plus serve this on local network:

```bash
docker run -d -p 5000:5000 --name zot ghcr.io/project-zot/zot-linux-amd64:latest

# Only for local testing with insecure registry
regctl registry set --tls=disabled localhost:5000
docker buildx create --use --driver docker-container --driver-opt network=host

# Create a simple base image
echo "FROM debian:bookworm-slim" > ./Dockerfile
 
# set IP address of your local registry if not running on localhost
docker buildx build -f ./Dockerfile --platform=linux/arm64 -t 127.0.0.1:5000/my-base:local --push .
```

Keep in mind that the app is built on the device, so the registry must be accessible from the device. The base_image.api_url has
to point to the device's network-accessible address.

#### Runtime And Build Layer

Both prepare_container and prepare_build_container are arrays of commands that are executed in the container to prepare the
respective layers. The only difference is that the build layer is not present at runtime.

The available command types are:

 * RUN - run a command in the container

```toml
prepare_container = [
    { type = "RUN", command = "apt-get update" },
    { type = "RUN", command = "apt-get install -y python3-pip" },
]
```

 * COPY - copy a file from the app's directory to the container sooner than in the App layer. This is useful for copying
   dependency files like requirements.txt. It is not necessary to copy the actual app files here, as they are copied later in the
   App layer.
   * source - path to the source file relative to the app's directory on the host
   * target - path to app directory inside the container (relative to app_dir_name if specified)

```toml
prepare_container = [
    { type = "COPY", source = "requirements.txt", target = "requirements.txt" },
]
```

#### App Layer

First, all the files from the app's directory are copied to the container (into app_dir_name if specified). Then, the commands in
build_steps are executed in order.

 * build_steps - steps to build an application or other preparation commands to be executed (array of strings)

```toml
build_steps = [
    "g++ -o /app/my_app /app/main.cpp",
    "chmod +x /app/my_app",
]
```

You can ignore files from being copied to the container by adding a .oakignore file to your app's directory. The syntax is similar
to .gitignore. Example:

```plaintext
# Ignore all .log files
*.log
# Ingore node_modules/ directory
node_modules/
```

### Mounts

Mounts allow you to link directories or devices from the device running the app into the app's container. You cannot mount
directories from the host this way. Mounts that are required must be present at both build time and run time.

 * required_mounts, required_devices - mounts that are required - if not present on startup of container, the app is stopped with
   error

Syntax is source[:target[:options]]; defaults:

 * source=target
 * options="rbind,rw"
 * All mount paths must be absolute. Relative paths are rejected for required_mounts, required_devices, optional_mounts,
   optional_devices, and additional_mounts (source/target).

Example:

```toml
required_mounts = [
    "/data/my-storage:/app/storage:rw,rbind",
]
```

 * optional_mounts, optional_devices - if not present of startup of container, these mounts are ignored
 * additional_mounts ( source , target , type , options , required ) array of objects, see below for example:

```toml
additional_mounts = [
    { source = "/run/user/1000/pulse", target = "/run/user/1000/pulse", type = "none", options = [
        "rbind",
        "rw",
    ], required = true },
    { source = "/home/root/.config/pulse/cookie", target = "/root/.config/pulse/cookie", type = "none", options = [
        "bind",
        "ro",
    ], required = true },
]
```

 * additional_build_mounts - same as additional_mounts, but only for build time; these mounts are not present at runtime

 * allowed_devices - list of devices that the app is allowed to access inside the container

```toml
allowed_devices = [{ allow = true, access = "rwm" }]
```

### Static frontend

Static frontend layer allows you to build and serve a static web frontend alongside your app. See [example on
GitHub](https://github.com/luxonis/oak-examples/blob/main/custom-frontend/open-vocabulary-object-detection/oakapp.toml).

 * static_frontend
   * dist_path - path to the built frontend files (relative to the app's directory on the host)
     * build (optional) - build configuration for the frontend
       * source_path - path to the frontend source files
       * steps - array of commands to build the frontend

```toml
[static_frontend]
dist_path = "./frontend/dist" # path to the built frontend files

[static_frontend.build]
source_path = "./frontend" # path to the frontend source files
steps = ["cd /app/frontend/src && npm install && npm run build"]
```

 * assign_frontend_port - if set to true, an available port will be assigned to OAKAPP_STATIC_FRONTEND_PORT environment variable
   inside the container; this can be used even if static_frontend is not specified

```toml
assign_frontend_port = true
```

 * static_frontend_dir_name (optional/advanced; default is static_frontend) - directory inside the container where the static
   frontend files are mounted (will be stored in OAKAPP_STATIC_FRONTEND_PATH environment variable); use only if you already use
   this directory name for something else

### DepthAI Models Cache

This section allows you to specify a folder with DepthAI models in *.yaml format that will be cached inside the container during
build time. This way, you can create apps that work offline without the need to download models at runtime.

 * depthai_models
   * yaml_path - path to the DepthAI models folder in *.yaml format
   * use_only_cache - if set to true, only the cached models will be used, and no new models will be downloaded at runtime (sets
     DEPTHAI_ZOO_INTERNET_CHECK environment variable)

```toml
depthai_models = { yaml_path = "./backend/src/depthai_models" }
```

 * depthai_models_dir_name (optional/advanced; default is depthai_models) - directory inside the container where the DepthAI
   models are mounted; use only if you already use this directory name for something else

### Environment Variables and Build Arguments

Environment variables are set for runtime only.

```toml
[env]
MY_ENV_VAR = "some_value"
ANOTHER_ENV_VAR = "another_value"
```

Build arguments are set only during build time and are not available at runtime.

```toml
[arg]
MY_BUILD_ARG = "some_build_value"
ANOTHER_BUILD_ARG = "another_build_value"
```

Both environment variables and build arguments have lower precedence than the variables set by the user in command line (oakctl
app run --env MY_ENV_VAR=value).
