Sur Mac mini / Cloud Mac, avec Ollama, Claude Code et GitHub Actions en parallèle, le problème le plus fréquent n'est pas « pas assez rapide », mais swap, CLI saccadée et CI plus lente.
Ce texte sans installation d'outils : pourquoi trois workloads IA en parallèle font vaciller la mémoire, et comment le scheduling l'évite. Contre-exemple, budget mémoire, seuils, runbook 30 s et script complet — sans répéter le benchmark 16 Go vs 24 Go.
TL;DR
- Ollama toujours chargé + burst CI → swap très fréquent sur M4 (voir contre-exemple)
- La solution n'est souvent pas d'upgrader le Mac, mais plan de couches pour burst / interactive / background
- Avant CI
ollama stop— étape la plus critique et la plus simple (version 30 s)
Le modèle AI workload scheduling : sur Cloud Mac, la plupart des swap/OOM viennent du scheduling, pas d'un manque absolu de RAM.
Le vrai problème : souvent pas trop peu de RAM, mais pas de priorités
Symptômes : modèle local à vide + pic CI + agent lent — souvent lu à tort comme « il faut plus de RAM ».
Sur Cloud Mac, la plupart des swap/OOM viennent du scheduling des workloads, pas d'un déficit absolu de RAM. Sur un Mac mini, trois types de charge coexistent (section suivante) :
- Burst — GitHub Runner /
xcodebuild, +4–8 Go instantanés au push - Interactive — Claude Code, IDE + terminal + gros dépôt
- Background — inférence locale (Ollama) : 8B chargé occupe 5–7 Go en silence
Par défaut, tous se partagent la mémoire unifiée à égalité — personne ne « doit céder ». Correction : définir priorités et déclencheurs, passer l'inférence background de « installé = toujours là » à ressource déchargeable, préemptible par la CI.
Mauvais planning (très fréquent sur M4)
Combinaison vue sur Cloud Mac en petite équipe — « mode interdit » à l'onboarding :
Bad pattern · all three workloads default「full on」 qwen3:8b always loaded → 5–7 GB (background, zero calls) push triggers xcodebuild → +4–8 GB peak (burst) Claude Code indexing large repo → +2–3 GB (interactive) Observed (24GB M4 Mac mini) Swap 0 → 2.1 GB xcodebuild link stage latency +~40% Claude Code terminal noticeably sluggish
Sur M4 à mémoire unifiée, 8B résident + burst CI + codage interactif en même temps = swap fréquent.L'intérêt : montrer que le scheduling n'est pas un bonus mais une condition avec plusieurs charges.
Drei Lastformen: burst / interactive / background
Le planning ne peut pas être qu'une horloge. Sur Cloud Mac, les profils mémoire diffèrent :
| Forme | Exemple | Couche | Profil mémoire | Priorité |
|---|---|---|---|---|
| Burst | xcodebuild, Link, Simulator |
L1 Runner | pic, imprévisible | La plus haute — le Fact ne doit pas échouer |
| Interactive | Claude Code, IDE, SSH | L3 | moyen, humain présent | haute — inférence via API, pas gros modèle local |
| Background | Ollama Embedding, Log-Zusammenfassung | L2 | différable, déchargeable | Niedrigste — muss burst weichen |
En bref : L2 est la seule couche « évictable » — ses tâches sont surtout asynchrones et rejouables.
Budget mémoire: Anteil der drei Workloads
Ollama / Claude Code / GitHub Runner comme composants exemple ; chiffres demesures Mac mini M4(régime établi, pas pic de compilation) :
| Composant | Couche | Usage typique | Pics |
|---|---|---|---|
| macOS + cache système | L0 | 3–4 GB | relativement stable |
| Espace Claude Code | L3 | 1–3 GB | inférence via API, pas de poids locaux |
| GitHub Runner job | L1 | 2–6 Go (régime établi) | phase de link +4–8 Go |
| Ollama · qwen3:8b | L2 | 5–7 GB | freigegeben mit ollama stop |
| Ollama · qwen3:14b | L2 | 9–13 GB | avec burst, swap 2 Go+ facile |
| Ollama · nomic-embed-text | L2 | 0.3–0.8 GB | background léger possible le jour |
À la louche, 24 Go le jour « code + CI + 8B résident » ≈ 17 Go — marge ; avec 14B résident, dépasse 22 Go facilement.Die Budget-Tabelle beantwortet „geht es?“; Scheduling beantwortet „wer wann Speicher nutzt“.
Scheduling-Modell: von Zeitfenstern zu memory_pressure-Schwellen
Début avec tableau jour/nuit (mode ②) ; montée en charge : seuils de pression mémoire — sans se fier à « il est 22 h, batch » :
AI Workload Scheduler · L2-Q03 recommended rules When memory_pressure enters warn / critical (or equivalent > ~70%): → auto ollama stop qwen3:8b / qwen3:14b When memory_pressure normal (< ~50%) and idle > 10 min: → auto preload nomic-embed-text (keepalive 10m) When CI event trigger (Runner job start): → force CI mode: stop all Ollama large models, priority L1 > L3 > L2 When CI job succeeds + memory drops: → async trigger L2 batch (log summary / embedding rebuild)
Créneaux = baseline ; seuils = upgrade. Petite équipe : runbook + stop avant CI ; puis guard memory_pressure (§ Runbook).
Trois modes de base
Stratégies de base avec seuils :
| Mode | Méthode | Pour |
|---|---|---|
| ① Léger en parallèle | tagsüber nur nomic-embed-text; 8B/14B on-demand |
Mac mini 16 Go, codage d'abord |
| ② Créneaux | 09–18 code+CI / 22–06 batch nuit | 24 Go, embedding / logs planifiés |
| ③ CI déclenche le recul | vor Job ollama stop, puis asynchron L2 |
pushes fréquents, pics xcodebuild |
Recommandé : ① + ③ pour tous ; ② en complément de batch nocturne ; guard de seuils en filet.
Pipeline-Aufteilung: was auf L2, was auf L3
Fixer le pipeline avant le planning, sinon Ollama tourne à vide (voir L2-Q01 · erreur classique):
| Tâche | Couche | Note scheduling |
|---|---|---|
| modifier dépôt, patch | L3 Claude Code(API) | pas de gros modèle local |
| build, test, archive | L1 Runner | priorité burst max ; stop L2 avant pic |
| résumé logs échec CI | L2 qwen3:8b |
après job ou batch nuit |
| CodeGraph / RAG embedding | L2 nomic-embed-text |
résident le jour (<1 Go) |
Pics Runner et décalage CI
L1 Runner produit le Fact — l'inférence ne remplace pas le build. Changement CI minimal :
# .github/workflows/ios.yml · self-hosted macOS runner - name: Enter CI mode — free memory for xcodebuild run: | ollama ps ollama stop qwen3:8b 2>/dev/null || true ollama stop qwen3:14b 2>/dev/null || true sleep 30 # wait for memory reclaim; do not start xcodebuild same second - name: Build run: xcodebuild ...
Gemessen:Auf 24GB M4 gibt ollama stop qwen3:8b libère 5–7 Go en ~5–15 s ; swap existant : récupération en minutes — donc stop avant CI au moins 30 s à l'avance.
Runbook: version 30 s und vollständiges Skript
Version 30 s (suffit pour la plupart)
Keine Zeit pour das volle Skript? Diese drei Blöcke decken ~80 % ab:
① Avant CI (entscheidend) — in GitHub Actions oder Runner-Hook:
ollama stop qwen3:8b ollama stop qwen3:14b sleep 30
② Jour — embedding léger seulement :
ollama run nomic-embed-text --keepalive 30m
③ Nacht — im Batch-Fenster 8B laden:
ollama run qwen3:8b # then run your log summary / embedding rebuild scripts
Version complète (production)
Pour LaunchAgent / cron / multi-env, enregistrer sous ~/bin/cloud-mac-stack-runbook.sh:
Runbook complet · sous-commandes
day-start · ci-pre · ci-post · night-batch
#!/usr/bin/env bash # cloud-mac-stack-runbook.sh — L2-Q03 standard Runbook set -euo pipefail OLLAMA_HOST="${OLLAMA_HOST:-127.0.0.1:11434}" export OLLAMA_MAX_LOADED_MODELS=1 ensure_ollama() { curl -sf "http://${OLLAMA_HOST}/api/tags" >/dev/null || ollama serve & sleep 2 } ci_pre() { # before CI: force CI mode, L1 wins ollama ps || true ollama stop qwen3:8b 2>/dev/null || true ollama stop qwen3:14b 2>/dev/null || true sleep 30 } ci_post() { # after CI: restore light embedding (lowest background tier) ensure_ollama ollama run nomic-embed-text --keepalive 10m } day_start() { # login / boot: embedding only or stop all ensure_ollama ollama stop qwen3:8b 2>/dev/null || true ollama stop qwen3:14b 2>/dev/null || true ollama run nomic-embed-text --keepalive 30m } night_batch() { # night batch (cron: 0 22 * * *) ensure_ollama ollama run qwen3:8b --keepalive 6h # ./your-log-summary-or-embed-rebuild.sh } case "${1:-}" in day-start) day_start ;; ci-pre) ci_pre ;; ci-post) ci_post ;; night-batch) night_batch ;; *) echo "Usage: $0 {day-start|ci-pre|ci-post|night-batch}"; exit 1 ;; esac
Memory guard (cron /5 min ou LaunchAgent) : décharger les gros modèles sous pression — minimum du scheduling par seuils.
#!/usr/bin/env bash # memory-guard.sh — memory_pressure threshold guard PRESSURE=$(memory_pressure 2>/dev/null | head -1 || true) if echo "$PRESSURE" | grep -qiE 'warn|critical|urgent'; then logger -t cloud-mac-stack "memory guard: stopping Ollama 8B/14B ($PRESSURE)" ollama stop qwen3:8b 2>/dev/null || true ollama stop qwen3:14b 2>/dev/null || true fi # optional: when pressure normal + no Runner job, restore embedding # if echo "$PRESSURE" | grep -qi 'normal'; then ... fi
Exemples d'intégration :
- GitHub Actions — erster Step
ci-pre, letzterci-post - LaunchAgent — à la connexion
day-start; cron 22:00night-batch - cron —
*/5 * * * * /path/memory-guard.sh
Planifier un Mac mini 16 Go
- pas de 14B résident ; 8B seulement en
night-batch - Le jour : seulement
day-start(embedding ou tout arrêter) - Jede CI braucht
ci-pre, ohne Ausnahme - Wenn „Desktop + 8B + Claude Code“ dauerhaft parallel laufen soll → 24GB; Scheduling hebt keine Hardware-Grenze
16 Go : jour sans gros modèle, nuit un modèle par tâche, avant CI toujours ci-pre. 24 Go : embedding le jour, 8B décalé de la CI, 14B la nuit.
Quelle stratégie choisir
| Votre cas | Recommandation |
|---|---|
| 24 Go · peu de pushes · surtout Claude Code | day-start + Embedding; kein Nacht-Batch |
| 24GB · tägliche CI · Log-Zusammenfassung | ci-pre/post + night-batch + Memory Guard |
| 16GB · lokales 8B nötig | nur night-batch; tagsüber Claude API |
| Ollama sans appel une semaine | zuerst L2-Q01 — Pipeline definieren |
Serie · Cloud Mac AI Stack
L2-Q03 · Couche de scheduling mémoire — répond dehors « éviter le swap sur Mac mini » ; suite de L2-Q01 couche d'inférence privée :
- L2-Q01 — Was Inference ist (Positionierung)
- L2-Q03 · cet article — couche de scheduling mémoire (scheduling sur un hôte)
- Geplant — Model-Pinning, Health-Check 11434, Ollama-Aufruf aus CI
- Downstream — L4 Context + MCP-Scheduling (morgen L4-Q03)
Kein Ollama-Tutorial und kein reiner CI/CD-Tuning-Text — mais erste Couche eines AI-Workload-Schedulers auf Apple Silicon.
Articles publiés
- L2-Q01 · Private Inference-Couche — L2-Position; dieser Text ist die Scheduling-Fortsetzung.
- L2-Q02 · 16 Go vs 24 Go — chiffres swap ; pas de doublon benchmark.
- L1-Q01 · Runner — höchste burst-Priorité.
- L3 · Claude Code — interaktiver Hauptpfad.
FAQ
Ollama, Claude Code et GitHub Actions en parallèle sur Mac mini — swap ?
Oui, sans priorités entre burst, interactif et arrière-plan. Voir § Le vrai problème et contre-exemple.
Ollama doit-il tourner en permanence ?
Non. Traitez l'inférence locale comme ressource planifiable : le jour, seulement nomic-embed-text ; gros modèles à la demande ou en batch nocturne.
Arrêter Ollama avant un build CI ?
Recommandé. Voir runbook 30 s · avant CI ou ci-pre en version complète.
Claude Code et Ollama ensemble ?
Ja. Codage via API ; localement : poids du modèle et pics CI. stop avant CI ou créneaux.
OOM sur Cloud Mac = manque de RAM ?
Dans nos scénarios, la plupart des OOM viennent du scheduling, pas d'un manque absolu. Limite 16 Go : mesures L2-Q02.
Créneaux ou seuils memory_pressure ?
D'abord le runbook 30 s; puis memory-guard.sh (voir runbook complet ci-dessous).
Différence avec L2-Q01 ?
Q01 = position Inference Service ; Q03 (couche de scheduling mémoire) = comment planifier les workloads IA sur un hôte.
Cloud Mac AI Stack · aperçu demain
Claude Code + MCP : GitHub, fichiers locaux et API sur une chaîne
Une fois L2 cadré, vient L4 Context : comment MCP relie GitHub, le dépôt et les API au flux Claude Code.
Retour au blog · Cloud Mac AI Stack