Depuis quelques temps, j'utilise comme beaucoup d'entre vous Claude Code pour accélérer la gestion de mes tâches techniques. Je l'utilise surtout pour m'aider à résoudre, comprendre, améliorer mes connaissances sur les sujets que je traite.
Utilisateur de la CLI, le fait de donner tout pouvoir à un outil tel que Claude ne me plaisait pas trop,
et j'ai donc naturellement commencé à utiliser Docker Sandbox (sbx) qui me permet, entre autres, d'avoir :
- Une isolation du filesystem (sbx n'a accès qu'au dossier courant, et il ne "pourrit" pas mon système hôte)
- Pas d'accès à toutes mes variables d'environnement
- Un contrôle sur les flux réseau sortants
Mais le problème, c'est qu'une sandbox sbx, c'est une micro-vm qui peut être éphémère.
Une fois la session Claude terminée, vous pouvez la supprimer avec sbx rm, son historique et sa mémoire avec.
⚠️ Ce que j'ai mis en place à date (été 2026) peut avoir évolué depuis, les projets sont très actifs !
Les problèmes
La mémoire
Claude Code stocke la mémoire et l'historique de chaque session dans
~/.claude/projects/<slug>/. Oui, vous pouvez vérifier chez vous, vous aurez un dossier
dont le nom dérive du chemin du workspace pour chaque dossier où vous avez lancé une session Claude.
Dans une sandbox, ce dossier vit sur un volume Docker lié au cycle de vie de la sandbox.
Lorsqu'on supprime la sandbox (sbx rm), on perd tout : la mémoire accumulée au fil des sessions,
les transcripts .jsonl, la config perso.
Et donc vous voyez venir la tuile : au prochain sbx run alors que la sandbox a été détruite, tout est oublié 🫤.
La config custom
Autre problème, j'utilise Claude à ma façon, et j'aimerais bien avoir ma façon aussi dans la sandbox, comme par exemple :
- Mon propre
CLAUDE.md - Ma config propre (thème clair, en français, pas de télémétrie)
- Mes plugins activés (RTK)
Avec sbx run claude, Claude Code est lancé en mode YOLO, mais pas plus.
Il va falloir trouver un moyen de copier depuis l'hôte.
TL;DR : Vous pouvez retrouver mon kit ici si vous avez la flemme de lire la suite 🫠.
Une solution : les kits mixin
Docker sbx permet d'étendre les fonctionnalités de base avec des kits, notamment les kits mixin. C'est donc cela que je vais utiliser pour résoudre mes 2 problèmes !
J'utilise la spec
v2des kits, livrée avecsbx0.38.0, sortie le jour même de cet article.
Sauver la mémoire sur l'hôte
Un kit sbx ne peut pas monter un dossier arbitraire de l'hôte.
Les seuls chemins réellement persistants côté hôte dans une sandbox sont le workspace lui-même
et les skills.
Tout le reste (~/.claude/projects, sessions, todos) est un volume déclaré par l'agent de base, donc lié
à la sandbox.
Ce qu'on va alors faire, c'est simplement de remplacer ~/.claude/projects/<slug> par un lien symbolique
pointant vers .claude-project/ à la racine du workspace : lorsque ma sandbox sera créée,
un dossier .claude-project/ sera créé à la racine du workspace, et le lien symbolique sera mis en place.
Côté kit, cela se fait via un script exécuté à chaque démarrage de sandbox dans le fichier spec.yaml.
1startup:
2 - description: Links ~/.claude/projects/<slug> to the workspace, excludes it from git
3 user: "1000"
4 command:
5 - sh
6 - -c
7 - |
8 # Mon super code généré par Claude pour faire un symlink
Ce script tourne à chaque démarrage de sandbox, mémoire et transcripts atterrissent alors
physiquement sur mon Mac, visibles dans le Finder, survivent à sbx rm.
J'ai défini un dossier .claude-project/, qui est exclu localement via .git/info/exclude,
cela est aussi géré au niveau du kit :
1# Ignore local to the clone, without touching the versioned .gitignore.
2# --git-common-dir (not --git-dir): in a linked worktree, --git-dir
3# points to .git/worktrees/<name>, where info/exclude is not read by git.
4GITDIR=$(git -C "$WS" rev-parse --git-common-dir 2>/dev/null) || exit 0
5case "$GITDIR" in /*) ;; *) GITDIR="$WS/$GITDIR" ;; esac
6mkdir -p "$GITDIR/info"
7grep -qxF '/.claude-project/' "$GITDIR/info/exclude" 2>/dev/null \
8 || echo '/.claude-project/' >> "$GITDIR/info/exclude"
Autre point important, avec agentInstructions je vais passer des instructions spécifiques
pour que Claude Code gère bien ce dossier .claude-project/.
1agentInstructions:
2 content: |
3 ## Host-persisted project directory
Avec cela, lorsque la sandbox est arrêtée, supprimée, relancée, le dossier .claude-project/ persiste avec ce qu'il faut !
Fini la perte de mémoire en environnement cloisonné 🧠 !
Récupérer ma config perso
Le symlink règle la mémoire, mais chaque sbx run repart aussi avec un settings.json vierge.
Même mécanique ici, un script qui merge un fichier JSON custom avec celui par défaut à chaque démarrage grâce à jq.
Voici mon fichier settings.custom.json (extrait) qui sera fusionné :
1{
2 "theme": "light-ansi",
3 "statusLine": {
4 "type": "command",
5 "command": "~/.claude/statusline.sh"
6 },
7 "env": {
8 "CLAUDE_CODE_ENABLE_TELEMETRY": "0"
9 },
10 "language": "French"
11}
Et toujours pareil, le merge sera effectué au démarrage de la sandbox, défini ici dans le spec.yaml :
1jq --arg dir "$TARGET" --slurpfile kit "$CUSTOMSETTINGS" \
2 '. * {autoMemoryDirectory: $dir} * $kit[0]' "$SETTINGS" > "$TMP"
Ajouter mes plugins (RTK surtout)
On continue, cette fois-ci avec les plugins. Vous avez compris le principe maintenant,
du bon script shell dans le spec.yaml, mais au setup cette fois, pour éviter d'installer RTK
à chaque (re)démarrage de la sandbox !
Alors pour le moment c'est un peu sale, car on a "pin" la version de RTK à installer, pour éviter un curl | sh :
1setup:
2 install:
3 - description: Installs rtk (pinned binary, checksum verified) and its Bash hook
4 user: "1000" # Le user n'est pas root, mais 1000 par défaut
5 command: |
6 # Ma super installation de RTK
Le plugin RTK a besoin de définir des ordres dans le fichier CLAUDE.md, on voit ça juste après.
Mon CLAUDE.md
Au fur et à mesure de mon utilisation de Claude, j'ai créé mon propre CLAUDE.md pour que l'outil me réponde
selon mes préférences, et j'aimerais bien le retrouver dans mes sandboxes.
Cette fois-ci, pas la peine de scripter, le kit permet de copier simplement des fichiers depuis
le répertoire files/home/.claude vers le répertoire ~/.claude/ de la sandbox.
"Sauf que", mon fichier à moi CLAUDE.md est personnel (profil, stack de référence, décisions actées,
conventions de travail), pas forcément lié au projet ou à la sandbox.
J'ai donc décidé :
- de le nommer
PERSONA.md, et de faire une inclusion via@-import. - d'avoir ce
PERSONA.mdplaceholder dans le kit mis à disposition. - d'avoir mon
PERSONA.mdsynchronisé avecmise run claudevia unetaskpersonnalisée (voir plus bas).
J'ai ensuite un @RTK.md : rtk en a besoin. Ce qui nous donne au final un fichier assez sommaire :
1<!-- PERSONA, mes infos "persos" -->
2@PERSONA.md
3
4<!-- Plugin RTK (https://github.com/rtk-ai/rtk) -->
5@RTK.md
Synchro de mon PERSONA.md
Pour utiliser mon vrai ~/.claude/PERSONA.md, je le synchronise avec mise run claude,
dont voici la task correspondante. Au moins si besoin d'être utilisée ailleurs, elle n'est pas exclusive au kit :
1#!/usr/bin/env bash
2#MISE description="Sandbox claude-project-host : new if absent, resume + attach if present"
3#MISE dir="{{cwd}}"
4#MISE tools={ "github:docker/sbx-releases" = "latest" }
5#USAGE arg "<workspace>" help="Chemin du workspace a monter" default="."
6
7# Copy PERSONA.md to the kit directory
8kit_dir="$HOME/.config/sbx/claude-project-host"
9cp "$HOME/.claude/PERSONA.md" "$kit_dir/files/home/.claude/PERSONA.md"
10
11ws="$(cd "${usage_workspace}" && pwd)" || { echo "Workspace not found: '${usage_workspace}'" >&2; exit 1; }
12name="claude-$(basename "$ws")"
13
14# Check if the sandbox is already present, reattach if so
15if sbx ls | awk '{print $1}' | grep -Fqx "$name"; then
16 echo "Sandbox '$name' present, reattaching..."
17 sbx run "$name"
18# Otherwise, create a new sandbox with the toolkit
19else
20 echo "Sandbox '$name' absent, creating..."
21 sbx run --name "$name" --kit "$kit_dir" claude "$ws"
22fi
En plus
Quelques bonus
Tant qu'à faire, je rajoute des instructions spécifiques dans mon kit :
- Faire des "Session summaries" : écrire un résumé après chaque choix / débat important, au format Markdown Obsidian pour que je puisse l'intégrer facilement dans mon coffre de notes.
- Pour le moment pas beaucoup plus 😅
Distribution du kit
Le mixin a été pensé pour mon usage perso, en français. Pour le publier, j'ai séparé le mécanisme (générique, à partager) du contenu (personnel, à ne pas partager).
Deux fichiers concentraient le problème :
PERSONA.md— on l'a vu plus haut, le kit publié embarque désormais un placeholder (les sections à remplir, sans contenu), et mon vraiPERSONA.mdreste local, resynchronisé par une tâchemise run claudequi vit hors du repo."language": "French"dans les préférences répliquées — un défaut personnel que je garde pour mon propre usage, à charge pour quiconque fork le kit de le changer pour le sien.
Et pour celles et ceux qui ont lu jusque-là, je remets le lien du dépôt : https://github.com/rverchere/sbx-kit-claude-project-host
Amusez-vous bien avec Docker Sandbox et Claude Code !
Liens
- Spec des kits
sbx: SPEC-v2.md - Kits communautaires : sbx-kits-contrib
- Plugin RTK : rtk-ai/rtk
