<!-- Source: https://docs.biosimulant.com/references/model-manifest -->

# model.yaml Schema

`model.yaml` declares a packaged BioModule: its entrypoint, communication-step assumptions, typed port metadata, dependencies, and optional ONNX details.

## Schema

```yaml
schema_version: "2.0"
title: string
description: string
standard: sbml | neuroml | cellml | nmodl | onnx | other
package: string
version: string

biosim:
  entrypoint: string
  init_kwargs: object
  setup: object
  communication_step: number

io:
  inputs:
    - name: string
      signal_type: scalar | array | record | event
      dtype: string
      shape: list
      schema: object
      accepted_profiles: list
      description: string
  outputs:
    - name: string
      signal_type: scalar | array | record | event
      dtype: string
      shape: list
      schema: object
      emitted_unit: string
      description: string

runtime:
  python_version: string
  dependencies:
    packages: [string]
    requirements_file: string
    lockfile: string
  remote:
    requirements:
      accelerator: gpu
      gpu_count: number

metadata:
  authors: [string]
  tags: [string]
  species: [string]

onnx:
  task: string
  model_file: string
  class_labels: [string]
  inputs: [...]
  outputs: [...]
```

## Package identity

`package` is the stable `namespace/name` identifier and `version` is the exact
SemVer package version, such as `1.0.0`. Together they form the package ref
`namespace/name@x.y.z`.

When you build or publish a package, `version` must be exact SemVer. `latest`
and other non-SemVer values are rejected. This rule is for manifests. CLI
commands such as `labs pull` accept a ref without a version; see
[Package & Publish](/how-to/package-and-publish#pull-and-run-versions).

A lab does not reference a model by package. Its `models[]` entries use a
relative `path`. To add a model source tree to a lab:

```bash
biosimulant labs add-model ./models/hh-population --lab ./my-lab --alias hh
```

`add-model` writes the relative path and alias into the lab's `lab.yaml`.

## `biosim` block

```yaml
biosim:
  entrypoint: "src.hh_population:HHPopulation"
  init_kwargs:
    n: 100
  setup:
    seed: 1234
  communication_step: 0.001
```

| Field | Meaning |
|-------|---------|
| `entrypoint` | Required. Python symbol in `module.path:ClassName` form |
| `init_kwargs` | Constructor kwargs merged with lab-level parameter overrides |
| `setup` | Default `setup()` config for the module |
| `communication_step` | Required. Positive default coupling boundary for this packaged model |

Model-entry `parameters` in a lab are constructor overrides. They are merged into
`biosim.init_kwargs` before the entrypoint factory is called. Runtime inputs are
separate: declare them under `io.inputs` and pass values through run-time input
payloads.

## I/O contract

String-only port lists are still accepted in some tooling, but current-kernel manifests should prefer structured typed ports.

```yaml
io:
  inputs:
    - name: current
      signal_type: scalar
      dtype: float64
      description: External current injection
    - name: spikes
      signal_type: event
      schema:
        ids: list[int]
  outputs:
    - name: membrane_potential
      signal_type: scalar
      dtype: float64
      emitted_unit: mV
    - name: state
      signal_type: record
      schema:
        v: float64
        u: float64
```

Use the manifest to describe what the module publishes and accepts. The runtime signal classes are still emitted from Python code.

Run-time input payload values are coerced against this input contract before the
module receives them. Raw scalar, array, record, and event payloads become
typed `BioSignal` instances when exactly one accepted input profile matches. If a
port accepts multiple profiles or units, provide an explicit typed input envelope
with `value`, `signal_type`, `dtype`, `shape`, `schema`, and/or `emitted_unit`.

## Dependencies

```yaml
runtime:
  python_version: "3.12"
  dependencies:
    packages:
      - numpy==1.26.4
      - scipy==1.12.0
    requirements_file: requirements.txt
```

Open-source `biosimulant labs run` only installs exact-pinned package specs into the
current Python environment. Runs on the Biosimulant platform use isolated
per-lock-hash environments and apply allow/deny dependency policy. Keep manifests
portable by pinning dependencies exactly when package installation is expected.

## Remote execution requirements

Models that require accelerator-backed remote execution can declare the requirement in `runtime.remote.requirements`:

```yaml
runtime:
  remote:
    requirements:
      accelerator: gpu
      gpu_count: 1
```

`accelerator: gpu` marks the model as requiring a GPU-backed remote size. In the remote execution catalog, GPU-backed means the size has a non-empty `gpu_type`. CPU-compatible models omit this block.

Lab authors should not duplicate model resource requirements in `lab.yaml`; Biosimulant aggregates model requirements into the resolved lab graph at run time.

## ONNX metadata

When `standard: onnx`, include an `onnx` block describing the model artifact and tensor signatures:

```yaml
onnx:
  task: classification
  model_file: data/assets/model.onnx
  class_labels: [quiescent, subthreshold, spiking]
  inputs:
    - name: input
      dtype: float32
      shape: [-1, 10]
  outputs:
    - name: probabilities
      dtype: float32
      shape: [-1, 3]
```

## Directory layout

```text
my-model/
  model.yaml
  src/
    my_module.py
  data/
    assets/
      model.onnx
  requirements.txt
```

## Validate and build

Add the model to `biosimulant-packages.yaml` with `type: model`, then validate
and build:

```bash
biosimulant labs release validate biosimulant-packages.yaml
biosimulant labs release build biosimulant-packages.yaml --out dist/biosimulant-packages
```

## See Also

- [lab.yaml Schema](/references/lab-manifest)
- [How to Write a lab.yaml](/how-to/write-lab-manifest)
- [How to Add an ONNX Model](/how-to/add-onnx-model)
