> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cyberwave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Model cache

> How Edge Core resolves ML model weights into a local cache before the worker container starts — including the runtime-managed fallback that lets Ultralytics `.pt` entries (YOLO26, YOLOE-26) self-download without a mirrored URL.

<Info>
  Stub — a human will curate the wording before publishing.
</Info>

## What it does

Every workflow worker that calls `cw.models.load("<id>")` needs the
weight file on disk before the worker container starts. Edge Core's
**Model Manager** resolves each ID into the local cache at
`~/.cyberwave/models/{model_id}/` and serves it read-only into the
worker. Sources are tried in priority order; the first one that yields
a checksum-verified file wins.

## Resolution order

For each required model:

1. **Pre-staged on disk.** A file already at `~/.cyberwave/models/{model_id}/` is registered as `downloaded_from: prestaged` and short-circuits the catalog entirely. Use this for air-gapped sites.
2. **Cyberwave-hosted signed URL** (`GET /api/v1/mlmodels/{uuid}/weights`). Authenticated artefact in our private GCS bucket — preferred when we have mirrored the checkpoint.
3. **Upstream weights URL** (`download_url` / `metadata.upstream_weights_url`). Public community mirror — used for ONNX models we publish to `static.cyberwave.com/ml_models/`.
4. **Runtime-managed download** (new): when the catalog entry has no URL of any kind but its `edge_runtime` ships its own weight resolver (today: `ultralytics` against its GitHub releases hub), Edge Core invokes that resolver in a subprocess and caches the result as `downloaded_from: runtime_managed`. This is what lets `.pt` catalog entries (YOLO26, YOLOE-26) work without a mirrored upstream URL.

Bit-rot detection (SHA-256) runs on every `ensure_model` call. Pre-staged files are never auto-overwritten by catalog updates.

## ML runtime extras

The default install keeps the runtime surface lean — no Torch, no Ultralytics, no ONNX. Catalog entries that rely on the **runtime-managed download** fallback need the matching runtime installed on the edge host:

```bash theme={null}
# Pull in Ultralytics so YOLO / YOLOE .pt entries can self-download
pip install 'cyberwave-edge-core[ml]'

# Other available extras (mirror the cyberwave SDK extras 1:1):
pip install 'cyberwave-edge-core[ml-onnx]'    # onnxruntime
pip install 'cyberwave-edge-core[ml-tflite]'  # tflite-runtime
pip install 'cyberwave-edge-core[ml-stt]'          # whisper.cpp catalog models only
pip install 'cyberwave-edge-core[ml-stt-faster]'   # faster-whisper catalog models only
pip install 'cyberwave-edge-core[ml-all-audio]'    # all speech extras (avoid on Pi)
pip install 'cyberwave-edge-core[ml-all]'          # CI/dev fat bundle only
```

Voice workflow nodes (Audio Assistant, Wake Word, Fuzzy Matcher) use separate extras — see [Edge workflow dependencies](/feature-reference/workflows/edge-dependencies).

When the required runtime is missing, the resolver raises a `RuntimeError` listing three workarounds: drop the file under `~/.cyberwave/models/{model_id}/`, upload to `/api/v1/mlmodels/{uuid}/weights`, or set `metadata.download_url` on the catalog entry.

## Pre-staging weights (air-gapped sites)

```bash theme={null}
mkdir -p ~/.cyberwave/models/yoloe-26s-seg
cp /usb-stick/yoloe-26s-seg.pt ~/.cyberwave/models/yoloe-26s-seg/
```

Edge Core picks up the file on the next sync, infers the runtime from the extension (`.pt` → `ultralytics`, `.onnx` → `onnxruntime`, …), and writes a sidecar `metadata.json` so subsequent runs are deterministic.

## Self-healing the cache

A failed download leaves an empty `cache_dir/{model_id}/` behind — `mkdir` runs before the network fetch, and any error in the downloader skips the cleanup. Left alone, the SDK in the worker container would later route that directory into `torch.load` and crash with `IsADirectoryError` on every restart.

Edge Core handles this in three layers:

* **Per-download cleanup** (conservative). A failed `_download_model` / `_download_runtime_managed` removes the staging directory before the exception propagates, provided it contains only an `.dl_*.part` partial download, a `metadata.json` sidecar, or nothing at all. Operator-staged content blocks the prune.
* **Startup sweep** (conservative). `ModelManager()` walks `cache_dir/` once at construction time and prunes any per-model subdirectory that is not in the manifest *and* contains only orphan cruft. This is what unsticks hosts that were already wedged before this code shipped. Operator-staged content blocks the prune.
* **`evict_model('foo')`** (decisive). When there is no manifest entry but `cache_dir/foo/` exists on disk, the directory is removed **unconditionally**. This is the recovery hook for a remote eviction API to call without shell access to the host; an explicit `evict` is treated as a stronger operator-intent signal than the conservative auto-sweeps.

The SDK has matching logic in `ModelManager._resolve_model_path` so an orphan dir that survives Edge Core (e.g., on a host that hasn't picked up this release yet but mounts a fixed SDK) is also recovered inside the worker container. The Ultralytics runtime is the defensive backstop: if a directory ever reaches it (a hand-built `UltralyticsRuntime().load(...)` call bypassing the manager), it raises a clear `FileNotFoundError` instead of letting Ultralytics call `torch.load(<dir>)`.

## Sidecar fields

Every cached weight has a `metadata.json` next to it. Fields you'll see:

| Field             | Meaning                                                                                                               |
| ----------------- | --------------------------------------------------------------------------------------------------------------------- |
| `downloaded_from` | `artifact_url`, `download_url`, `runtime_managed`, or `prestaged`                                                     |
| `source_url`      | Public URL we fetched (or `null` for `artifact_url` and `runtime_managed` — neither is a re-fetchable persistent URL) |
| `upstream_url`    | Provenance hint                                                                                                       |
| `checksum_sha256` | SHA-256 of the on-disk bytes; re-verified on every load                                                               |
| `runtime`         | `ultralytics`, `onnxruntime`, `tflite`, `tensorrt`, `torch`, `opencv`                                                 |

See the full module docstring in [`cyberwave-edge-core/cyberwave_edge_core/model_manager.py`](https://github.com/cyberwave-os/cyberwave-edge-core/blob/main/cyberwave_edge_core/model_manager.py).
