<!-- Source: https://docs.biosimulant.com/references/library/hub-composition-api -->

# HubComposition API

`HubComposition` explicitly resolves version-pinned Hub Labs into one
caller-owned `BioWorld`. It is the local-runtime API for mixing a Hub Lab with
your own `BioModule` instances.

```python
from biosimulant import BioWorld
from biosimulant.hub import HubComposition

world = BioWorld(communication_step=0.1)
world.add_biomodule("controller", DoseController())

composition = HubComposition(world, lab_root="./lab")
composition.add("medium", "acme/nutrient-medium@1.1.0")
composition.apply()
composition.setup()
world.run(duration=24.0)
```

**Info:**

  `HubComposition` requires `biosimulant` 0.0.20 or later. `.add()` resolves
  the requested Lab; importing `biosimulant.hub` never downloads a Lab.

## Constructor

```python
HubComposition(world, lab_root, registry_url=None, dependency_root=None)
```

| Parameter | Meaning |
| --- | --- |
| `world` | The `BioWorld` that receives the resolved Hub Lab models and wiring. |
| `lab_root` | A source Lab directory containing `lab.yaml` and the matching `biosimulant.lock`. |
| `registry_url` | Optional Hub registry endpoint override. |
| `dependency_root` | Optional writable directory for this Lab's resolved dependency state. |

By default, dependency state belongs only to the parent Lab:

```text
<lab_root>/.biosimulant/dependencies/
```

It is disposable operational state, excluded from ordinary package payloads.
Each package-backed child must use an exact `package@version` and have a
matching SHA-256 entry in the sibling `biosimulant.lock`.

## Methods

### `.add(alias, reference)`

Adds a Hub Lab beneath `alias` and resolves `reference`, which must be exactly
`namespace/name@version`.

```python
composition.add("medium", "acme/nutrient-medium@1.1.0")
```

The parent lockfile must pin that same package and version. The downloaded
archive is checksum-verified before its Lab tree is added. An alias can be
added only once. Returns the composition so calls can be chained.

### `.connect(source, targets)`

Adds wiring between aliases in the caller's composed Lab. `targets` is a list
of destination references.

```python
composition.connect("controller.dose", ["medium.inflow"])
```

Only connect ports exposed by the referenced Lab's root `io`; signal types must
remain compatible. Returns the composition so calls can be chained.

### `.apply(install_deps=True)`

Flattens the resolved Lab tree into the supplied `BioWorld`, instantiates its
models, and applies the declared wiring. Set `install_deps=False` only when the
model dependencies have already been installed by your environment.

### `.setup()`

Calls `world.setup(...)` with the resolved Labs' setup declarations. Call it
after `.apply()` and before `world.run(...)`.

### `.dependency_root`

Read-only `Path` property for the effective Lab-local dependency directory.
Pass `dependency_root=` to the constructor when the default Lab location is not
writable.

## Packaging and standalone archives

Normal `.bsilab` releases retain package references and lockfile provenance.
Use `biosimulant labs package --vendor-dependencies` to build a fully
self-contained archival package. When running a standalone archive in a
read-only directory, use the CLI `--dependency-root` option to choose writable
state.

For the end-to-end manifest, lockfile, cache, and vendoring workflow, follow
the [Compose Hub Labs Locally guide](/how-to/library/compose-hub-labs-locally).
