The inf.yml file defines app settings and resource requirements.
Project Structure
1my-app/2├── inf.yml # Configuration3├── inference.py # App logic4├── requirements.txt # Python packages (pip)5└── packages.txt # System packages (apt) — optionalBasic structure
1namespace: myteam2name: my-app3title: My App4description: What my app does5category: image6kernel: python-3.1178resources:9 gpu:10 count: 111 vram: 24 # 24GB (auto-converted to bytes)12 type: any13 ram: 32 # 32GBFields
| Field | Required | Description |
|---|---|---|
namespace | Yes | Your workspace username (app owner). Another namespace needs admin access; see Deploying |
name | Yes | App identifier (slug format). This is the slug that addresses the app: namespace/name in the API, the CLI and the URL. |
title | No | The name a person reads on the app's page — Veo 3.1 for veo-3-1. Free of the slug's constraints: spaces, capitals and punctuation are fine. Without one, the app is presented under its name. |
description | Yes | What it does (max 200 characters; belt app deploy warns when over the limit, including with --dry-run) |
category | Yes | Grid grouping — see Categories |
kernel | Yes | Runtime: python-3.10, python-3.11, python-3.12, node-22 |
resources | Yes | Hardware requirements |
images | No | Store listing images (card, thumbnail, banner URLs; optional dark with the same slots) |
App tags
Tags describe what the app does and traits such as open-weights or realtime. They appear on the app record, in store listings, and in search indexing alongside name and description.
Declare them under version metadata in inf.yml:
1metadata:2 tags:3 - text-to-image4 - open-weights| Rule | Detail |
|---|---|
| Format | Lowercase slugs: letters, digits, and single hyphens (text-to-image, lora). Up to 10 tags per app, each at most 50 characters. |
| Browseable tags | Tags on at least three public apps appear in GET /store/tags with a display title and count — see Store API — List browseable tags. Other valid slugs (for example virtual-try-on, ocr) work on apps and in filters; they are omitted from that list until usage crosses the threshold. |
| On deploy | When the deploy request does not send tags, the API normalizes metadata.tags from the version and stores them on the app. Invalid entries in inf.yml are dropped (they do not fail deploy). If metadata.tags is empty too, the stored tags are kept. |
| Explicit API tags | POST /apps and deploy payloads may include a top-level tags array — it replaces the app's tags and takes precedence over metadata.tags. |
belt app deploy --meta updates listing fields such as category and images; app tags are set on full deploy (or via the REST API), not through --meta alone.
In the web app, open your app → Info to edit category and tags. The tags field is a list: press Enter or type a comma to add a slug (up to 10). A later deploy that sends tags or declares metadata.tags replaces tags set only in the UI.
Store images
Optional URLs shown in the app Grid and store. The CLI reads these from inf.yml when you deploy:
1images:2 card: https://example.com/card.png3 thumbnail: https://example.com/thumb.png4 banner: https://example.com/banner.png5 dark: # optional: covers for the dark theme6 card: https://example.com/card-dark.png7 thumbnail: https://example.com/thumb-dark.png8 banner: https://example.com/banner-dark.pngWithout dark, the three slots serve both themes. Omit images to use auto-generated covers after deploy.
To update the listing title, images, description, or category without shipping a new app version:
1belt app deploy --metaOnly non-empty fields in your local inf.yml are sent (for example, omit images.banner to leave the existing banner unchanged). The app must already be deployed at least once before --meta works.
App UI
Optional version metadata that names an artifact page to show beside finished app tasks, in the web app, in chat, and in MCP clients that support MCP Apps (see MCP server).
1metadata:2 ui:3 artifact: myteam/run-dashboard # artifact ref namespace/name4 # artifact: myteam/run-dashboard@3 # pin one published version5 # artifact: art_abc123 # or artifact id| Value | Behavior |
|---|---|
Ref without @ | Follows the artifact's current published version when a task finishes |
Ref with @version | Pins one published version |
| Artifact id | Resolves that artifact; unpinned versions follow the live page |
The artifact must exist and be readable by you at deploy time. The page must also be at least as visible as the app (a public app needs a public page), so everyone who can see the app can see its page. Otherwise deploy is refused with 400 validation_error naming the page. The API exposes the same object on AppVersionDTO.ui and in metadata.ui; see Apps API — custom UI page.
Publish the page first (belt artifact publish), then deploy the app with this block. See Artifacts — capabilities for what the HTML page may call (db, user, assets).
Resources
The CLI automatically converts human-friendly values to bytes:
- < 1000 → treated as GB (e.g.,
80= 80GB) - 1000 to 1 billion → treated as MB (e.g.,
80000= 80GB)
1resources:2 gpu:3 count: 1 # Number of GPUs4 vram: 24 # 24GB5 type: any # GPU type6 ram: 32 # 32GBGPU Types
| Value | Description |
|---|---|
any | Any GPU will work |
nvidia | Requires NVIDIA GPU |
amd | Requires AMD GPU |
apple | Requires Apple Silicon |
none | No GPU needed (CPU only) |
Note: Currently only NVIDIA CUDA GPUs are supported.
An app has one resources block. Setup parameters choose a model or configuration inside it, so the block has to fit the largest one. Models that need different amounts of memory are separate apps.
For CPU-only apps:
1resources:2 gpu:3 count: 04 type: none5 ram: 4Categories
| Category | Use For |
|---|---|
image | Image generation, editing |
video | Video generation, processing |
audio | Audio generation, TTS |
text | Text generation |
chat | Conversational AI |
3d | 3D model generation |
flow | Apps deployed from a Flow |
decision | Decision models: typed questions in, a probability for every answer out (no generative output). See Decision apps and the authoring contract |
other | Everything else |
Dependencies
1torch>=2.02transformers3accelerateSystem Packages (packages.txt)
For apt-installable system dependencies (both Python and Node.js):
1ffmpeg2libgl1-mesa-glxBase Images
Apps run in containers with these base images:
| Type | Image |
|---|---|
| GPU | docker.inference.sh/gpu:latest-cuda |
| CPU | docker.inference.sh/cpu:latest |
Python environment
Each Python app version gets its own venv. It starts with build tools (setuptools, setuptools-scm, wheel, wheel-stub, build, packaging, ninja, scikit-build-core, cython, flit-core, numpy) plus pydantic and inferencesh.
torch and its CUDA wheels, accelerate, huggingface_hub, transformers and diffusers are not preinstalled. List every package your code imports in requirements.txt. transformers and diffusers need accelerate at runtime for device_map, low_cpu_mem_usage and enable_model_cpu_offload().
App versions that already have an environment keep it. New versions, and versions set up on a new worker, get this base.
Environment Variables
1env:2 MODEL_NAME: gpt-43 MAX_TOKENS: "2000"4 HF_HUB_ENABLE_HF_TRANSFER: "1"Access in code:
1import os2model = os.environ["MODEL_NAME"]Secrets and Credentials
Declare required secrets and OAuth credentials:
1credentials:2 huggingface:3 secrets: [HF_TOKEN]4 description: HuggingFace token for gated models56 google:7 capabilities: [google.sheets]8 description: Access to Google Sheets9 optional: trueEntries are keyed by the credential slug. The older list form (- provider: huggingface, - key: google.sheets) is still read. Use credentials: only; integrations: in inf.yml is rejected (renamed in CLI v1.18.59).
credentials: is the app-wide list. In a multi-function app, each function can declare the subset it uses; see Per-function credentials.
See Secrets and Credentials for details.