English · 简体中文 · 日本語 · 한국어 · Français · فارسی
Claude Code comprime automáticamente las sesiones largas: borra la mayor parte de tu conversación, la sustituye por un resumen y sigue adelante. Normalmente te das cuenta porque el modelo empieza a preguntar de nuevo cosas que quedaron zanjadas dos horas antes.
Este repositorio toma el camino opuesto. Mide cuán llena está realmente la sesión y, cuando el final está genuinamente cerca, exporta la sesión completa a disco y continúa en una nueva que lee la transcripción del padre por entero antes de hacer nada más. Nada se pierde en un resumen, y la cadena de sesiones queda visible y recuperable.
También diagnostica una trampa de configuración que vale la pena conocer aunque no instales nada de esto: consulta El recorte.
Requiere Python 3.8+ y Claude Code. Nada más; no hay dependencias que instalar.
git clone https://github.com/IRDcode/claude-code-session-handoff
cd claude-code-session-handoff
python install.py --dry-run # ver todos los cambios primero
python install.pyLuego reinicia Claude Code y comprueba qué ha detectado:
python ~/.claude/skills/long-session-handoff/scripts/session_weight.py --explainLa instalación por defecto no cambia cómo Claude Code gestiona el contexto. La compactación automática se queda tal cual; el guardián simplemente hace el relevo antes de que pueda dispararse. Para quitarlo todo:
python install.py --uninstallsettings.json se respalda antes de tocarlo, tus hooks y tu línea de estado
existentes se dejan intactos, e instalar dos veces no hace nada.
| ruta | qué es |
|---|---|
~/.claude/skills/long-session-handoff/ |
el procedimiento que sigue el modelo, más tres scripts |
~/.claude/hooks/session-weight-watch.py |
el detector, en cuatro eventos |
~/.claude/hooks/statusline-weight.py |
el peso en la línea de estado, en cada renderizado |
~/.claude/runtime/ |
estado anti-insistencia, un log y una caché de medición |
~/.claude/handoffs/ |
las exportaciones y chains.json, que enlaza padre e hijo |
Se registran cuatro eventos de hook: UserPromptSubmit, SessionStart,
PreCompact y PostCompact. Tus hooks existentes en esos eventos se conservan.
| Claude Code por defecto | con esto instalado | |
|---|---|---|
| cuando la sesión se llena | se dispara la compactación; la mayor parte de la conversación se descarta y se sustituye por un resumen | se te ofrece un relevo mucho antes de ese punto |
| qué sabe la sesión siguiente | lo que captara el resumen, escrito por el agente que ya estaba perdiendo el hilo | la transcripción del padre, leída por entero y verificada con recuentos |
| historial descartado | sin referencia en la sesión viva | recuperado del disco en 05-dropped-context.md |
| ¿cuán llena está de verdad? | /context muestra el % de la ventana |
la línea de estado muestra el % del muro que realmente termina la sesión |
| encontrar la continuación después | recorrer /resume |
chains.json registra padre, hijo, el peso en el momento de migrar y si la lectura se verificó |
La línea de estado se ve así:
Opus 5 | ████████░░ 85% 830k/977k | 696t 402tc 6.1h | HANDOFF DUE (5) | no-compactPorcentaje del muro, no de la ventana. Son distintos, a veces por un factor de cinco, y eso es justo de lo que trata la sección siguiente.
Vale la pena leerlo incluso si no instalas nada.
Claude Code tiene dos puntos distintos en los que una sesión termina:
la compactación se dispara en ventana − reserva de respuesta (~20k) − búfer de resumen (~13k)
el envío se rechaza en techo − reserva de respuesta (~20k) − margen (~3k)El primero aplica con la compactación activada; el segundo, desactivada. Así que una ventana de 200.000 tokens compacta alrededor de 167.000.
Aquí está la trampa: autoCompactWindow en settings.json se recorta al techo
del modelo, en silencio. Pide 1.000.000 contra un techo de 200.000 y obtienes
200.000, sin que nada en la interfaz lo diga. Una sesión configurada para un
millón de tokens se compacta a 167.000, tres veces seguidas, mientras unos
830.000 tokens ya pagados quedan sin usar.
No es hipotético. Es el origen de este repositorio: tres compactaciones con
preTokens de 167.398 / 167.071 / 166.904, contra un archivo de configuración
que decía autoCompactWindow: 1000000.
--explain te dice en qué caso estás:
WINDOW
client reported 1,000,000
ceiling 1,000,000 (source DISABLE_COMPACT+CLAUDE_CODE_MAX_CONTEXT_TOKENS)
resolved 1,000,000 (source settings)
WALL -- the token count past which no more work happens here
1,000,000 ceiling - 20,000 reply reserve - 3,000 margin
= 977,000 then SENDING IS REFUSED (no summary; a handoff is the only exit)Si dice settings CLAMPED to …, tu ajuste de ventana está siendo rebajado.
Solo una configuración escapa al recorte: DISABLE_COMPACT=1 junto con
CLAUDE_CODE_MAX_CONTEXT_TOKENS. El instalador puede ponerlo por ti, pero
pregunta primero y te dice el coste, porque también desactiva el /compact
manual:
python install.py --disable-compact --window 1000000Con eso puesto, la sesión ya no termina en un resumen: termina en un rechazo a enviar. Es un intercambio real. Un rechazo es sobrevivible: haces el relevo y sigues. Un historial destruido en silencio no lo es. Pero si ignoras todos los avisos hasta el muro, esa sesión deja de aceptar turnos, y conviene saberlo de antemano. El guardián se dispara al 85%, dejando unos 147.000 tokens de margen, así que en la práctica no se llega.
Sáltate este flag si prefieres conservar /compact. El relevo sigue funcionando.
Nada de esto parchea ni envuelve Claude Code. Lee dos interfaces documentadas —el contrato de stdin/stdout de los hooks y la carga de la línea de estado— y analiza las transcripciones JSONL que el cliente ya escribe. Por eso sobrevive a actualizaciones que romperían una herramienta construida sobre internos.
Donde hace falta un número exacto, se toma de la evidencia y no se afirma. Tres capas:
- La ventana viene de
context_window_size, que el cliente informa sobre sí mismo en cada renderizado de la línea de estado. - Si la sesión se ha compactado alguna vez, el disparador viene del
preTokensregistrado en la transcripción en ese momento: el disparador observado, no calculado.score()lo prefiere y lo indica concorrected from observed preTokens. - Solo sin ninguno de los dos recurre a la aritmética de reservas, y
--explainmuestra cada entrada para que la desviación sea visible en lugar de silenciosa.
Versiones antiguas de Claude Code. Los cuatro eventos de hook y la línea de
estado han sido estables durante muchas versiones. Si falta un evento en la tuya,
ese hook nunca se dispara y el resto sigue funcionando: el detector es aditivo, no
un reemplazo. --disable-compact es la única parte que depende de nombres de
ajustes concretos; --explain te dirá si no tuvo efecto.
Sistemas operativos. Python puro, sin dependencias, sin partes compiladas. Las
rutas pasan por os.path, CLAUDE_CONFIG_DIR se respeta en todas partes, y el
instalador elige un nombre de intérprete que funcione en tu shell en lugar de
fijarlo. El único código específico de plataforma es forzar UTF-8 en stdout, que
Windows necesita y en el resto es inocuo.
Verifícalo en tu propia máquina:
python tests/test_session_weight.py # aritmética, la compuerta, las dos trampas
python tests/test_compat.py # suelo de sintaxis, puntos de entrada, salida de los hookstest_compat.py encuentra todos los demás Python instalados en tu máquina y vuelve
a ejecutar la suite en cada uno, así una diferencia de versión aparece como un fallo
y no como una sorpresa más adelante.
Se miden siete señales. El contexto es el único que vota si hay que moverse; el resto solo afina cuánta urgencia hay.
| señal | umbral |
|---|---|
| contexto frente al muro | ≥ 85% → relevo, ≥ 95% → dejar de preguntar y actuar |
| turnos del asistente | ≥ 900 |
| llamadas a herramientas | ≥ 600 |
| tiempo de trabajo activo | ≥ 4 h |
| la compactación ya se disparó | cualquiera |
Nada se ofrece por debajo del 62% del muro, sin importar qué más se active. Esta compuerta existe porque las demás señales son aproximaciones de la presión de contexto, inventadas para un mundo en el que el contexto no podía medirse directamente. Medido contra la sesión que construyó esto: 4,3 h de trabajo más dos compactaciones previas puntuaban «relevo ya», mientras el contexto estaba en 147.527 de 977.000 — el 15%. Moverse entonces habría tirado 829.473 tokens sin ganar nada.
Dos detalles de medición que importan más de lo que parece:
- El tiempo activo es la suma de los huecos menores de 10 minutos, nunca último menos primero. Una sesión abierta toda la noche marca 44 h de intervalo y 11 h de trabajo; puntuar el intervalo dispara un relevo en una sesión inactiva.
- Las compactaciones se cuentan desde la fila tipada de la transcripción, nunca buscando una cadena marcadora. Busca el marcador una vez y aparecerá en tu propia salida de herramienta, y el recuento se infla solo.
El aviso aparece como máximo una vez por tramo — 200 turnos más, u otra décima parte del muro — con un suelo de 15 minutos. Nunca se dispara dentro de un subagente.
medir → preguntar → exportar → crear la continuación → esta lee al padreLa exportación escribe cinco archivos: cada mensaje del usuario literal (incluidos los enviados a mitad de turno, que son fáciles de perder), cada mensaje sustancial del asistente, la transcripción completa con las cargas de herramientas recortadas, un índice de recuentos y lo que descartaron las compactaciones anteriores.
Después la continuación se crea y se despierta sin interfaz para leer la exportación antes de que tú la abras. Debe responder con recuentos que coincidan con el índice; si no coinciden, la lectura fue parcial y el relevo no está hecho. Esa lectura ocurre en una sesión en la que nadie está esperando, así que la parte costosa de una migración no te cuesta tiempo real.
Después obtienes el id y el nombre:
claude --resume 7157caa1-11ce-4f29-a46a-09913d483fb0o busca el nombre en /resume: lleva las palabras del tema del padre más
(cont. 2).
Todo lo anterior se puede comprobar en tu propia máquina. Los scripts imprimen números, no tranquilidad:
# ¿dónde termina realmente mi sesión, y por qué?
session_weight.py --explain
# ¿cuál es el peso actual, con cada señal nombrada?
session_weight.py --session-id <uuid>
# legible por máquina
session_weight.py --session-id <uuid> --jsonPara confirmar que un cambio de configuración surtió efecto, no te fíes del archivo: lee la transcripción. Busca el primer turno cuyo total de tokens supere el umbral antiguo y comprueba que no le sigue ninguna fila de compactación nueva.
Dichas sin rodeos, porque una herramienta que mide cosas debe ser honesta sobre lo que no ha medido:
- Las reservas (~20k / ~13k / ~3k) se derivan del comportamiento observado. Una
versión futura podría cambiarlas. Hay tres capas de defensa: la ventana que el
propio cliente informa, el
preTokensreal que queda en la transcripción (el disparador observado, quescore()prefiere), y solo al final esta aritmética de reservas — la conjetura es únicamente la tercera capa. - El muro de rechazo de envío se ha calculado y corroborado, no alcanzado a propósito. El guardián está diseñado para que nunca llegues ahí.
- Probado en Windows con Python 3.11, 3.12 y 3.14, y comprobado contra la gramática de 3.8. Linux y macOS deberían funcionar — no queda código específico de plataforma más allá de la codificación de consola — pero ninguno se ha ejecutado de principio a fin.
- La exportación de cinco archivos y el medidor están cubiertos por las pruebas. El
despertar sin interfaz depende de que tu binario
claudese pueda lanzar; si no se puede, la exportación igualmente se completa y la herramienta te dice qué hacer. - Caché de prompt: un relevo inicia una sesión nueva, así que su caché arranca en frío. Para una sesión cerca del muro es un buen intercambio; sigue siendo un coste.
Los informes de fallos son bienvenidos, especialmente «los números no cuadraban en
mi entorno»: incluye la salida de --explain. Si una versión de Claude Code mueve
esta aritmética, ese es el informe que lo arregla más rápido.
Antes de abrir un PR, ejecuta las dos suites:
python tests/test_session_weight.py
python tests/test_compat.pySECURITY.md documenta exactamente qué lee, qué escribe y qué envía por la red (nada). Merece un repaso antes de instalar algo que toca tus archivos de sesión.
MIT — ver LICENSE. Libre para usar, modificar y redistribuir, incluso comercialmente. La única condición es que el aviso de copyright y el texto de la licencia viajen con el código, de modo que un fork o una copia reempaquetada siga indicando de dónde salió.
Si usas el enfoque o los hallazgos —en particular el diagnóstico de la ventana
recortada— se agradece un enlace de vuelta. CITATION.cff está ahí para que el
botón «Cite this repository» de GitHub produzca algo correcto.
Escrito por IRDkiya.