---
url: /en/artifact/oci.md
description: >
  Learn the path rules for the CNB OCI Artifact Registry and how to publish and
  use artifacts with ORAS, Docker Compose, llmman, and Docker Model.
---
The **OCI Artifact Registry** stores and distributes OCI-compliant application configurations,
files, and AI models.

::: warning Usage restrictions
Container images (including buildx registry caches and attestations) and Helm Charts pushed to the
OCI registry address will be rejected. Use the [Docker Registry](./docker.md) and
[Helm Registry](./helm.md), respectively.
:::

## Artifact Path Rules

Two naming rules are supported when publishing artifacts to a repository:

* **Same-name artifact**: The artifact path is the same as the repository path, such as
  `oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}`.
* **Different-name artifact**: The repository path is used as a namespace, and the artifact path is
  `repository path/artifact name`, such as
  `oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}/<ARTIFACT_NAME>`.

## Login

Log in with a CNB access token. To obtain `CNB_TOKEN`, see
[Creating an Access Token](./intro.md#creating-an-access-token).

ORAS, Docker Compose, and Docker Model can use credentials stored by Docker:

```bash
docker login -u cnb -p "${CNB_TOKEN}" oci.cnb.cool
```

When using llmman, you can also save the credentials with its login command:

```bash
llmman login oci.cnb.cool -u cnb -p "${CNB_TOKEN}"
```

## Publish Generic OCI Artifacts with ORAS

### Local CLI

[ORAS](https://oras.land/) can package a local file or directory and publish it to the OCI Artifact Registry:

```bash
oras push \
  oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}/<ARTIFACT_NAME>:latest \
  <PATH_TO_ARTIFACT>
```

Pull the artifact:

```bash
oras pull \
  oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}/<ARTIFACT_NAME>:latest
```

### Cloud Native Build

The following example packages a local file or directory from the repository and pushes it to the
CNB OCI Artifact Registry:

```yaml title=".cnb.yml"
main:
  push:
    - docker:
        image: ghcr.io/oras-project/oras
      stages:
        - name: oras push
          # <PATH_TO_ARTIFACT> is the path to a local file or directory, such as ./dist
          # <ARTIFACT_NAME> is the artifact name
          script: oras push "${CNB_OCI_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}/<ARTIFACT_NAME>:latest" <PATH_TO_ARTIFACT>
```

## Publish Application Configurations with Docker Compose

Docker Compose versions that support OCI artifacts can package Compose application configurations
and publish them to the OCI Artifact Registry.

### Local CLI

Run the following command in the directory containing `compose.yaml`:

```bash
docker compose publish \
  oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}/<APP_NAME>:latest
```

If the application uses multiple Compose files, merge and publish them together:

```bash
docker compose \
  -f compose.yaml \
  -f compose.production.yaml \
  publish --resolve-image-digests \
  oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}/<APP_NAME>:latest
```

To use the artifact, add the `oci://` prefix to its address:

```bash
docker compose \
  -f oci://oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}/<APP_NAME>:latest \
  up -d
```

::: warning Publishing restrictions
A Compose application cannot be published directly as a portable OCI artifact if it contains host
bind mounts, services with only `build` and no `image`, or local files referenced through `include`
that have not been published. Publish the service images and referenced Compose configurations first.
:::

### Cloud Native Build

The following example packages a Compose application configuration from the repository and pushes
it to the CNB OCI Artifact Registry:

```yaml title=".cnb.yml"
main:
  push:
    - services:
        - docker
      stages:
        - name: docker compose publish
          # <APP_NAME> is the Compose application name
          script: docker compose publish --yes --resolve-image-digests "${CNB_OCI_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}/<APP_NAME>:latest"
```

## Manage Model Artifacts with llmman

[llmman](https://github.com/llmmanorg/llmman) can package models such as GGUF and safetensors as
OCI artifacts that conform to the CNCF Model Format and push them to the CNB OCI Artifact Registry.

### Local CLI

Package a local model directory and push it to CNB:

```bash
llmman build \
  --tag oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}/<MODEL_NAME>:latest \
  <MODEL_DIR>

llmman push \
  oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}/<MODEL_NAME>:latest
```

Pull and run the model:

```bash
llmman pull "oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}/<MODEL_NAME>:latest"
llmman run "oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}/<MODEL_NAME>:latest" "Introduce yourself in one sentence"
```

### Cloud Native Build

The following example packages a local model directory from the repository and pushes it to the CNB
OCI Artifact Registry:

```yaml title=".cnb.yml"
main:
  push:
    - docker:
        image: docker.io/ai/llmman:server
      stages:
        - name: llmman login
          script: llmman login "${CNB_OCI_REGISTRY}" -u "${CNB_TOKEN_USER_NAME}" -p "${CNB_TOKEN}"
        - name: llmman build & push
          # <MODEL_DIR> is the model directory, such as ./model
          # <MODEL_NAME> is the model name
          script: |
            llmman build --tag "${CNB_OCI_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}/<MODEL_NAME>:latest" <MODEL_DIR>
            llmman push "${CNB_OCI_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}/<MODEL_NAME>:latest"
```

## Manage Model Artifacts with Docker Model

### Local CLI

Docker Model can package, push, and pull GGUF models with the `docker model` command:

```bash
docker model package --gguf <MODEL_FILE> \
  --push oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}/<MODEL_NAME>:latest

docker model pull \
  oci.cnb.cool/${CNB_REPO_SLUG_LOWERCASE}/<MODEL_NAME>:latest
```

### Cloud Native Build

The following example packages a GGUF model file from the repository and pushes it to the CNB OCI
Artifact Registry:

```yaml title=".cnb.yml"
main:
  push:
    - services:
        - docker
      stages:
        - name: docker model package & push
          # <MODEL_FILE> is the model file path, such as ./model.gguf
          # <MODEL_NAME> is the model name
          script: docker model package --gguf <MODEL_FILE> --push ${CNB_OCI_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}/<MODEL_NAME>:latest
```
