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

# lab.yaml Schema

`lab.yaml` describes a composed simulation: model instances, wiring, runtime, and optional child labs.

Put a `README.md` beside each root or owned child `lab.yaml`. Biosimulant shows
it in the lab About view and falls back to generated details from `lab.yaml` when
it is missing. Keep README images under `assets/` and reference them with
relative paths such as `![Run results](assets/results.png)`, not base64.

## Schema

```yaml
schema_version: "2.0"
title: string
description: string

models:
  - path: string
    alias: string
    parameters: object

wiring:
  - from: string
    to:
      - string

runtime:
  duration: number
  communication_step: number
  settle_steps: number

io:
  inputs:
    - name: string
      maps_to: string
  outputs:
    - name: string
      maps_to: string

children:
  - path: string
    alias: string
    parameters: object
  - package: string
    version: string
    alias: string
    parameters: object
    # A matching biosimulant.lock entry is required.
```

## Runtime

`runtime.communication_step` is required and must be positive.
`runtime.settle_steps` is optional, must be a non-negative integer, and defaults to `0`.

```yaml
runtime:
  duration: 10.0
  communication_step: 0.1
  settle_steps: 0
```

Set input values at run time through the run modal or run payloads. Use
parameters for persistent scalar defaults that belong in the lab manifest.

Finite downstream report, export, or visualisation modules should implement
`execute()` with `ExecutionPolicy.ONCE_AFTER_RUN`. BioWorld drains arbitrary
chains of those modules automatically after the final simulation boundary.
`settle_steps` remains available for legacy temporal modules that deliberately
need zero-time propagation. Settling does not extend simulated time and does not
invoke canonical modules.

The old external tick field is not supported.

## Models

Each `models[]` entry creates one module instance in the lab.

| Field | Meaning |
|-------|---------|
| `path` | Relative path to a local model directory |
| `alias` | Unique name used in wiring |
| `parameters` | Constructor overrides merged into `biosim.init_kwargs` |

Model entries use `path` only. Validation rejects `package` or `version` on a
model entry. To reuse a published Lab, add it under `children`.

Current-kernel labs should not declare per-entry timing or ordering fields. Promote model-specific configuration to `parameters`, and expose runtime values as typed `io.inputs`.

## Wiring

Connections use `alias.port` references:

```yaml
wiring:
  - from: retina.visual_stream
    to:
      - lgn.retina
  - from: lgn.thalamus
    to:
      - sc.vision
```

Fan-out is supported by listing multiple destinations under `to`.

## Composability

Expose lab-level ports with an `io` block:

```yaml
io:
  inputs:
    - name: stimulus
      maps_to: neuron.current
  outputs:
    - name: spike_train
      maps_to: recorder.spikes
```

Parent labs wire to `child_alias.external_port_name`.

## Nested child labs

```yaml
children:
  - path: ../labs/microcircuit
    alias: circuit_a
    parameters: {}
```

Children can be addressed in wiring just like models:

```yaml
wiring:
  - from: stim.current
    to:
      - circuit_a.stimulus
```

Package-backed child Labs use an exact `package` + `version` and require a
matching entry in the sibling `biosimulant.lock` with `artifact_sha256`. The
archive is verified and resolved into the parent Lab's
`.biosimulant/dependencies/` state. Path-backed children remain supported for
existing self-contained Labs. See [Compose Hub Labs Locally](/how-to/compose-hub-labs-locally).

**Info:**

  For portable local package builds, prefer path-based children. Package-backed children always need an explicit version; they never fall back to `latest`.

## See Also

- [How to Write a lab.yaml](/how-to/write-lab-manifest)
- [model.yaml Schema](/references/model-manifest)
