~/.claude/projects/ en el sistema de archivos local. Un adaptador SessionStore le permite reflejar esas transcripciones en su propio backend, como un almacén de objetos, un almacén de clave-valor o una base de datos, para que una sesión creada en un host pueda reanudarse en otro host que se ejecute desde un directorio de trabajo coincidente.
Razones comunes para usar un almacén de sesiones:
- Implementaciones multi-host. Las funciones sin servidor, los trabajadores con escalado automático y los ejecutores de CI no comparten un sistema de archivos. Un almacén compartido permite que las réplicas reanuden las sesiones de las demás.
- Durabilidad. Los contenedores locales son efímeros. Un almacén externo sobrevive a reinicios y redeploys.
- Cumplimiento y auditoría. Mantén transcripciones en almacenamiento que ya gobiernas, con tus propias reglas de retención, cifrado y controles de acceso.
La interfaz SessionStore
Un SessionStore es un objeto con dos métodos requeridos, append y load, y cuatro métodos opcionales. El SDK llama a append para escribir entradas de transcripción durante una consulta y a load para leerlas de nuevo para reanudar.
SessionKey direcciona una transcripción. projectKey es una codificación estable y segura para el sistema de archivos del directorio de trabajo, sessionId es el UUID de la sesión, y subpath se establece cuando la entrada pertenece a una transcripción de subagente o archivo sidecar en lugar de la conversación principal.
Debido a que projectKey codifica el directorio de trabajo, reanude o continúe desde el almacén desde un directorio de trabajo que coincida con la ejecución original. En TypeScript, si establece CLAUDE_CODE_PROJECT_DIR_NAME junto a CLAUDE_CONFIG_DIR en la opción env de una consulta, el SDK codifica las entradas de esa consulta, y sus búsquedas de resume y continue, por ese nombre en su lugar. Debido a que los ayudantes independientes como listSessions y deleteSession no toman env y leen el entorno del proceso, establezca CLAUDE_CONFIG_DIR y el mismo nombre en el entorno del proceso del host también. Requiere Agent SDK v0.3.234 o posterior.
Trate subpath como una clave de sufijo opaca; sigue el diseño en disco, por ejemplo subagents/agent-<id>. Cuando subpath no está definido, la clave se refiere a la transcripción principal.
En una
SessionSummaryEntry, mtime es el tiempo de escritura del almacenamiento del sidecar y debe compartir una fuente de reloj con los valores mtime que listSessions devuelve. data es un estado propiedad del SDK opaco; persístalo textualmente sin interpretarlo.
Construya las entradas llamando al ayudante exportado foldSessionSummary, fold_session_summary en Python, en cada lote dentro de append. Omita lotes cuya clave tenga un subpath; las transcripciones de subagente no deben contribuir al resumen de la sesión principal. El fold nunca establece mtime: establézcalo en el momento de la persistencia, a través del argumento options.mtime en TypeScript o sobrescribiendo el campo en la entrada devuelta en Python. Las llamadas concurrentes a append para la misma sesión pueden competir en el sidecar, así que serialice la lectura-fold-escritura con una transacción, una comparación e intercambio, o un bloqueo por sesión; el fold en sí es puro.
Para lo que el SDK hace con la transcripción que load devuelve, consulte Reanudar desde el almacén.
Inicio rápido
El SDK incluye unInMemorySessionStore para desarrollo y pruebas. El ejemplo a continuación ejecuta una consulta con el almacén adjunto, captura el ID de sesión del mensaje de resultado, luego reanuda desde el almacén en una segunda llamada query(). La segunda llamada pasa la misma instancia de almacén más resume, por lo que el SDK carga la transcripción del almacén en lugar del sistema de archivos local:
Escribe tu propio adaptador
Implementaappend y load contra tu backend. Añade listSessions, listSessionSummaries, delete y listSubkeys si deseas que listSessions(), lecturas de metadatos de una sola llamada, deleteSession() y la reanudación de subagentes funcionen contra el almacén.
Las entradas pasadas a append se escriben como SessionStoreEntry (un objeto { type: string; ... }). Trátalas como valores opacos seguros para JSON: persístalas en orden y devuélvelas desde load en el mismo orden. load debe devolver entradas que sean profundamente iguales a lo que se anexó; la serialización byte-igual no es requerida, por lo que backends que reordenan claves de objeto, como un tipo de columna JSON binaria, están bien.
Implementaciones de referencia
Ambos repositorios del SDK incluyen adaptadores de referencia ejecutables bajoexamples/session-stores/ en TypeScript y examples/session_stores/ en Python. Hay un adaptador por tipo de almacenamiento, y cada uno muestra cómo append y load se asignan a ese tipo de backend. No se publican como paquetes; copia el adaptador del tipo más cercano a tu backend en tu proyecto, instala el cliente de tu backend y adáptalo.
Cada adaptador toma una instancia de cliente preconfigurada, por lo que controlas credenciales, TLS, región y agrupación. El siguiente ejemplo conecta el adaptador de almacén de objetos en
query() y luego se reanuda desde él en otro host:
TypeScript
Valida tu adaptador
Ambos SDKs incluyen un conjunto de conformidad que afirma el contrato de comportamiento queappend, load y los métodos opcionales deben satisfacer. Las pruebas para métodos opcionales se omiten automáticamente cuando esos métodos no se implementan.
En TypeScript, copia shared/conformance.ts del directorio de ejemplos en tu suite de pruebas. En Python, el conjunto se incluye en el paquete. Para ejecutarlo con pytest, que no es una dependencia del SDK, instala pytest primero:
run_session_store_conformance llama una vez por contrato para construir un almacén nuevo:
Python
MyRedisStore en sí, como hace este ejemplo, funciona cuando el constructor no toma argumentos. Para un adaptador que toma un cliente preconfigurado, pasa una lambda que construya el almacén en su lugar. Debido a que los contratos reutilizan las mismas claves de sesión, cada almacén que devuelve la fábrica debe comenzar con almacenamiento vacío, así que haz que la lambda aprovisione almacenamiento de respaldo aislado por llamada, como un falso en memoria nuevo, un prefijo de clave único, o una base de datos de prueba nueva.
Notas de comportamiento
Arquitectura de escritura dual
El subproceso de Claude Code siempre escribe cada lote de entradas de transcripción en el disco local primero, y luego el SDK reenvía el mismo lote aappend() de su almacén, por lo que el almacén es un espejo del transcripción local en lugar de un reemplazo. Cuál copia sobrevive a la ejecución depende de cómo se inició la ejecución:
- Sesión nueva, o una reanudación cuando el almacén no tiene nada para la sesión: la transcripción local bajo su directorio de configuración sobrevive a la ejecución, y el almacén recibe una copia.
- Ejecución reanudada desde el almacén: la copia local se elimina al final de la ejecución, por lo que el almacén contiene la única copia duradera.
CLAUDE_CONFIG_DIR en un directorio temporal en options.env. Una ejecución reanudada desde el almacén ya elimina su copia local, por lo que no necesita tal configuración. En TypeScript, también propague process.env en env, ya que la opción env reemplaza el entorno del subproceso.
Si su aplicación inicia sesión a través de archivos en el directorio de configuración, como credenciales de OAuth o un apiKeyHelper en su settings.json de usuario, copie primero esos archivos en el directorio temporal, o establezca ANTHROPIC_API_KEY en env en su lugar. De lo contrario, la ejecución falla con Not logged in.
Dos opciones entran en conflicto con el espejo, y el SDK lanza una excepción al inicio si combina cualquiera de ellas con un almacén:
persistSession: falseen TypeScript: desactiva las escrituras locales en las que se basa el espejo. El SDK de Python no tiene una opción equivalente.- Checkpointing de archivos,
enableFileCheckpointingen TypeScript oenable_file_checkpointingen Python: escribe sus copias de seguridad de archivos directamente en el disco local, y el SDK no las refleja en el almacén.
Reanudación desde el almacén
Cuando pasaresume, o continue: true en TypeScript o continue_conversation=True en Python, junto con un almacén, el SDK solicita una transcripción al almacén antes de generar el subproceso:
resume: el SDK solicita la sesión cuyo ID pasó.continue: trueocontinue_conversation=True: el SDK solicita la sesión más nueva del almacén.
CLAUDE_CONFIG_DIR apuntando allí, y elimina el directorio cuando finaliza la ejecución. La transcripción local que esa ejecución escribe se elimina con él, por lo que el almacén contiene la única copia duradera en esta ruta.
El SDK también siembra el directorio temporal con archivos de su directorio de configuración real. Lo que copia difiere según el idioma:
- TypeScript: credenciales,
.claude.json, y susettings.jsonde usuario. Desettings.jsonelimina las claves que se comportan mal bajo un directorio de configuración temporal:enabledPlugins,extraKnownMarketplaces, su aliasadditionalMarketplaces, y cualquierCLAUDE_CONFIG_DIRen el bloqueenvdel archivo. Antes de Agent SDK v0.3.232, el SDK no eliminaba el alias. La autenticación configurada en configuración, comoapiKeyHelper, funciona cuando reanuda desde el almacén. Antes de Agent SDK v0.3.222, el SDK de TypeScript copiaba solo credenciales y.claude.json. - Python: solo credenciales y
.claude.json, por lo que una aplicación que se autentica a través deapiKeyHelperen susettings.jsonde usuario falla conNot logged incuando reanuda desde un almacén. UnapiKeyHelperen configuración administrada o de proyecto aún funciona, porque Claude Code lee esos archivos desde ubicaciones queCLAUDE_CONFIG_DIRno afecta.
resume: ambos SDKs pasan el ID al subproceso, que reanuda la transcripción local exactamente como lo haceresumesin un almacén.continue: trueen TypeScript: el SDK inicia una sesión nueva.continue_conversation=Trueen Python: el SDK continúa desde la sesión local más nueva.
Las escrituras de espejo son de mejor esfuerzo
Siappend() rechaza, el SDK reintenta el lote hasta dos veces más con un retroceso corto, para un máximo de tres intentos en total. Una llamada que agota el tiempo de espera no se reintenta, ya que la llamada original aún puede llegar. Si el lote aún falla, el SDK registra el error, emite un mensaje { type: "system", subtype: "mirror_error" } en el iterador, descarta el lote y continúa la consulta. Debido a que un lote reintentado puede volver a entregar entradas que ya llegaron, deduplique por entry.uuid en su implementación de append().
Una interrupción del almacén no interrumpe el agente, ya que el subproceso escribe localmente primero. Monitoree mirror_error si necesita detectar pérdida de datos del almacén. En una ejecución reanudada desde el almacén, un lote descartado no tiene copia sobreviviente una vez que finaliza la ejecución.
getSessionMessages devuelve la cadena posterior a la compactación
getSessionMessages({ sessionStore }) devuelve la cadena de mensajes vinculada que el agente vería al reanudar. Después de la compactación automática, los turnos anteriores se reemplazan por un resumen, por lo que una sesión cuyo almacén contiene 503 entradas sin procesar puede devolver 18 mensajes de getSessionMessages. Para el historial sin procesar completo, incluidos los turnos anteriores a la compactación y las entradas de metadatos, llame a store.load(key) directamente.
forkSession no es una copia byte a byte
forkSession({ sessionStore }) lee las entradas de origen, reescribe cada campo sessionId y remapea los UUID de mensajes, luego añade las entradas transformadas bajo una clave nueva. Una copia a nivel de adaptador o un atajo CopyObject produciría una transcripción que aún hace referencia al ID de sesión anterior, por lo que el SDK no usa uno.
Transcripciones de subagentes
Las transcripciones de subagentes se reflejan bajosubpath: "subagents/agent-<id>". listSubagents({ sessionStore }) requiere que el adaptador implemente listSubkeys; getSubagentMessages({ sessionStore }) lo usa cuando está disponible pero recurre a la subruta directa cuando no está definido. La reanudación también llama a listSubkeys para restaurar archivos de subagentes; sin él, solo se materializa la transcripción principal.
Retención
El SDK nunca elimina de su almacén por su cuenta. La retención es responsabilidad del adaptador: use el mecanismo de caducidad o ciclo de vida de su backend, o ejecute una limpieza programada, de acuerdo con sus requisitos de cumplimiento. Las transcripciones locales bajoCLAUDE_CONFIG_DIR se barren independientemente por la configuración cleanupPeriodDays, siguiendo las reglas de barrido de retención. Una ejecución reanudada desde el almacén no deja transcripción local, por lo que para esas ejecuciones la retención de su almacén es la única retención que existe.
Compatible con
Las siguientes funciones del SDK de TypeScript aceptan una opciónsessionStore y operan contra el almacén en lugar del sistema de archivos local cuando se proporciona:
query()startup()listSessions()getSessionInfo()getSessionMessages()renameSession()tagSession()deleteSession()forkSession()listSubagents()getSubagentMessages()
session_store en ClaudeAgentOptions para ejecutar query() contra un almacén. Las operaciones restantes tienen cada una una función respaldada por almacén de Python que toma el almacén como argumento: list_sessions_from_store(), get_session_info_from_store(), get_session_messages_from_store(), list_subagents_from_store(), get_subagent_messages_from_store(), rename_session_via_store(), tag_session_via_store(), delete_session_via_store() y fork_session_via_store(). startup() no tiene equivalente en Python. Las funciones independientes documentadas en la referencia del SDK de Python, como list_sessions(), leen archivos de sesión locales.
Recursos relacionados
- Trabajar con sesiones: Continúa, reanuda y bifurca sin un almacén personalizado
- Alojar el SDK: Patrones de implementación para entornos multi-host
- TypeScript
Options: Referencia de opción completa - Implementaciones de referencia: Adaptadores de ejemplo ejecutables para un almacén de objetos, un almacén de clave-valor y una base de datos, en ambos repositorios del SDK