English | 中文 | 한국어 | Français | Português
Remarque : Cette traduction est assistée par machine et peut être en retard par rapport au README anglais. Pour toute information faisant autorité, consultez README.md. Les corrections sont les bienvenues — veuillez ouvrir un PR.
Note: This translation is machine-assisted and may lag the English README. For anything authoritative, see README.md. Corrections are very welcome — please open a PR.
Proxy d'optimisation du cache pour Claude Code. Corrige les bogues du prompt cache qui entraînent une consommation excessive du quota, stabilise le préfixe de requête et surveille les régressions silencieuses. Fonctionne avec toutes les versions de CC, y compris le binaire Bun v2.1.113+.
Ce README documente la branche main actuelle ; la disponibilité des versions est notée par fonctionnalité.
Un proxy local se place entre Claude Code et Anthropic. Avant de continuer la lecture, voici exactement ce que cela signifie — le traitement complet se trouve dans Modèle de sécurité.
- Se lie à
127.0.0.1par défaut. - Transmet le trafic de Claude Code à Anthropic. Sur le chemin par défaut, il n'effectue aucun autre appel sortant — la télémétrie est écrite dans des fichiers locaux sous
~/.claude/, jamais envoyée nulle part. Deux fonctionnalités optionnelles effectuent leurs propres appels sortants, toutes deux désactivées sauf si vous les activez : le rafraîchissement OAuth (CACHE_FIX_OAUTH_REFRESH=on) envoie vers le endpoint de tokens d'Anthropic, et l'accélération de téléchargement via le forward proxy réémet les téléchargements de versions versdownloads.claude.ai/storage.googleapis.com. - Peut lire et réécrire
POST /v1/messages. Cette capacité est la réparation du cache — il n'existe aucune version de ceci qui fonctionne sans elle. - La transformation est idempotente : si aucune correction n'est nécessaire, la requête est transmise sans modification. Elle normalise la structure de la requête (ordre des blocs, empreinte, TTL) ; elle ne modifie pas votre conversation.
- Chaque transformation est un fichier dans
proxy/extensions/, lisible de manière isolée. - Évalué indépendamment comme un outil légitime par @TheAuditorTool (2026-04-14).
Le mode forward proxy (--remote-control) termine en plus le TLS pour api.anthropic.com à l'aide d'une autorité de certification (CA) générée localement, à laquelle votre client doit faire confiance. Tout le reste transite sans être inspecté. Ce mode est optionnel et désactivé par défaut.
Installez ou testez-le si : les sessions reprises ou de longue durée montrent des pics répétés de cache_creation_input_tokens ; votre ratio de lecture du cache est faible ou instable ; vous voyez des passages inattendus à un TTL de 5 min, des erreurs 400 de désynchronisation des blocs Thinking ou des boucles de nouvelles tentatives liées aux images ; ou si l'une des fonctionnalités sans rapport avec le cache décrites ci-dessous vous concerne.
Vous pouvez l'ignorer si : vos sessions maintiennent déjà un ratio de lecture du cache stable et élevé ; vous reprenez rarement des sessions longues ; vous n'êtes pas sous pression de quota ; ou vous préférez ne pas placer un proxy local dans le chemin API. Les quatre sont de bonnes raisons de ne pas installer ceci.
Si vous ne savez pas dans quel cas vous vous trouvez, mesurez-le — vous n'avez pas besoin de ce projet installé pour le découvrir.
Claude Code enregistre déjà la comptabilité du cache par requête dans ses propres transcriptions de session, vous pouvez donc mesurer la santé de votre cache maintenant, avant d'installer quoi que ce soit.
# Replace <session-uuid>, or use a glob to pick your most recent session.
jq -r 'select(.message.usage.cache_read_input_tokens != null) |
"\(.requestId)\t\(.message.usage.cache_read_input_tokens) \(.message.usage.cache_creation_input_tokens)"' \
~/.claude/projects/*/<session-uuid>.jsonl |
sort -u -k1,1 | cut -f2 |
awk '{n++; r+=$1; c+=$2}
END {if (n==0) print "no usage rows found — check the session path";
else printf "requests=%d cache_read=%d creation=%d read-ratio=%.0f%%\n", n, r, c, 100*r/(r+c)}'sort -u -k1,1 compte chaque appel API une seule fois — Claude Code écrit plusieurs lignes de transcription par requête, et pas toujours le même nombre de fois par requête (analyse d'ArkNill). La somme des lignes brutes pondère chaque appel par son propre nombre de duplicatas. Deux balayages indépendants des transcriptions locales sur une machine (2026-08-02) ont confirmé la tendance : les courtes sessions sont celles qui posent problème — plus de la moitié des sessions de moins de 20 requêtes ont décalé d'un point ou plus sans déduplication, pire cas 41 points, tandis que les longues sessions étaient presque toutes inférieures à un point (3 sur ~37).
Lecture du résultat :
- Moins de ~20 requêtes : le chiffre est sans signification. Un démarrage froid n'a rien à lire, donc la création domine et chaque session saine semble cassée. Utilisez une session longue ou reprise.
- Ratio faible et soutenu sur une longue session, ou
creationqui explose à chaque--resume— c'est le problème que ce projet existe pour résoudre. - Ratio élevé sur une longue session — vous n'en avez pas besoin. Voir En avez-vous besoin ? ci-dessus.
v4.0.0 — Proxy HTTP local avec un pipeline d'extensions dédiées à l'optimisation des coûts et à l'observabilité. Deux paramètres par défaut de longue date ont été inversés :
thinking-block-sanitizev1 est activé par défaut (atténue le blocage400de désynchronisation des blocs Thinking — #63147) et le rechargement à chaud des extensions dans le processus est optionnel (CACHE_FIX_HOT_RELOAD=on). Mesure de référence A/B (v3.0.0 sur v2.1.117) : 95,5 % de cache hits via le proxy, contre 82,3 % en accès direct au premier tour après warm-up. Notes de version complètes →
Avis Opus 4.7 : Les données mesurées montrent que 4.7 consomme le quota Q5h à un rythme environ 2,4 fois supérieur à celui de 4.6 à nombre de tokens visibles équivalent (confirmé indépendamment par @ArkNill). Deux facteurs : un nouveau tokenizer (jusqu'à 35 % de tokens en plus, documenté) et le surcoût de l'adaptive thinking (~105 %, non documenté dans la réponse d'utilisation). L'impact Q5h se cumule dans le Q7d — le plafond hebdomadaire que la plupart des utilisateurs intensifs atteindront en premier. Solution de contournement :
CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1réduit la consommation d'environ 3,3× mais peut réduire la qualité sur les tâches complexes. Voir Discussion #25 (observation initiale) et Discussion #42 (données A/B contrôlées + analyse Q7d).
Le proxy fonctionne avec toute version de CC — Node.js ou binaire Bun. Il se place entre Claude Code et l'API Anthropic, appliquant les corrections du cache sous forme d'extensions composables.
# Install
npm install -g claude-code-cache-fix
# Start the proxy (runs on localhost:9801)
node "$(npm root -g)/claude-code-cache-fix/proxy/server.mjs" &
# Launch Claude Code through it
ANTHROPIC_BASE_URL=http://127.0.0.1:9801 claudeC'est tout. Le proxy applique son pipeline d'extensions par défaut automatiquement. Pas de scripts d'encapsulation, pas de NODE_OPTIONS, pas de préchargement.
Le démarrage rapide ci-dessus utilise le mode reverse proxy : vous pointez ANTHROPIC_BASE_URL vers le proxy. C'est simple, mais sur Claude Code >= 2.1.196, un ANTHROPIC_BASE_URL non-Anthropic désactive Remote Control (/remote-control), /schedule et les connecteurs MCP de claude.ai (CC traite toute URL de base personnalisée comme une passerelle Bedrock/Vertex). Si vous dépendez de ces fonctionnalités, utilisez le mode forward proxy.
En mode forward proxy, le proxy se place devant le vrai api.anthropic.com en tant que HTTPS_PROXY. L'URL de base de Claude Code reste api.anthropic.com, donc Remote Control continue de fonctionner, tandis que le proxy voit et transforme toujours /v1/messages.
# Start the proxy in forward-proxy mode
CACHE_FIX_FORWARD_PROXY=on node "$(npm root -g)/claude-code-cache-fix/proxy/server.mjs" &
# It prints the two env vars to wire the client, e.g.:
# export HTTPS_PROXY=http://127.0.0.1:9801
# export NODE_EXTRA_CA_CERTS=~/.claude/cache-fix-ca/ca.pem
# Launch Claude Code through it (leave ANTHROPIC_BASE_URL UNSET)
HTTPS_PROXY=http://127.0.0.1:9801 \
NODE_EXTRA_CA_CERTS=~/.claude/cache-fix-ca/ca.pem \
claudeOu laissez le lanceur faire les deux étapes pour vous avec --remote-control :
# Spawns the proxy with CACHE_FIX_FORWARD_PROXY=on and wires the client
# (HTTPS_PROXY + the MITM CA, ANTHROPIC_BASE_URL left unset) automatically.
cache-fix-proxy --remote-controlL'option --remote-control est l'équivalent en une commande du câblage manuel ci-dessus : il démarre le proxy en mode forward, attend la CA, et lance claude pointé sur HTTPS_PROXY avec NODE_EXTRA_CA_CERTS défini (et ajoute 127.0.0.1,localhost,::1 à NO_PROXY pour que les services locaux — par ex. les serveurs MCP HTTP/SSE-transport sur localhost — contournent le proxy au lieu d'être routés vers lui ; tout NO_PROXY existant est préservé). Sans cette option, le lanceur reste en mode reverse proxy (définit ANTHROPIC_BASE_URL), inchangé.
Si vous câblez le mode forward proxy manuellement (en définissant
HTTPS_PROXYvous-même au lieu d'utiliser--remote-control), définissez aussiNO_PROXY=127.0.0.1,localhost,::1, sinon les serveurs MCP HTTP-transport locaux et autres services localhost seront routés vers le proxy cache-fix et échoueront.
Fonctionnement : le proxy gère aussi le HTTP CONNECT. Il MITM uniquement l'hôte amont (api.anthropic.com), terminant le TLS avec une CA générée localement pour pouvoir exécuter le même pipeline d'extensions, et fait transiter tous les autres tunnels CONNECT sans les inspecter (mcp-proxy, télémétrie, npm, ...). Au premier démarrage, il génère une CA sous $CLAUDE_CONFIG_DIR/cache-fix-ca/ (par défaut ~/.claude/cache-fix-ca/ ; surchargeable via CACHE_FIX_CA_DIR) ; le client doit lui faire confiance via NODE_EXTRA_CA_CERTS. Un WebSocket/Upgrade vers l'hôte amont (par ex. /voice) est relayé tel quel. Parce que l'URL de base reste api.anthropic.com, tout /api/oauth/*, /v1/agents, les récupérations d'identifiants Remote Control, etc. passent sans être touchés et RC reste activé.
Le chaînage avec un proxy d'entreprise fonctionne de la même manière qu'en mode reverse : définissez HTTPS_PROXY/HTTP_PROXY pour les connexions sortantes du proxy lui-même (le proxy compose api.anthropic.com à travers lui). Le HTTPS_PROXY du client pointe vers le proxy cache-fix ; le HTTPS_PROXY du proxy cache-fix (dans son propre env) pointe vers le proxy d'entreprise.
Sémantique de crash sur un proxy partagé. En mode forward proxy, le proxy MITM tout l'hôte amont, donc une session Claude Code en vol est câblée à ce port et ne peut pas basculer. Pour éviter qu'une mauvaise requête n'abatte le processus, une attache forward réussie installe des gestionnaires uncaughtException/unhandledRejection au niveau du processus qui journalisent et continuent de servir au lieu de crasher. Ceux-ci sont limités au mode forward (un proxy reverse seul garde la sémantique de crash par défaut de Node) et sont retirés quand la dernière instance forward se ferme. Le compromis : sur un proxy partagé / multi-tenant, activer le mode forward change le comportement de crash pour chaque client de cette instance tant que le mode est actif — une erreur fatale est avalée plutôt que remontée au superviseur.
Exécution persistante. Le ... node .../proxy/server.mjs & ci-dessus convient pour un essai rapide, mais un processus en arrière-plan n'est pas supervisé : il ne redémarre pas s'il crash ou si la machine redémarre. Pour exécuter le mode forward proxy en tant que service géré (redémarrage auto, démarrage à la connexion), utilisez le même chemin install-service décrit sous Exécution en tant que service — définissez simplement le flag à l'installation pour qu'il soit intégré dans l'unité :
CACHE_FIX_FORWARD_PROXY=on cache-fix-proxy install-serviceL'unité systemd générée / agent launchd porte CACHE_FIX_FORWARD_PROXY=on, donc le service démarre le proxy en mode forward et le maintient (systemd Restart=on-failure plus le timer de healthcheck ; launchd KeepAlive).
Le service ne gère que l'extrémité proxy. Il ne — et ne peut pas — définir quoi que ce soit sur votre client claude, qui est un processus séparé. Vous câblez toujours le client vous-même dans le shell qui lance claude, en utilisant les deux valeurs du quick-start forward-proxy ci-dessus :
HTTPS_PROXY— où le proxy écoute :http://127.0.0.1:<port>(port par défaut9801, ou votreCACHE_FIX_PROXY_PORT).NODE_EXTRA_CA_CERTS— la CA que le proxy a générée au premier démarrage :~/.claude/cache-fix-ca/ca.pem(ou$CACHE_FIX_CA_DIR/ca.pem).
Si autre chose sur cet hôte MITM aussi
api.anthropic.com— un agent d'inspection TLS d'entreprise, un proxy pin de changement de compte — n'utilisez pas ces recettes.NODE_EXTRA_CA_CERTSne prend qu'un fichier, donc l'épingler à notre seule CA désapprouve silencieusement tous les autres composants. Utilisez--remote-control, qui publie dansca-trust.d/et consomme le bundle fusionné à la place. Voir Coexistence avec un autre MITM.
# a) per-invocation — scoped to just this claude run
HTTPS_PROXY=http://127.0.0.1:9801 \
NODE_EXTRA_CA_CERTS=~/.claude/cache-fix-ca/ca.pem \
claude
# b) whole shell — add to ~/.zshrc / ~/.bashrc (every HTTPS in that shell goes
# through the proxy; harmless since non-anthropic hosts are blind-tunneled,
# but that shell's HTTPS breaks if the proxy is ever down)
export HTTPS_PROXY=http://127.0.0.1:9801
export NODE_EXTRA_CA_CERTS=~/.claude/cache-fix-ca/ca.pem
# c) scoped to claude only — a shell function (recommended; avoids b's blast radius)
claude() {
HTTPS_PROXY=http://127.0.0.1:9801 \
NODE_EXTRA_CA_CERTS=~/.claude/cache-fix-ca/ca.pem \
command claude "$@"
}NODE_EXTRA_CA_CERTS ne prend exactement qu'un fichier. Si autre chose sur l'hôte MITM aussi api.anthropic.com et définit aussi cette variable — un agent corporate, un proxy pin de changement de compte — le dernier écrivain gagne et chaque autre CA est silencieusement non approuvée. Mesuré le 2026-07-30 : deux composants de ce type sur une machine ont tour à tour cassé le TLS de l'autre.
Donc --remote-control n'assigne pas simplement la variable. Il :
- Publie notre CA dans
<config>/ca-trust.d/ccf.pem— uniquement notre propre nom de fichier, jamais celui d'un sibling, réécrit à chaque lancement. - Lit
<config>/ca-trust.pem— un bundle fusionné construit par exactement un écrivain externe à partir des racines ambiantes/corporate plus chaqueca-trust.d/*.pempublié — et pointeNODE_EXTRA_CA_CERTSdessus.
<config> est CLAUDE_CONFIG_DIR ou ~/.claude. Nous n'écrivons jamais le bundle fusionné : fusionner nécessite de trouver les racines corporate ambiantes, ce qui est spécifique à l'environnement.
Il s'agit d'une convention coopérative entre processus du même utilisateur, pas d'une frontière de confiance. La vérification prouve parse, et porte nous — jamais ne contient que des écrivains approuvés.
CACHE_FIX_DOWNLOAD_REWRITE=on semble être un simple bouton de performance. Ce n'en est pas un : l'activer désactive entièrement claude update sur cet hôte. Réécrire une URL de téléchargement signifie la lire, ce qui signifie MITM downloads.claude.ai — et le client du canal release épingle uniquement les racines publiques et rejette toute CA privée, donc la vérification de version meurt avant qu'un octet ne soit téléchargé :
Failed to fetch version from .../claude-code-releases/latest after 3 attempt(s):
unable to verify the first certificateMesuré avec openssl s_client -proxy 127.0.0.1:9901 -connect downloads.claude.ai:443 -servername downloads.claude.ai :
CACHE_FIX_DOWNLOAD_REWRITE |
leaf CN | verify |
|---|---|---|
on |
api.anthropic.com |
code 21 |
off |
downloads.claude.ai (WR3 / GTS Root R1) |
code 0 |
- Il ne peut pas être restreint au seul téléchargement binaire. Le MITM est décidé par hôte au moment du
CONNECT, et la vérification de version partagedownloads.claude.aiavec le téléchargement lui-même. - Aucun override côté client n'atteint ce client.
HTTPS_PROXY/ALL_PROXY,/etc/hosts,/etc/resolv.conf, etNODE_EXTRA_CA_CERTSont chacun été réfutés.
Les autres hôtes ne sont pas affectés : github.com à travers le même proxy retourne son vrai certificat et vérifie. Le flag est désactivé par défaut ; laissez-le ainsi.
À chaque requête /v1/messages, le pipeline exécute une chaîne ordonnée d'extensions couvrant la stabilité du cache, l'observabilité, l'atténuation thinking-desync, image, microcompact, breakpoint, canal bootstrap, et d'autres surfaces.
| Extension | Ce qu'elle corrige |
|---|---|
fingerprint-strip |
Supprime l'empreinte cc_version instable du prompt système |
sort-stabilization |
Ordre déterministe des définitions d'outils et MCP |
ttl-management |
Détecte le niveau TTL serveur, injecte les marqueurs cache_control corrects |
identity-normalization |
Normalise les champs d'identité des messages pour la stabilité du préfixe |
fresh-session-sort |
Corrige l'ordre non déterministe au premier tour |
cache-control-normalize |
Normalise les marqueurs cache_control entre messages |
cache-telemetry |
Extrait les stats de cache des en-têtes de réponse → ~/.claude/quota-status/{account.json,sessions/<id>.json} |
session-health |
Observe le risque thinking-desync par session et avertit avant la zone de danger. Lecture seule |
thinking-block-sanitize |
Supprime les blocs thinking omis (texte vide) pour éviter le 400 thinking-desync (#63147). Activé par défaut depuis v4.0.0 |
workflow-agent-id-synthesis |
Dérive un id d'agent stable par leg pour les sous-agents Workflow |
session-budget-breaker |
Plafond de dépenses dur par session opt-in — voir ci-dessous |
Les extensions vivent en fichiers .mjs dans proxy/extensions/ avec config dans proxy/extensions.json. Depuis v4.0.0 le proxy les charge une fois au démarrage.
Recommandé (Linux/macOS) — sous-commande install-service :
cache-fix-proxy install-serviceDétecte votre plateforme et écrit la configuration appropriée :
- Linux →
~/.config/systemd/user/cache-fix-proxy.service(unité utilisateur systemd) - macOS →
~/Library/LaunchAgents/com.cnighswonger.cache-fix-proxy.plist(agent launchd)
Sur Linux :
systemctl --user daemon-reload
systemctl --user enable --now cache-fix-proxy
systemctl --user enable --now cache-fix-proxy-healthcheck.timer # auto-recovery — see below
sudo loginctl enable-linger $USER # optional: start on boot, not just on loginSur macOS :
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.cnighswonger.cache-fix-proxy.plist
launchctl enable gui/$(id -u)/com.cnighswonger.cache-fix-proxy
launchctl kickstart gui/$(id -u)/com.cnighswonger.cache-fix-proxyManuel (toute plateforme) :
nohup cache-fix-proxy server > /tmp/cache-fix-proxy.log 2>&1 &
echo 'export ANTHROPIC_BASE_URL=http://127.0.0.1:9801' >> ~/.bashrcUne image conteneur multi-arch (amd64, arm64) est publiée sur GitHub Container Registry à chaque tag de version.
docker run -d --name cache-fix-proxy \
--restart=always \
-p 9801:9801 \
ghcr.io/cnighswonger/claude-code-cache-fix:latest
# Puis dans votre shell :
export ANTHROPIC_BASE_URL=http://127.0.0.1:9801Utilisez --restart=always au lieu du compagnon de vérification de santé systemd — Docker gère l'auto-récupération nativement.
Pour les environnements d'entreprise derrière un proxy inspectant SSL, montez votre bundle CA :
docker run -d --name cache-fix-proxy --restart=always -p 9801:9801 \
-e HTTPS_PROXY=http://proxy.corp.example:8080 \
-e CACHE_FIX_PROXY_CA_FILE=/etc/ssl/corp-ca.pem \
-v /path/to/zscaler-root.pem:/etc/ssl/corp-ca.pem:ro \
ghcr.io/cnighswonger/claude-code-cache-fix:latestTags d'image : latest, 4, 4.0, 4.0.0.
Note Linux : l'exemple host.docker.internal chaîné ci-dessous est automatique sur Docker Desktop (macOS/Windows). Sur Docker Engine Linux nu vous avez généralement besoin de --add-host=host.docker.internal:host-gateway :
docker run -d --name cache-fix-proxy --restart=always -p 9801:9801 \
--add-host=host.docker.internal:host-gateway \
-e CACHE_FIX_PROXY_UPSTREAM=http://host.docker.internal:8080 \
ghcr.io/cnighswonger/claude-code-cache-fix:latestMode forward proxy dans Docker (garde Remote Control). Ajoutez -e CACHE_FIX_FORWARD_PROXY=on et pointez CACHE_FIX_CA_DIR vers un chemin inscriptible :
mkdir -p ./cache-fix-ca && sudo chown 1000:1000 ./cache-fix-ca
docker run -d --name cache-fix-proxy --restart=always -p 9801:9801 \
-e CACHE_FIX_FORWARD_PROXY=on \
-e CACHE_FIX_CA_DIR=/ca -v "$PWD/cache-fix-ca:/ca" \
ghcr.io/cnighswonger/claude-code-cache-fix:latest
# La CA est maintenant à ./cache-fix-ca/ca.pem sur l'hôte. Pointez le client vers le
# proxy (laissez ANTHROPIC_BASE_URL non défini pour garder Remote Control actif) :
HTTPS_PROXY=http://127.0.0.1:9801 NODE_EXTRA_CA_CERTS=$PWD/cache-fix-ca/ca.pem claudecurl http://127.0.0.1:9801/health
# {"status":"ok"}Tous les paramètres du proxy sont contrôlés via des variables d'environnement.
| Variable | Défaut | Description |
|---|---|---|
CACHE_FIX_PROXY_PORT |
9801 |
Port d'écoute |
CACHE_FIX_PROXY_BIND |
127.0.0.1 |
Adresse de liaison |
CACHE_FIX_PROXY_UPSTREAM |
https://api.anthropic.com |
URL amont |
CACHE_FIX_FORWARD_PROXY |
non défini | Mettre à on pour le mode forward proxy |
CACHE_FIX_CA_DIR |
~/.claude/cache-fix-ca |
Répertoire pour la CA |
CACHE_FIX_PROXY_TIMEOUT |
600000 |
Délai d'expiration en ms |
CACHE_FIX_EXTENSIONS_DIR |
proxy/extensions/ |
Répertoire des extensions .mjs |
CACHE_FIX_EXTENSIONS_CONFIG |
proxy/extensions.json |
Fichier de config des extensions |
CACHE_FIX_DEBUG |
0 |
Activer le log de débogage |
CACHE_FIX_HOT_RELOAD |
non défini | Mettre à on pour le hot-reload in-process |
Le proxy respecte les variables suivantes lors du forwarding vers api.anthropic.com.
| Variable | Effet |
|---|---|
HTTPS_PROXY / HTTP_PROXY |
Route les requêtes amont via le proxy HTTP CONNECT corporate |
NO_PROXY |
Liste d'hôtes à contourner |
CACHE_FIX_PROXY_CA_FILE |
Chemin vers un PEM avec CA supplémentaires |
NODE_EXTRA_CA_CERTS |
Mécanisme Node standard — aussi respecté |
CACHE_FIX_PROXY_REJECT_UNAUTHORIZED=0 |
Échappatoire non sécurisée. Désactive la vérification TLS |
Exemple (Windows PowerShell) :
$env:HTTPS_PROXY = 'http://proxy.corp.example:8080'
$env:NO_PROXY = 'localhost,127.0.0.1,.corp.example'
$env:CACHE_FIX_PROXY_CA_FILE = 'C:\corp\zscaler-root.pem'
node "$(npm root -g)\claude-code-cache-fix\proxy\server.mjs"Si vous livrez un binaire Node ou Bun qui veut le proxy cache-fix in-process, importez la factory depuis claude-code-cache-fix/proxy/server :
import { startProxy } from "claude-code-cache-fix/proxy/server";
const handle = await startProxy({
port: 0, // port éphémère assigné par l'OS ; passez un nombre pour l'épingler
bind: "127.0.0.1",
watch: false, // saute fs.watch — recommandé pour binaires compilés
});
console.log(`proxy en écoute sur ${handle.address}:${handle.port}`);
// ...plus tard...
await handle.close();createProxyServer() → http.Server construit le handler de requête câblé dans un http.Server. Le serveur retourné n'écoute pas et le pipeline d'extensions n'a pas été chargé.
startProxy(options?) → Promise<{ server, port, address, close }> charge le pipeline d'extensions, démarre optionnellement le watcher, et commence à écouter.
La factory embarquable a été contribuée par @bilby91 chez Crunchloop DAP — voir PR #123.
Changements de comportement en v4.0.0 :
thinking-block-sanitizev1 est maintenant activé par défaut. Était opt-in viaCACHE_FIX_THINKING_SANITIZE=onen v3.8.0–v3.9.x. Après sept jours de prod dogfood sur 37 sessions (zérocannot be modified400s, hit-rate agrégé 94,66% vs 92,44% baseline), la v1 est le nouveau défaut.- Le hot-reload d'extensions in-process est maintenant désactivé par défaut. Était activé en v3.x. Mettez
CACHE_FIX_HOT_RELOAD=onpour restaurer le comportement précédent.
Note pour les intégrateurs (hôtes Bun, intégrations DAP utilisant createProxyServer() / startProxy())
v4.0.0 bascule CACHE_FIX_THINKING_SANITIZE de default-off à default-on. La v1 droppera chaque body de requête passant par le proxy embarqué. Si votre hôte dépend du comportement sans sanitization, préservez-le en mettant CACHE_FIX_THINKING_SANITIZE=off.
Votre unité systemd existante / plist launchd est inchangée ; seul le code proxy sur disque est mis à jour par npm. Redémarrez le processus en cours pour prendre le nouveau code.
Linux (systemd user unit) :
npm install -g claude-code-cache-fix@4
systemctl --user restart cache-fix-proxymacOS (launchd user agent) :
npm install -g claude-code-cache-fix@4
launchctl kickstart gui/$(id -u)/com.cnighswonger.cache-fix-proxyLinux :
CACHE_FIX_HOT_RELOAD=on cache-fix-proxy install-service
systemctl --user daemon-reload
systemctl --user restart cache-fix-proxymacOS :
CACHE_FIX_HOT_RELOAD=on cache-fix-proxy install-service
launchctl bootout gui/$(id -u)/com.cnighswonger.cache-fix-proxy
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.cnighswonger.cache-fix-proxy.plist
launchctl kickstart gui/$(id -u)/com.cnighswonger.cache-fix-proxyRégressions économiques du cache. Le but original de cache-fix est d'absorber les comportements de gestion du cache dans Claude Code qui coûtent de l'argent réel et du quota — rétrogradations TTL, churn d'en-têtes cassant le cache, problèmes de verrouillage d'identité, et le reste du catalogue documenté dans l'historique d'issues.
Observabilité du canal bootstrap. Claude Code v2.1.150 a introduit un consommateur de section prompt qui récupère une chaîne fournie serveur depuis /api/claude_cli/bootstrap et la fusionne dans le chemin prompt d'instructions comportementales de l'agent. Nous avons signalé ce comportement à l'équipe sécurité d'Anthropic en mai 2026 ; Anthropic a clos le rapport comme Informatif. Cache-fix a livré une gestion explicite pour ce chemin en v3.7.0 et l'a étendue en v3.7.1.
L'extension bootstrap-defense de cache-fix ship trois modes, sélectionnés via CACHE_FIX_BOOTSTRAP_MODE :
| Mode | Défaut ? | Comportement |
|---|---|---|
audit |
oui | Les réponses bootstrap passent vers CC. Chaque réponse est logguée dans ~/.claude/cache-fix-bootstrap-log.jsonl |
block |
opt-in | onRequest retourne 200 avec body JSON vide. Upstream jamais appelé |
allowlist |
opt-in (expérimental) | La réponse bootstrap passe, mais les clés éligibles prompt-source non dans allowlist sont strippées |
Certains comportements de Claude Code vivent sous la couche requête — ils se produisent côté client, dans le chemin dispatch des outils, avant que le proxy ne voie le trafic. cache-fix livre des scripts de hooks autonomes sous hooks/examples/.
| Script | Ce qu'il fait |
|---|---|
worktree-edit-guard.py |
Bloque les appels d'outils Edit/Write/MultiEdit/NotebookEdit dont le chemin cible sort du worktree git actif |
Scripts autonomes qui ne sont pas des extensions proxy ni des hooks CC — installables séparément.
| Outil | Ce qu'il fait |
|---|---|
tools/gh-auth-status-shim/ |
Wrapper gh PATH-résolu qui supprime le faux toast "GitHub CLI authentication expired" de CC Desktop |
Le proxy corrige ce qu'il peut au niveau requête. Quelques vars d'environnement côté client CC et knobs ~/.claude/settings.json résolvent des problèmes adjacents que le proxy ne peut pas atteindre.
{
"env": {
"CLAUDE_CODE_DISABLE_LEGACY_MODEL_REMAP": "1",
"ANTHROPIC_MODEL": "claude-opus-4-7",
"ANTHROPIC_SMALL_FAST_MODEL": "claude-haiku-4-5-20251001"
}
}CLAUDE_CODE_DISABLE_LEGACY_MODEL_REMAP=1 — flag le plus impactant. CC a un chemin legacy qui remap silencieusement votre modèle épinglé vers un autre après certaines mises à jour. Mettre à 1 désactive le remap.
ANTHROPIC_MODEL — épingle le modèle principal.
ANTHROPIC_SMALL_FAST_MODEL — épingle le modèle "rapide" secondaire.
Ce réglage ne prend effet que lorsque le modèle actif qualifie pour contexte 1M. Sans ces prérequis il plafonne à 200K codé en dur.
Si vous définissez ce flag, CC strippe tout champ d'outil hors de ["name", "description", "input_schema", "cache_control"] des requêtes sortantes. Les outils custom s'appuyant sur defer_loading ou eager_input_streaming perdront silencieusement ces champs.
Les commandes slash de diagnostic gonflent l'historique de conversation (#49335)
Exécuter /context, /release-notes ajoute la sortie diagnostic à l'historique de conversation plutôt que de rendre terminal-only. Les tours suivants rejouent le payload gonflé via prompt cache, composant le coût token. Mesuré empiriquement à +3 480 cache_creation_input_tokens pour une seule invocation /context sur v2.1.148.
Si vous êtes sur une version CC basée Node.js (v2.1.112 ou antérieure), l'intercepteur preload fonctionne sans proxy :
npm install -g claude-code-cache-fix
NODE_OPTIONS="--import claude-code-cache-fix" claudeVoir docs/preload-setup.md pour les scripts wrapper, alias shell, instructions Windows et intégration VS Code mode preload.
L'extension VS Code (v0.5.0) supporte les deux modes proxy et preload :
Mode proxy (recommandé) :
- Démarrez le proxy (voir ci-dessus)
- Dans la palette de commandes VS Code : Claude Code Cache Fix: Enable Proxy Mode
- Redémarrez toute session Claude Code active
Le proxy et l'intercepteur ont un accès complet en lecture/écriture aux requêtes et réponses API. Ceci est inhérent à l'approche.
Ce qu'il fait : Modifie la structure des requêtes sortantes (ordre des blocs, empreinte, TTL, git-status) pour corriger les bogues de cache. Lit les en-têtes de réponse et données d'utilisation SSE pour la surveillance.
Ce qu'il ne fait PAS : Aucun appel réseau depuis le proxy ou intercepteur. Toute télémétrie est écrite dans des fichiers locaux sous ~/.claude/. Aucune donnée ne quitte votre machine.
Audit indépendant : Évalué comme "OUTIL LÉGITIME" par @TheAuditorTool (2026-04-14).
Quand vous utilisez --resume ou /resume dans Claude Code, le prompt cache casse silencieusement. Au lieu de lire les tokens mis en cache (pas cher), l'API les reconstruit depuis zéro à chaque tour (cher). Une session qui devrait coûter ~$0.50/heure peut brûler $5–10/heure sans indication visible.
Trois bogues causent ceci :
- Dispersion partielle des blocs — Les blocs d'attachement sont censés vivre dans
messages[0]. À la reprise, certains ou tous dérivent vers des messages ultérieurs, changeant le préfixe de cache. - Instabilité d'empreinte — L'empreinte
cc_versionest calculée à partir du contenumessages[0]. Quand ces blocs bougent, l'empreinte change. - Ordre non déterministe des outils — Les définitions d'outils peuvent arriver dans des ordres différents entre tours.
Mode proxy (v3.0.0+) : Un serveur HTTP sur localhost:9801 intercepte les requêtes POST /v1/messages. Un pipeline de modules d'extension traite chaque requête.
Mode preload (v2.x) : Un module Node.js --import qui patch globalThis.fetch avant que Claude Code ne fasse des appels API.
Les deux modes sont idempotents.
Le paquet sert trois objectifs avec des cycles de vie différents :
| Objectif | Exemples | Quand désactiver |
|---|---|---|
| Corrections de bogues | Relocalisation de blocs, empreinte, tri d'outils, TTL | Quand CC corrige le bogue sous-jacent |
| Surveillance | Suivi quota, détection microcompact, flags GrowthBook | Garder indéfiniment |
| Optimisations | Stripping d'images, réécriture d'efficacité de sortie | Tant qu'elles aident votre flux |
Au premier appel API, l'intercepteur journalise une ligne d'état de santé (nécessite CACHE_FIX_DEBUG=1) :
cache-fix health: relocate=active(2h ago) fingerprint=dormant(5 clean sessions) tool_sort=active ttl=active identity=waitingSi le ratio cache_read tombe sous 50% sur 5+ appels après désactivation des corrections :
REGRESSION WARNING: cache_read ratio averaged 12% across last 5 calls.
Fixes are disabled — consider re-enabling to recover cache performance.Avant de réécrire l'empreinte cc_version, l'intercepteur vérifie que son sel codé en dur et ses indices de caractères reproduisent l'empreinte envoyée par Claude Code. Si la vérification échoue, la réécriture est automatiquement ignorée.
Chaque correction est conçue pour échouer vers une non-action :
- Si les regex de détection des blocs ne correspondent pas → les blocs ne sont pas relocalisés
- Si le format de l'empreinte change → l'empreinte n'est pas réécrite
- Si le tri des outils ne produit aucun changement → la charge passe non modifiée
Les deux modes écrivent l'état du quota à chaque appel API. Le mode proxy (v3.5.0+) se divise en ~/.claude/quota-status/account.json plus ~/.claude/quota-status/sessions/<id>.json. Le script tools/quota-statusline.sh inclus affiche une ligne de statut en direct montrant :
- Q5h barre de quota
[███░┃░░░░░]+ pourcentage +(exhaust X, reset Y) - Q7d même forme avec durées à l'échelle du jour
- Niveau TTL —
TTL:1hquand sain,TTL:5men rouge quand le serveur vous a rétrogradé - PEAK en jaune pendant les heures de pointe semaine
Exemple de ligne (milieu de fenêtre, état sain) :
Q5h [███░┃░░░░░] 30% (exhaust 4h40m, reset 3h00m) | Q7d [█████┃░░░░] 53% (exhaust 3d13h, reset 3d0h) | TTL:1h 98.3%mkdir -p ~/.claude/hooks
cp "$(npm root -g)/claude-code-cache-fix/tools/quota-statusline.sh" ~/.claude/hooks/
chmod +x ~/.claude/hooks/quota-statusline.shAjoutez à ~/.claude/settings.json :
{
"statusLine": {
"type": "command",
"command": "~/.claude/hooks/quota-statusline.sh"
}
}Quand le serveur rétrograde votre TTL à 5m (rétrogradation quota-aware à Q5h ≥ 100%), chaque idle plus long que 5 minutes cause une reconstruction complète du contexte. Sans la ligne de statut, ceci est invisible. Avec, l'avertissement rouge TTL:5m vous dit : arrêtez de travailler, attendez que la fenêtre Q5h se réinitialise, puis reprenez.
Claude Code injecte le git status live dans le prompt système à chaque appel. Toute édition de fichier change le git status, ce qui bust tout le cache préfixe. Désactiver ceci économise ~1 800 tokens par appel :
export CLAUDE_CODE_DISABLE_GIT_INSTRUCTIONS=1Si vous avez écrit une statusline custom, script de monitoring, ou autre chose qui lit ~/.claude/quota-status.json directement, cette section est pour vous. v3.5.0 a divisé ce fichier en mode proxy ; mode preload inchangé.
| v3.4.x et antérieur | v3.5.0+ mode proxy | v3.5.0+ mode preload | |
|---|---|---|---|
| Champs quota | ~/.claude/quota-status.json |
~/.claude/quota-status/account.json |
~/.claude/quota-status.json |
| Champs cache | même fichier | ~/.claude/quota-status/sessions/<filename>.json |
même fichier |
| Attribution multi-session | aucune — dernier écrivain gagne | fichiers par session | mono-session |
<filename> est dérivé de l'en-tête x-claude-code-session-id via règle safe-name déterministe.
Le ~/.claude/quota-status.json legacy est auto-supprimé à la première écriture mode proxy après mise à niveau.
Votre script doit essayer les chemins v3.5.0+ proxy d'abord et retomber sur le chemin legacy si non présent.
Bash (style statusline) :
QS_DIR="$HOME/.claude/quota-status"
ACCOUNT="$QS_DIR/account.json"
LEGACY="$HOME/.claude/quota-status.json"
# Règle de nom de fichier canonique — doit refléter proxy/extensions/cache-telemetry.mjs
# sessionFilename() : trim, puis "" → unknown, passe-plat regex sûr, sinon
# inv-<sha256-prefix>. Sans ceci, les ids malformés ou avec whitespace ratent
# le fichier per-session même si l'écrivain l'a créé sous le nom canonique.
session_filename() {
local trimmed
trimmed="$(printf '%s' "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
if [ -z "$trimmed" ]; then echo unknown; return; fi
if printf '%s' "$trimmed" | grep -qE '^[A-Za-z0-9_-]{1,128}$'; then
printf '%s' "$trimmed"
else
# sha256sum sur Linux ; shasum -a 256 sur macOS. Les deux émettent "<hex> -".
local hash
if command -v sha256sum >/dev/null 2>&1; then
hash="$(printf '%s' "$trimmed" | sha256sum)"
else
hash="$(printf '%s' "$trimmed" | shasum -a 256)"
fi
printf 'inv-%s' "$(printf '%s' "$hash" | cut -c1-16)"
fi
}
# session id : préfère stdin CC, retombe sur le jsonl le plus récent
sid="$(jq -r '.session_id // empty' 2>/dev/null < /dev/stdin || true)"
if [ -z "$sid" ]; then
sid="$(ls -t "$HOME"/.claude/projects/*/*.jsonl 2>/dev/null | head -1 | xargs -I{} basename {} .jsonl)"
fi
filename="$(session_filename "$sid")"
# quota : account.json (v3.5.0+) → retombe sur legacy
if [ -f "$ACCOUNT" ]; then
quota_json="$(cat "$ACCOUNT")"
elif [ -f "$LEGACY" ]; then
quota_json="$(cat "$LEGACY")"
fi
# cache : sessions/<filename>.json (v3.5.0+) → retombe sur legacy
if [ -f "$QS_DIR/sessions/$filename.json" ]; then
cache_json="$(cat "$QS_DIR/sessions/$filename.json")"
elif [ -f "$LEGACY" ]; then
cache_json="$(cat "$LEGACY")"
fiNode :
import { readFileSync, existsSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
import { createHash } from "node:crypto";
const home = homedir();
const accountPath = join(home, ".claude", "quota-status", "account.json");
const legacyPath = join(home, ".claude", "quota-status.json");
const SAFE_NAME_RE = /^[A-Za-z0-9_-]{1,128}$/;
// Miroir de sessionFilename() de cache-telemetry.mjs. La règle côté lecteur doit
// correspondre à la règle côté écrivain ; sinon les ids malformés/avec whitespace
// ratent leur fichier per-session.
function sessionFilename(rawId) {
if (rawId === null || rawId === undefined) return "unknown";
const s = String(rawId).trim();
if (s.length === 0) return "unknown";
if (SAFE_NAME_RE.test(s)) return s;
return "inv-" + createHash("sha256").update(s).digest("hex").slice(0, 16);
}
function readQuotaJson() {
if (existsSync(accountPath)) return JSON.parse(readFileSync(accountPath, "utf8"));
if (existsSync(legacyPath)) return JSON.parse(readFileSync(legacyPath, "utf8"));
return null;
}
function readCacheJson(sessionId) {
const filename = sessionFilename(sessionId);
const p = join(home, ".claude", "quota-status", "sessions", `${filename}.json`);
if (existsSync(p)) return JSON.parse(readFileSync(p, "utf8"));
if (existsSync(legacyPath)) return JSON.parse(readFileSync(legacyPath, "utf8"));
return null;
}Sur les hôtes multi-agent, le fichier global unique pré-v3.5.0 faisait que chaque session écrasait les stats cache des autres à chaque réponse.
Claude Code lit CLAUDE_CONFIG_DIR pour relocaliser sa racine config loin du défaut ~/.claude. Le proxy honore maintenant la même variable pour tout son état on-disk.
Les images lues via l'outil Read persistent en base64 dans l'historique de conversation. Une seule image 500 Ko coûte ~62 500 tokens par tour sur Opus 4.6, et ~85 000+ sur Opus 4.7.
export CACHE_FIX_IMAGE_KEEP_LAST=3export CACHE_FIX_IMAGE_MAX_DIM=2000| Pression | Variable | Ce qu'elle fait |
|---|---|---|
| Trop d'images en conversation | CACHE_FIX_IMAGE_KEEP_LAST=N |
Strippe les images des vieux messages utilisateur |
| Une seule image trop grande | CACHE_FIX_IMAGE_MAX_DIM=2000 |
Remplace les images dépassant la limite par placeholder |
Pipeline conditionnel qui reflète les vraies règles d'Anthropic. Strictement opt-in via une seule env var :
export CACHE_FIX_IMAGE_GUARD=1| Pass | Déclencheur | Action |
|---|---|---|
| Pass 0 (legacy) | CACHE_FIX_IMAGE_KEEP_LAST=N défini |
Strippe les images tool_result des messages utilisateur plus vieux que N |
| Pass 3 | CACHE_FIX_IMAGE_PRESERVE_DETAIL=1 ET long edge image > cap natif |
Resize Lanczos via sharp |
| Pass 1 | long edge image > cap de rejet actif | Strippe et remplace |
| Pass 2 | body requête dépasse CACHE_FIX_IMAGE_REQUEST_SIZE_MAX |
Droppe les plus vieilles |
| Count cap | count images survivantes > cap | Droppe les plus vieilles |
Le Pass 3 nécessite sharp pour resize Lanczos.
npm install sharp| Combinaison Env var | Comportement |
|---|---|
| Rien défini | Pas de traitement image |
KEEP_LAST=N seul |
Comportement v3.2.1 count cap |
MAX_DIM=N seul |
Comportement v3.2.1 hard size cap |
KEEP_LAST=N + MAX_DIM=N |
Composition v3.2.1 |
IMAGE_GUARD=1 |
Nouveau pipeline |
IMAGE_GUARD=1 + MAX_DIM=N |
MAX_DIM override Pass 1 |
IMAGE_GUARD=1 + PRESERVE_DETAIL=1 |
Ajoute Pass 3 |
IMAGE_GUARD=1 + KEEP_LAST=N |
KEEP_LAST d'abord |
PRESERVE_DETAIL=1 sans IMAGE_GUARD=1 |
Log warning, no-op |
| Env var | Défaut | But |
|---|---|---|
CACHE_FIX_IMAGE_GUARD |
non défini | Gate pipeline top-level |
CACHE_FIX_IMAGE_PRESERVE_DETAIL |
non défini | Active Pass 3 resize |
CACHE_FIX_IMAGE_REQUEST_SIZE_MAX |
31457280 (30 MB) | Budget octets Pass 2 |
CACHE_FIX_IMAGE_COUNT_MAX |
100 | Cap dur count images |
Quand CC rencontre une erreur permanente "image could not be processed", le harness la traite actuellement comme transitoire et retente — avec contexte conversation complet et même payload image 34 Mo — jusqu'à ~19 fois par anthropics/claude-code#66815. Une seule mauvaise image peut consommer ~60% de l'enveloppe quota 5-heure.
Le disjoncteur surveille chaque réponse route messages. Quand upstream retourne une erreur permanente de traitement d'image, il enregistre la failure.
Opt-in via env var ; default-off :
export CACHE_FIX_IMAGE_RETRY_BREAKER=on| Mode | Comportement |
|---|---|
on |
Détecte + enregistre + court-circuite |
off (défaut) |
Pass-through |
dry-run |
Détecte + enregistre + log, mais ne court-circuite pas |
Un plafond de dépenses dur par session opt-in. Une fois que la consommation token cumulative d'une session CC dépasse une limite que vous définissez, les futurs /v1/messages pour cette session sont court-circuités localement — ils n'atteignent jamais Anthropic.
Opt-in via la gate ; default-off :
export CACHE_FIX_SESSION_BUDGET=on
export CACHE_FIX_SESSION_BUDGET_COST_USD=25 # p.ex. stop la session à ~$25| Mode | Comportement |
|---|---|
on |
Tally par session ; court-circuite la prochaine requête une fois au-dessus d'un plafond |
off (défaut) |
Pass-through |
dry-run |
Tally + log would_block |
| Env var | Défaut | But |
|---|---|---|
CACHE_FIX_SESSION_BUDGET |
off |
Gate — on / off / dry-run |
CACHE_FIX_SESSION_BUDGET_TOKENS |
non défini | Stop dur quand tokens cumulatifs traversent cet entier |
CACHE_FIX_SESSION_BUDGET_COST_USD |
non défini | Stop dur quand coût estimé traverse ce float |
CACHE_FIX_SESSION_BUDGET_RATE_TPM |
non défini | Stop dur quand tokens/min traversent cet entier |
CACHE_FIX_SESSION_BUDGET_RATE_WINDOW_MS |
60000 | Fenêtre glissante pour levier rate |
CACHE_FIX_SESSION_BUDGET_MAX_ENTRIES |
4096 | Cap LRU |
CACHE_FIX_SESSION_BUDGET_EVENT_LOG |
~/.claude/session-budget-events.jsonl |
Chemin log |
- Abonnement (OAuth, ex. Max) — cas #68285. Utilisez
_TOKENSou_RATE_TPM. - Clé API directe (pay-as-you-go) — cas plus sévère. Il n'y a pas de buffer quota. Ici
_COST_USDest un plafond dollar littéral.
Le coût est une estimation — pairez-le avec un cap token pour une borne dollar garantie.
Si la comptabilité est incertaine — gate off, pas de plafond défini, usage manquant, pas de clé session, modèle inconnu à rates.json, première requête après restart, ou quoi que ce soit throw — la requête forward.
Une requête court-circuitée retourne avant tout appel upstream, donc elle ne produit aucune ligne usage.jsonl. Le seul signal fire est le log JSONL.
- Dépassement concurrence. Un large fan-out tire quasi-simultanément, donc un plafond cumulatif pur dépasse d'environ ce batch.
_RATE_TPMatténue. - Coût sortie est post-hoc — le tally gate la prochaine requête.
- Restart remet le tally à zéro — in-memory.
- Par session, pas par compte.
Certains canaux de distribution Claude Code — notamment l'extension VS Code sous auto-update — émettent une valeur cc_version dans le x-anthropic-billing-header qui inclut un hash per-build au-dessus de MAJOR.MINOR.PATCH.
L'existant fingerprint-strip ne couvre PAS ce cas.
Opt-in via env var ; default-off :
export CACHE_FIX_NORMALIZE_CC_VERSION=strip # collapse X.Y.Z.<suffix> → X.Y.Z
# ou
export CACHE_FIX_NORMALIZE_CC_VERSION=pin:2.1.185 # littéral fourni par l'opérateurUn backup ceinture-et-bretelles contre les régressions transcript CC par [anthropics/claude-code#66734] et [anthropics/claude-code#66486]. Quand le proxy est dans le chemin, chaque message assistant + tool result observé / input utilisateur est miroiré dans un fichier JSONL par session sous contrôle utilisateur.
Opt-in via env var ; default-off :
export CACHE_FIX_SESSION_MIRROR=onLe prompt cache d'Anthropic supporte jusqu'à quatre marqueurs cache_control par requête. Claude Code utilise actuellement trois sur quatre ; le troisième (entre contenu auto-injecté messages[0] et le premier vrai contenu utilisateur) manque entièrement.
Le proxy peut injecter le marqueur manquant en opt-in.
export CACHE_FIX_INJECT_MESSAGES_BREAKPOINT=1L'injection est conservatrice : elle ne tire que quand la requête porte déjà 1–3 marqueurs.
Une env var diagnostic-only dump la forme structurelle de messages[0] :
export CACHE_FIX_DUMP_MESSAGES_HEAD=/tmp/messages-head.jsonlAprès ~90 minutes idle, le time_based_microcompact de Claude Code remplace l'ancien contenu tool_result par une chaîne sentinelle. Le contenu original est perdu ; cette partie est irrécupérable depuis le proxy. Mais la sentinelle elle-même peut porter un timestamp embarqué, ce qui signifie qu'un second passage microcompact écrit des octets différents.
Cette extension adresse la moitié récupérable : normaliser la sentinelle vers une forme canonique stable.
# Étape 1 (diagnostic) : dump les sentinelles détectées vers un JSONL pour observation.
export CACHE_FIX_DUMP_MICROCOMPACT=/tmp/microcompact-dump.jsonl
# Étape 2 (normalisation) : une fois le format de sentinelle confirmé, opt-in.
export CACHE_FIX_NORMALIZE_MICROCOMPACT=1Sur Opus 4.7, Anthropic a inversé la valeur par défaut API pour thinking.display de "summarized" à "omitted". Cette extension est le complément côté proxy : quand une requête vers un endpoint Opus 4.7 a thinking activé mais display non défini, injecte le mode configuré à la frontière API.
# Restaure les résumés (le défaut intégré — surfaces non-interactives obtiennent le contenu du raisonnement)
export CACHE_FIX_THINKING_DISPLAY=summarized
# Suppression forcée (runtimes d'agent qui ne veulent pas de blocs thinking du tout)
export CACHE_FIX_THINKING_DISPLAY=omitted
# No-op explicite (l'extension passe-through inchangée)
export CACHE_FIX_THINKING_DISPLAY=disabledL'extension est activée par défaut depuis v3.6.1. Le test cache-prefix a mesuré 0% de baisse absolue du ratio cache_read en état stable quand l'injection est active sur Opus 4.7.
Les sessions Opus 4.7 [1m] de longue durée accumulent des blocs thinking entrelacés et font croître leur contexte live jusqu'à ce que la reconstruction d'historique propre de Claude Code désynchronise une signature de bloc thinking, produisant un 400 … thinking blocks … cannot be modified permanent à chaque tour suivant.
L'extension session-health observe les conditions qui corrèlent avec le trip et avertit avant qu'une session n'atteigne la zone de danger.
| Env var | Défaut | But |
|---|---|---|
CACHE_FIX_THINKING_RISK_WARN_TOKENS |
250000 |
Niveau token contexte auquel risque devient warn |
CACHE_FIX_THINKING_RISK_HIGH_TOKENS |
340000 |
Niveau auquel risque devient high |
CACHE_FIX_THINKING_RISK |
non défini (on) | Mettre à off pour supprimer le signal warning |
Sur les chemins rejeu d'historique (resume / --continue / auto-compaction / annulation outil parallèle), Claude Code renvoie les tours assistant antérieurs en forme omise { "type":"thinking", "thinking":"", "signature":"<intact>" }. L'API rejette le thinking modifié dans le dernier message assistant avec un 400 permanent, ce qui coince la session à chaque tour suivant.
L'extension thinking-block-sanitize droppe ces blocs omis.
Activé par défaut depuis v4.0.0.
| Env var | Défaut | But |
|---|---|---|
CACHE_FIX_THINKING_SANITIZE |
non défini (= v1) | v4.0.0+ : drop bloc omis v1 est le défaut. Mettre à off pour désactiver. Mettre à v2 pour drop tools-hash-mismatch |
L'intercepteur peut réécrire la section # Output efficiency du prompt système de Claude Code. Désactivé par défaut. Activez avec CACHE_FIX_OUTPUT_EFFICIENCY_REPLACEMENT.
L'intercepteur de préchargement inclut la surveillance de la dégradation microcompact, des faux limiteurs de débit, de l'état des feature flags GrowthBook, de la télémétrie d'usage et des rapports de coûts.
L'extension usage-log (opt-in via proxy/extensions.json) ajoute une ligne JSON par réponse API à ~/.claude/usage.jsonl. La forme de ligne est MeterRowSchema v:1.
| Champ | Type | Source |
|---|---|---|
v |
littéral 1 |
constante |
ts |
datetime ISO-8601 | heure serveur |
sid |
hex 8-char | id session proxy |
model |
string ≤64 | message_start.message.model |
request_id |
string ≤64 (optionnel) | en-tête réponse upstream request-id. Default-on depuis v4.2.0 |
Pourquoi request_id compte opérationnellement. Le champ sid est généré une fois au démarrage du proxy et partagé entre chaque session CC servie par ce proxy. Sur les hôtes qui font tourner plusieurs sessions CC concurrentes via un seul proxy, toutes les lignes s'effondrent sur le même sid. Les transcripts CC par session à ~/.claude/projects/<project>/<session-uuid>.jsonl portent déjà requestId pour chaque appel API. Capturer la même valeur dans la ligne meter rend la jointure post-hoc triviale :
# Trouve à quelle session CC appartient chaque ligne usage.jsonl :
for row in $(jq -c . < ~/.claude/usage.jsonl); do
req=$(jq -r '.request_id // empty' <<< "$row")
[ -z "$req" ] && continue
grep -l "\"requestId\":\"$req\"" ~/.claude/projects/*/*.jsonl
doneLe nom de fichier du transcript correspondant est l'UUID de la session CC, récupérant l'attribution par session pour chaque ligne meter émise avec le champ activé.
L'extension usage-log ci-dessus n'enregistre que les réponses réussies (200). Les non-200 (429 throttling capacité, erreurs 5xx) ne laissent qu'une ligne non structurée.
upstream-error-log (opt-in, nouveau en v4.2.0) émet un record structuré pour chaque status >= 400 vers ~/.claude/usage-log/upstream-errors.jsonl.
Opt-in via env var ; default-off :
export CACHE_FIX_UPSTREAM_ERROR_LOG=onSous-système default-off qui fait du proxy cache-fix le seul, proactif, lock-coopératif, rafraîchisseur du credential OAuth à ~/.claude/.credentials.json. Ferme la race rotation refresh-token qui peut révoquer toute la famille token et 401 chaque client Claude Code concurrent.
Opt-in via env var ; default-off :
export CACHE_FIX_OAUTH_REFRESH=on| Env var | Défaut | But |
|---|---|---|
CACHE_FIX_OAUTH_REFRESH |
off |
Gate maître |
CACHE_FIX_OAUTH_CRED_PATH |
~/.claude/.credentials.json |
Chemin fichier credential |
CACHE_FIX_OAUTH_TOKEN_URL |
https://platform.claude.com/v1/oauth/token |
Endpoint token |
CACHE_FIX_OAUTH_REFRESH_MARGIN_MS |
7200000 (2h) | Rafraîchit quand expiry est dans cette fenêtre |
CACHE_FIX_OAUTH_TICK_MS |
300000 (5min) | Intervalle vérification |
CACHE_FIX_OAUTH_POST_TIMEOUT_MS |
8000 | Deadline POST refresh hard |
- Vous opérez déjà une gateway ou proxy de cache dans le chemin de requête.
- Vous avez besoin de sémantique crash-to-supervisor. En mode forward-proxy, le proxy installe des handlers
uncaughtException/unhandledRejectionprocess-wide. - Vos sessions sont courtes et froides. La valeur du proxy se concentre sur les sessions reprises et longue durée.
- Le proxy nécessite un processus en cours d'exécution — Le proxy doit être démarré avant Claude Code.
- Rétrogradation TTL overage — Dépasser 100% du quota 5-heure déclenche une rétrogradation TTL imposée serveur de 1h à 5m.
- Microcompact n'est pas évitable — Les fonctionnalités de surveillance détectent la dégradation contexte mais ne peuvent pas la prévenir.
- La réécriture du prompt système est expérimentale — Preload-only, opt-in.
- Couplage de version — Le sel d'empreinte et les heuristiques de détection de blocs sont dérivés des internals Claude Code.
- @ArkNill/claude-code-hidden-problem-analysis — Analyse basée sur 38 996 requêtes via proxy : 7 bogues, test causal feature flag GrowthBook, advisory taux consommation Opus 4.7.
- @Renvect/X-Ray-Claude-Code-Interceptor — Proxy HTTPS de diagnostic avec tableau de bord temps réel.
- @fgrosswig/claude-usage-dashboard — Tableau de bord forensique auto-hébergé.
- Crunchloop DAP — Environnement de développement Agent SDK / DAP. Première équipe de production à merger l'intercepteur sur trunk.
- VM Farms (@vmfarms) — Environnement développement agents exécutant workloads multi-runners concurrents.
- @VictorSun92 — Fix monkey-patch original pour v2.1.88
- @bilby91 (Crunchloop DAP) — Validation environnement production Agent SDK / DAP, factory proxy embarquable
- @jmarianski — Analyse cause racine via capture proxy MITM et rétro-ingénierie Ghidra
- @cnighswonger — Stabilisation empreinte, correction tri outils, stripping images, fonctionnalités surveillance, architecture proxy, mainteneur paquet
- @ArkNill — Analyse mécanisme microcompact, documentation feature flags GrowthBook, README coréen
- @Renvect — Découverte duplication images
- @fgrosswig — Méthodologie tableau de bord usage Claude
- @TomTheMenace — Wrapper
.batWindows - @deafsquad — Fix universel smoosh_split un-smoosh, architecture proxy
- @codeslake — Mode forward proxy opt-in, respect de
CLAUDE_CONFIG_DIR, rendez-vousca-trust.d - @Gunther-Schulz — Série attribution :
capture,prefix-diff,insertion-normalization,deferred-tool-rewrite,output-guard - @thepiper18 — Traduction originale en portugais brésilien
Si vous avez contribué à l'effort communautaire sur ces problèmes et n'êtes pas listé ici, veuillez ouvrir une issue ou PR.
Si cet outil vous a fait économiser de l'argent, envisagez de m'offrir un café :
