---
question: "Where do I put an agent's avatar so the API serves it?"
kind: task
via_web: na
via_cli: na
via_python: available
via_api: na
via_config: available
ref_python: logo_url
ref_config: slides_template_sources
prereq: You need an in-engine module listed under `modules:` in `config.yaml`. [Create a module](/user-guide/build/modules/creating-a-module) first.
next:
  - /capabilities/build/assets/overview
  - /capabilities/build/agents/creating-an-agent
  - /capabilities/build/apps/create-an-app
---

# Add an asset

An asset is a file in the module folder. Put it where the engine or Nexus looks, point at it from an agent, an app or `config.yaml`, then restart. Images go in `assets/public/`, which the API serves to the browser. Template trees go anywhere in the project and are declared in `config.yaml`.

## Web UI

Not applicable. Nexus has no screen that adds a file to a module. Files uploaded in a workspace are that workspace's data, not module assets. Use the Python or Config steps on this page.

## CLI

Not applicable. There is no `abi` command that creates an asset, and `abi new module` does not scaffold an `assets/` folder. Create the folder and copy the file yourself, as in the Python steps. The command list is the [CLI reference](/user-guide/reference/cli).

## Python

### Put the file in `assets/public/`

```text
src/my_module/
├── __init__.py
├── agents/
│   └── ReviewerAgent.py
└── assets/
    └── public/
        └── reviewer.png
```

Once the engine loads the module, the API serves the file at `/modules/my_module/assets/public/reviewer.png`, with no API key.

### Point the agent at it

Set `logo_url` on the agent class, relative to the module:

```python title="agents/ReviewerAgent.py"
class ReviewerAgent(Agent):
    name: str = "Reviewer"
    description: str = "Reviews pull requests."
    logo_url: str = "assets/public/reviewer.png"
```

Nexus turns it into the full URL on the API host (`public_api_host` in `config.yaml`). An app does the same with `avatar_url` in its `manifest.json`. A full `https://` URL is used as is.

### Restart and check

Restart the engine (`abi dev down`, then `abi dev up`). The agent selector in Nexus chat shows the image. The file answers on the API port:

```bash
curl -I "http://localhost:9879/modules/my_module/assets/public/reviewer.png"
```

## REST API

Not applicable. No endpoint creates an asset: the API only serves `assets/public/` files, read-only, under `GET /modules/...`. The process list is the [API](/api).

## Config

A template tree gives Nexus Slides, Documents or Sheets more seeds to start from. ABI's own stay, under the `abi` namespace.

### Add the template files

A folder of `<id>.html` files, plus an optional `catalog.json` that names them. Copy an ABI seed to start, for example `naas_abi/apps/nexus/assets/slides/templates/minimal-light-v1.html`, and keep its structure:

```json title="src/my_module/assets/slides/templates/catalog.json"
{
  "templates": [
    {
      "id": "acme-deck-v1",
      "name": "Acme Deck",
      "description": "Acme colors and logo.",
      "preview": { "bg": "#ffffff", "panel": "#f5f5f5", "accent": "#ff5500", "ink": "#1a1a1a" }
    }
  ]
}
```

Catalog order is the order Nexus lists them in.

### Declare the tree

```yaml title="config.yaml"
modules:
  - module: naas_abi
    enabled: true
    config:
      nexus_config:
        slides_template_sources:
          - namespace: "acme"
            path: "src/my_module/assets/slides/templates"
```

The `namespace` is lowercase letters, digits and dashes, up to 32 characters. The `path` is relative to the directory the API runs in, the project root. Documents and Sheets take the same entries under `documents_template_sources` and `sheets_template_sources`.

### Restart and check

Restart the engine. The templates are listed as `acme/<id>` next to `abi/<id>`, which is what `GET /api/slides/templates?workspace_id=<id>` returns. A path that is not a folder is skipped with a warning in the API log.

### Or point a workspace logo at a public asset

The workspace seed accepts a module asset path:

```yaml title="config.yaml"
        organizations:
          - slug: "my-company"
            workspaces:
              - slug: "ops-workspace"
                logo_url: "src/my_module/assets/public/logo.png"
```

Nexus serves it from `/modules/my_module/assets/public/logo.png`. The seed only fills an empty logo: a logo chosen in the app wins, until it is cleared there.
