# Core AI Fast First Token and the Right Compute Unit: Lesson 05. CPU-only safe path and memory

Lesson id: `core-ai-fast-first-token/05-cpu-only-safe-path-and-memory`
Human lesson: https://edgefde.dev/courses/core-ai-fast-first-token/05-cpu-only-safe-path-and-memory.html

## Goal

Add an ordered compute plan with a CPU-only fallback and budget memory by measured function loads.

## Prerequisites

- Lesson 04 checks
- Lesson 01 memory gate from the LLM survival course (optional)

## Inputs

- Model URL
- Per-device remote config for forced CPU

## Outputs and artifacts

- `loadWithFallback` function
- Remote switch for `.cpuOnly`
- Measured MB per `loadFunction`

## Steps

1. Write `options(for:)` mapping plans to `SpecializationOptions(preferredComputeUnitKind:)` and `.cpuOnly`.
2. Write `loadWithFallback` that skips units not in `ComputeUnitKind.availableKinds` and logs the chosen plan.
3. Add a remote flag per device model that forces `.cpuOnly`.
4. Measure memory before and after each `loadFunction(named:)` with `os_proc_available_memory()`, three times on a quiet app.
5. Feed the measured number into your memory gate, plus KV cache or state buffers.
6. Check docs and code reviews use `.aimodel`/`.aimodelc` for Core AI and `.mlpackage`/`.mlmodelc` for Core ML.

## Constraints

- Do not override the default compute choice without measurements.
- Swift only.

## Acceptance checks

- Forcing `.cpuOnly` via remote config works on every supported device.
- The memory number per function is in the model's release notes.

## Key concepts

- `SpecializationOptions.cpuOnly` is the safe fallback. `ComputeUnitKind.availableKinds` says what the device has.
- Each compute plan is a separate specialization and cache entry.
- Weights and buffers belong to loaded functions, not to `AIModel`. Measure memory around `loadFunction`.
- Core AI uses `.aimodel` and `.aimodelc`. Core ML uses `.mlpackage` and `.mlmodelc`.

## Takeaways

- Ship an ordered list of compute plans that ends in `.cpuOnly`, plus a remote switch.
- Budget memory from measured function loads, and only load the functions you need.
- Keep the default compute choice unless your measurements show a reason to change it.
