Sur Mac mini, planifier les charges IA : comment éviter le swap avec Ollama, Claude Code et GitHub Runner

L2-Q03 · Couche de scheduling mémoire

2026.06.04  ·  ~14 min  ·  runbook ops, pas tutoriel d'installation

Mémoire unifiée Mac mini : Ollama, Claude Code et GitHub Actions — planning pour éviter le swap

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.

AI
Workload Scheduling
30s
Runbook minimal
0
lignes brew install

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) :

  • BurstGitHub Runner / xcodebuild, +4–8 Go instantanés au push
  • InteractiveClaude 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, letzter ci-post
  • LaunchAgent — à la connexion day-start ; cron 22:00 night-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.

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
Planning IA Tarifs Cloud Mac