En bref

  • Problème : Codex Desktop donnait une impression de ralentissement local sur mon Mac.
  • Ce que j’ai testé : tailles de ~/.codex, bases SQLite, WAL et sessions JSONL archivées.
  • Résultat : ~/.codex est passé d’environ 18 Go à 9.3 Go, et une agrégation large sur logs_2.sqlite est passée de 13.96s à 0.09s.
  • À retenir : avant d’accuser le modèle ou le réseau, inspecter l’état local.
  • Repo lié : pezzos/codex-local-maintenance.

Le ralentissement qui m’a fait regarder sous le capot

Je suis parti d’un ressenti très simple : Codex devenait de plus en plus lent. Pas un bug net, pas une erreur reproductible, plutôt cette impression que l’app traîne un poids local avant même qu’une conversation ait vraiment commencé.

Mon hypothèse de départ était assez large. Dans ~/.codex, trois fichiers semblaient pouvoir accumuler de l’historique :

  • state_5.sqlite
  • logs_2.sqlite
  • .codex-global-state.json

Je voulais savoir si l’un d’eux ajoutait du bruit au démarrage, à la sidebar, aux vues de logs, ou aux recherches locales. Je n’avais pas encore de preuve. Juste une bonne raison de mesurer.

Ce que les tailles racontaient

Les premiers relevés ont vite déplacé le soupçon. Le fichier JSON global ne pesait que 252 Ko, donc il n’était probablement pas la source principale du problème.

Le reste était plus parlant :

  • ~/.codex montait à environ 18 Go
  • logs_2.sqlite faisait 2.1 Go
  • le WAL de logs_2.sqlite montait jusqu’à 301 Mo, puis 1.3 Go pendant les premières opérations
  • archived_sessions faisait 5.4 Go
  • sessions faisait 6.8 Go
  • une agrégation large sur logs_2.sqlite prenait 13.96s

Ce n’était donc pas une histoire de petit fichier de préférence mal rangé. Le poids venait surtout de la base SQLite des logs, de son WAL, et des sessions JSONL archivées.

Nettoyer sans casser l’historique vivant

Je n’ai pas voulu supprimer brutalement ~/.codex. La partie délicate, ici, est que Codex peut être en train d’écrire dans ses bases ou dans ses sessions. Le bon ordre était donc lent et prudent.

D’abord, inspection en lecture seule : tailles, tables SQLite, nombre de lignes, WAL, répertoires de sessions. Ensuite seulement, nettoyage hors Codex, avec l’application fermée.

Le passage manuel commençait par fixer les chemins et sauvegarder les fichiers que j’allais toucher :

export CODEX_HOME="$HOME/.codex"
export KEEP_DAYS=14
export RUN_ID="$(date +%Y-%m-%d-%H%M%S)"
export BACKUP_DIR="$HOME/Documents/Codex/codex-maintenance-backups/$RUN_ID"

mkdir -p "$BACKUP_DIR"

cp "$CODEX_HOME/logs_2.sqlite"* "$BACKUP_DIR/" 2>/dev/null || true
cp "$CODEX_HOME/state_5.sqlite"* "$BACKUP_DIR/" 2>/dev/null || true
cp "$CODEX_HOME/session_index.jsonl" "$BACKUP_DIR/" 2>/dev/null || true

Ensuite, j’ai nettoyé la base de logs. L’idée était de tronquer le WAL, supprimer les logs trop anciens, être plus agressif sur TRACE, DEBUG et INFO, puis compacter :

sqlite3 "$CODEX_HOME/logs_2.sqlite" "
PRAGMA wal_checkpoint(TRUNCATE);
DELETE FROM logs
WHERE ts < strftime('%s','now','-14 days');
DELETE FROM logs
WHERE level IN ('TRACE','DEBUG','INFO')
  AND ts < strftime('%s','now','-3 days');
VACUUM;
PRAGMA wal_checkpoint(TRUNCATE);
PRAGMA optimize;
"

J’ai appliqué le même principe de checkpoint, VACUUM et optimisation à la base d’état, mais sans suppression de lignes :

sqlite3 "$CODEX_HOME/state_5.sqlite" "
PRAGMA wal_checkpoint(TRUNCATE);
VACUUM;
PRAGMA wal_checkpoint(TRUNCATE);
PRAGMA optimize;
"

Enfin, les sessions déjà archivées depuis plus de 14 jours sont parties en quarantaine horodatée, hors de ~/.codex :

export QUARANTINE="$HOME/Documents/Codex/codex-archived-sessions-quarantine/$RUN_ID"
mkdir -p "$QUARANTINE/archived_sessions"

find "$CODEX_HOME/archived_sessions" \
  -type f \
  -name '*.jsonl' \
  -mtime +14 \
  -print0 |
while IFS= read -r -d '' f; do
  mv "$f" "$QUARANTINE/archived_sessions/"
done

Les sessions déjà archivées depuis plus de 14 jours ont été déplacées en quarantaine, hors de ~/.codex, au lieu d’être supprimées directement. C’est moins satisfaisant qu’un grand ménage définitif, mais plus confortable : si une hypothèse est mauvaise, les fichiers existent encore ailleurs.

Le résultat après passage

Après nettoyage, les chiffres ont changé franchement :

  • ~/.codex est descendu à 9.3 Go
  • archived_sessions est passé de 5.4 Go à 894 Mo
  • logs_2.sqlite plus son WAL sont passés d’environ 2.6 Go à environ 595 Mo
  • logs_2.sqlite-wal est revenu autour de 9 Mo
  • 1 259 anciennes archives, pour 4.5 Go, ont été déplacées en quarantaine
  • la même agrégation de logs est passée d’environ 13.96s à 0.09s

Le gain disque est évident, mais ce n’est pas le plus intéressant. Le temps de requête sur les logs donne une piste plus concrète : une partie de la lenteur ressentie pouvait venir de là. Je ne peux pas prouver que tous les ralentissements venaient du bloat local, mais ce nettoyage a supprimé une source plausible et mesurable.

Le petit script que je veux garder

J’ai ensuite transformé le nettoyage manuel en script de maintenance macOS. Il fait peu de choses, volontairement :

  • il sort si Codex tourne ;
  • il prend un lock pour éviter deux runs concurrents ;
  • il sauvegarde logs_2.sqlite*, state_5.sqlite* et session_index.jsonl avant de modifier quoi que ce soit ;
  • il checkpoint et compacte logs_2.sqlite ;
  • il compacte state_5.sqlite ;
  • il déplace les vieilles sessions archivées dans une quarantaine ;
  • il supprime les anciens logs de maintenance et les quarantaines trop vieilles.

Le LaunchAgent macOS utilise RunAtLoad=true, donc le script se lance au login. Ce n’est pas un daemon permanent ; c’est juste un coup de balai au démarrage de session, quand Codex n’est pas encore lancé.

J’ai extrait une version générique dans un petit dépôt dédié. Les chemins personnels, le label launchd, les dossiers de logs et la quarantaine sont paramétrés ou templatisés. Le script ne contient pas de credential.

Ce que tu peux reprendre

  • la méthode d’inspection : taille disque, WAL, tables SQLite, temps de requête ;
  • le réflexe de backup avant modification ;
  • le principe de quarantaine plutôt qu’une suppression immédiate ;
  • le script, à condition de lire ses chemins, sa rétention et ses garde-fous.

Ce qu’il ne faut pas copier aveuglément

  • le lancement pendant que Codex tourne ;
  • la suppression directe des sessions archivées sans quarantaine ;
  • mes seuils de rétention 14 jours et 3 jours ;
  • mes chemins macOS de backup et de quarantaine ;
  • l’exécution automatique au login si Codex tourne déjà chez toi à ce moment-là ;
  • l’idée que ce nettoyage explique tous les ralentissements Codex.

Ce que je retiens

Quand une app agentique ralentit, la réponse facile est d’accuser le modèle, le réseau, ou la conversation courante. Ici, le premier endroit utile était beaucoup plus banal : le dossier local.

Je garde surtout trois réflexes :

  1. mesurer avant de nettoyer ;
  2. déplacer avant de supprimer ;
  3. automatiser seulement après un passage manuel compris.

Ce n’est pas une méthode générale pour accélérer Codex. C’est une trace pratique : dans ce cas précis, ~/.codex avait accumulé assez de logs SQLite et de sessions JSONL pour mériter une maintenance locale.

Le repo contient

  • bin/codex-maintenance.sh, le script de maintenance ;
  • un template LaunchAgent macOS ;
  • RESULTATS.md, avec les mesures avant/après ;
  • des notes d’investigation et un scan simple de credentials.

Il sert à

  • refaire l’enquête sans repartir de zéro ;
  • inspecter le script et l’adapter avant de toucher à ~/.codex ;
  • adapter une maintenance locale prudente sur macOS.

Il ne sert pas à

  • promettre une accélération générale de Codex ;
  • nettoyer un environnement en cours d’écriture ;
  • remplacer une sauvegarde ou une lecture des fichiers qui seront déplacés.