← Claude Code Hub
✦ Tip #199 Sep 16, 2026

prompt_cache en Claude Code: mira si tu caché se ha enfriado antes de escribir

Te levantas a por un café y, al volver, el primer mensaje que escribes reprocesa la conversación entera. Tu status line puede avisarte antes, en el segundo exacto en que la caché muere.

Una línea de tiempo: escribiendo con la barra en verde al 98 por ciento, te levantas, y en el punto expires_at la barra se repinta en ámbar avisando de 461k tokens al escribir

TL;DR El JSON que recibe tu status line trae un objeto prompt_cache con warm, ttl, expires_at y recache_tokens_if_cold. Con una docena de líneas de jq la barra se repinta sola en el segundo exacto en que tu caché muere, y te dice cuántos tokens vas a recachear si escribes.

Te levantas a por un café. Vuelves, escribes lo primero que se te ocurre y ese turno reprocesa la conversación entera a precio completo. No te ha avisado nadie, y encima lo pagas sin enterarte de que lo has pagado.

La línea de /cost te lo cuenta, pero después y solo si abres la pantalla. La status line lo puede contar antes, y hay una línea en la documentación que explica por qué: Claude Code vuelve a ejecutar tu script cuando una caché caliente llega a su expires_at. Sabe cuándo va a morir y despierta a tu barra en ese instante.

Lo que viaja en el JSON

Esto es lo que recibió mi propia status line hace un rato, sin retocar:

"prompt_cache": {
  "warm": true,
  "caching_observed": true,
  "ttl": "1h",
  "expires_at": 1789595743,
  "requests": 238,
  "misses": 1,
  "expected_rebuilds": 1,
  "hit_ratio": 0.9838970255083798,
  "cache_write_tokens": 1207215,
  "miss_recache_tokens": 340839,
  "last_miss_at": 1789590652,
  "last_miss_cause": { "causes": ["ttl_expired_1h"] },
  "miss_causes": { "ttl_expired_1h": 1 },
  "recache_tokens_if_cold": 461120
}

Fíjate en el fallo. Uno solo en 238 peticiones, y su causa es ttl_expired_1h: exactamente lo que cuenta este tip, la caché que expira mientras no miras. Me pasó veinticinco minutos antes de capturar esto y no me enteré, porque mi barra todavía no lo pintaba.

Y fíjate en el último campo, que es el que no puedes ver en ningún otro sitio. recache_tokens_if_cold son 461.120 tokens: lo que va a reprocesar mi siguiente mensaje si para entonces la caché ya se ha enfriado. No es una métrica, es el precio de escribir.

El segmento

Va dentro del script que ya tengas. Si todavía no tienes ninguno, monta primero la status line y vuelve aquí.

if [ "$(echo "$input" | jq '.prompt_cache != null')" = "true" ]; then
  WARM=$(echo "$input" | jq -r '.prompt_cache.warm')
  PCT=$(echo "$input" | jq -r '(.prompt_cache.hit_ratio // 0) * 100 | floor')
  TTL=$(echo "$input" | jq -r '.prompt_cache.ttl // "?"')
  COLD=$(echo "$input" | jq -r '(.prompt_cache.recache_tokens_if_cold // 0) / 1000 | floor')

  if [ "$WARM" = "true" ]; then
    CACHE="${GREEN}●${RST} ${DIM}caché${RST} ${PCT}% ${DIM}${TTL}${RST}"
  else
    CACHE="${YELLOW}▲ caché fría · +${COLD}k al escribir${RST}"
  fi
fi

Dos estados, y esto es lo que imprime con el JSON de arriba:

● caché 98% 1h
▲ caché fría · +461k al escribir

Esa primera comprobación no sobra. El objeto no existe hasta la primera respuesta de la API: lo verifiqué capturando el JSON de una sesión recién abierta y ahí la clave prompt_cache directamente no está. Sin la guarda, el segmento se pinta en ámbar con un +0k antes de que tú hayas escrito nada.

No es una cuenta atrás, y eso es lo bueno

La status line no tiene reloj: corre por eventos. Estos:

  • llega un mensaje nuevo del asistente
  • termina un /compact
  • cambias de modo de permisos o de modo vim
  • cambias el command de tus settings
  • una ventana de rate limit llega a su resets_at
  • una caché caliente llega a su expires_at

Ese último es el que hace el trabajo. Mientras escribes, la barra está en verde porque se repinta con cada respuesta. Te vas, y en el segundo en que la caché expira Claude Code lanza tu script una vez más y la barra se pone en ámbar sola, con la sesión parada y sin que tú hagas nada. Vuelves, miras abajo y ya sabes si teclear sale caro.

Si de verdad quieres la cuenta atrás, es otra cosa y la pides tú: añade refreshInterval a tu statusLine y el script corre también cada N segundos, con lo que puedes pintar los minutos que le quedan a expires_at.

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh",
    "refreshInterval": 30
  }
}

El mínimo es 1 segundo. Y no te preocupes por el gasto: la status line corre en local y no consume tokens de API, lo dicen las propias docs.

Referencia: los campos que vas a usar

Campo Qué es Para qué lo pintas
warm Si el prefijo cacheado sigue dentro de su TTL El semáforo
ttl "5m" o "1h" Saber cuánto margen tienes
expires_at Cuándo se enfría, en epoch La cuenta atrás, con refreshInterval
recache_tokens_if_cold Lo que recachea tu próximo mensaje si ya está fría El precio de escribir
hit_ratio Tokens leídos de caché sobre la entrada total La salud de la sesión
misses · miss_causes Fallos y su causa, por nombre Ver si se repite el mismo culpable

Los trece campos y su letra pequeña están en las docs. Estas seis filas son las que caben en una barra.

Ese ttl merece un vistazo antes de montar nada, porque la hora entera no la tiene todo el mundo: en la conversación principal son sesenta minutos mientras estés dentro del uso incluido de tu plan, y cinco en cuanto pasas a usage credits o tiras de API key. Con cinco, cualquier interrupción te devuelve en frío, que es justo por lo que conviene compactar antes de levantarte y no al volver.

Con esto la barra te dice tres cosas de un vistazo: si la caché está viva, si tu sesión la está aprovechando y cuánto cuesta el siguiente mensaje. El resto del mecanismo, qué es exactamente lo que se cachea y qué lo rompe, y si prefieres el número a demanda en vez de siempre puesto, la línea de /cost. En ese mismo JSON viaja también el porcentaje de límite consumido, que es el otro vecino que merece un hueco en la barra.

Documentación oficial: Status line: prompt cache fields

Requisitos

  • Claude Code v2.1.251 o superior para el objeto prompt_cache. El last_miss_cause y el miss_causes necesitan la v2.1.260.
  • jq para el snippet. El JSON de arriba es una captura real de mi sesión en la v2.1.270, y la salida de los dos estados está ejecutada contra ese mismo JSON.
  • El objeto cuenta solo la conversación principal. Lo que gasten tus subagentes no entra.
Guía gratuita

Los 51 esenciales, en una guía.

Una página por tip. Cinco capítulos. Lo que de verdad uso a diario en producción. Sin teoría, sin humo.

  • I. Empieza bien 10 tips
  • II. Conciencia 3 tips
  • III. Maestría 22 tips
  • IV. Autonomía 10 tips
  • V. Comparativa 6 tips
¿Eres desarrollador/a Web profesional?

Recibirás la guía por email · Te unes a la newsletter Gravitas · Cancela cuando quieras

de 51
#

Wmedia · 51 Tips
Guía gratuita · 51 tips · 5 capítulos

Los 51 esenciales, en una guía.

¿Eres desarrollador/a Web profesional? · Cancela cuando quieras
Workshop para equipos

Multiplica el output de tu equipo sin sacrificar calidad: workshop AI First de 6 a 8 horas, online, sobre la plataforma Claude.

Ver el workshop

¿Quieres los 51 esenciales de Claude Code en una guía?