Problem
On smaller-memory Macs, users may already have browsers, Docker, chat apps, IDEs, and other memory-heavy applications open. Loading an Osaurus model can then push macOS into new swap activity and make model load, TTFT, and decode extremely slow with no clear explanation.
This is distinct from static low-RAM feasibility and from the existing generic host-pressure advisory. A Mac may have old swap allocated while currently healthy. The signal needed here is new swap growth during an Osaurus cold model-load / first-prefill window, relative to a sample taken immediately before that load.
Current gap
HostMemoryPressureProbe already records swapUsedBytes and swapins, but MemoryPressureAdvisory.evaluate deliberately triggers only from low free memory plus decompression rate. It does not compute a per-load swap delta. The existing RAM feasibility banner predicts whether a model fits; it does not tell the user that loading the selected model has just caused system swap usage to increase.
Required behavior
- Take a host-memory baseline immediately before a real cold model load begins. Do not start a new attribution window for an already-resident model.
- Sample during model loading and through first prefill / first output.
- Compute monotonic
swapGrowthBytes = max(0, current.swapUsedBytes - baseline.swapUsedBytes) and retain model name, load phase, elapsed time, free/compressed memory, decompression rate, and swap-in rate.
- When new swap growth crosses a meaningful noise floor or rises rapidly, show a prominent one-time popup for that load. Use tiered warning/severe thresholds rather than total swap percentage; exact thresholds should be calibrated with fault-injected samples and at least one small-RAM Mac.
- Suggested copy:
Loading MODEL caused macOS swap usage to grow by X GB. This can make the model dramatically slower and increase SSD activity. Close memory-heavy apps, unload other models, or choose a smaller model.
- Popup actions:
- Open Activity Monitor (Memory view) so the user can identify applications to quit.
- Unload Model.
- Keep Running.
The app must never automatically quit another application. It may assist the user in identifying memory-heavy apps, but the user decides what to close.
Attribution wording
The measurement is host-wide. Osaurus can prove that new swap growth occurred inside its model-load window, but macOS may choose pages belonging to other open applications for swap. Logs should say the load coincided with / triggered system swap growth, not claim that every swapped byte belongs to the Osaurus process.
Non-goals
- Do not warn from historical swap usage or percentage alone.
- Do not silently lower
MLX.Memory.memoryLimit.
- Do not enable JangPress or another model-family backend as a universal fix.
- Do not block every load solely from this advisory.
- Do not change sampler, prompt, reasoning, or model behavior.
Acceptance tests
- High pre-existing swap with zero per-load growth: no popup.
- Per-load swap growth above the warning threshold: popup names model and delta.
- Rapid severe growth: severe wording and actions appear promptly.
- Growth outside an active load/prefill attribution window: no model-attributed popup.
- Already-resident model reuse: no new cold-load attribution window.
- Unload/new model load resets the baseline and one-time suppression.
- Probe failure or counter regression: no fabricated warning.
- Popup does not refuse the load, alter MLX limits, or repeat continuously.
- Fault-injected UI test proves all three actions.
- Live small-RAM proof records baseline/current/delta,
phys_footprint, memory pressure, TTFT, and token/s before this is called complete.
Relevant current code
Packages/OsaurusCore/Services/ModelRuntime/HostMemoryPressureProbe.swift
Packages/OsaurusCore/Models/Chat/MemoryPressureAdvisory.swift
Packages/OsaurusCore/Services/ModelRuntime.swift
Packages/OsaurusCore/Views/Chat/FloatingInputCard.swift
Packages/OsaurusCore/Tests/Chat/MemoryPressureAdvisoryTests.swift
Packages/OsaurusCore/Tests/Chat/MemoryPressureWiringTests.swift
Problem
On smaller-memory Macs, users may already have browsers, Docker, chat apps, IDEs, and other memory-heavy applications open. Loading an Osaurus model can then push macOS into new swap activity and make model load, TTFT, and decode extremely slow with no clear explanation.
This is distinct from static low-RAM feasibility and from the existing generic host-pressure advisory. A Mac may have old swap allocated while currently healthy. The signal needed here is new swap growth during an Osaurus cold model-load / first-prefill window, relative to a sample taken immediately before that load.
Current gap
HostMemoryPressureProbealready recordsswapUsedBytesandswapins, butMemoryPressureAdvisory.evaluatedeliberately triggers only from low free memory plus decompression rate. It does not compute a per-load swap delta. The existing RAM feasibility banner predicts whether a model fits; it does not tell the user that loading the selected model has just caused system swap usage to increase.Required behavior
swapGrowthBytes = max(0, current.swapUsedBytes - baseline.swapUsedBytes)and retain model name, load phase, elapsed time, free/compressed memory, decompression rate, and swap-in rate.The app must never automatically quit another application. It may assist the user in identifying memory-heavy apps, but the user decides what to close.
Attribution wording
The measurement is host-wide. Osaurus can prove that new swap growth occurred inside its model-load window, but macOS may choose pages belonging to other open applications for swap. Logs should say the load coincided with / triggered system swap growth, not claim that every swapped byte belongs to the Osaurus process.
Non-goals
MLX.Memory.memoryLimit.Acceptance tests
phys_footprint, memory pressure, TTFT, and token/s before this is called complete.Relevant current code
Packages/OsaurusCore/Services/ModelRuntime/HostMemoryPressureProbe.swiftPackages/OsaurusCore/Models/Chat/MemoryPressureAdvisory.swiftPackages/OsaurusCore/Services/ModelRuntime.swiftPackages/OsaurusCore/Views/Chat/FloatingInputCard.swiftPackages/OsaurusCore/Tests/Chat/MemoryPressureAdvisoryTests.swiftPackages/OsaurusCore/Tests/Chat/MemoryPressureWiringTests.swift