CONTINUUM

Recuperación semántica universal y verificable para agentes de IA de larga duración con puntos de control semánticos, libro de acciones idempotente y registro encadenado por hash como servidor MCP de denegación por defecto

Documentación

CONTINUUM Banner

CONTINUUM: Recuperación semántica verificable para agentes de IA de larga duración. Puntos de control semánticos (no volcados de conversación), un libro de contabilidad de acciones idempotente que rechaza efectos secundarios duplicados, y un registro de eventos encadenado por hash y a prueba de manipulaciones, todo expuesto como un servidor MCP con denegación por defecto. Independiente del framework, Python 3.11+.

Python 3.11+ PyPI License Pydantic v2 Website Demo CI status Coverage Stars

Visita el sitio web de CONTINUUM

Build with Ona

Si CONTINUUM ayuda a tus agentes a recuperarse, por favor dale una estrella al repositorio. Ayuda a otros a descubrirlo y mantiene llegando buenos primeros issues.

English | 简体中文 | Español | 日本語 | Português | 한국어


Contenido

Por qué · Inicio rápido · Cómo funciona · Dónde encaja CONTINUUM · Características · Extensión de seguridad · Verificación empírica · Integración MCP · Integración de frameworks · Conceptos centrales · Arquitectura · API y CLI · Hoja de ruta · Lo que CONTINUUM no es · Trabajo relacionado · Estado y limitaciones · Contribuciones · Licencia


Por qué

Los agentes de IA modernos ejecutan tareas largas (cientos de llamadas LLM, invocaciones de herramientas, escrituras en archivos y bases de datos). Cuando fallan, la respuesta habitual es reproducir todo desde cero, lo que duplica trabajo, duplica efectos secundarios, desperdicia tokens y pierde decisiones.

CONTINUUM plantea una pregunta más estrecha y difícil: ¿puede un agente reanudar desde una representación semántica compacta de su estado de tarea mientras verifica de forma independiente que ese estado sigue siendo válido en el entorno actual? Su diferenciador es triple:

  • Puntos de control semánticos: una representación compacta y versionada de lo que el agente necesita para continuar, no un volcado de conversación.
  • Revalidación independiente del entorno: cada componente del punto de control se verifica contra el entorno actual antes de reanudar, con la obsolescencia propagándose a través del grafo de dependencias.
  • Estado con trazabilidad de origen: cada hecho se rastrea hasta su origen, por lo que el progreso informado por el agente nunca es autocertificable.

Inicio rápido

Publicado en PyPI como continuum-agent 0.1.2: pip install continuum-agent (pip install continuum-agent==0.1.2 para fijar). Las etiquetas de lanzamiento además incluyen ruedas compiladas adjuntas a GitHub Releases.

Rutas que no requieren clonar ni instalación local:

RutaCómo
Instalar desde PyPIpip install continuum-agent==0.1.2, luego continuum --help
Instalar con Homebrewbrew install wized2/continuum/continuum, luego continuum --help
Ver la recuperación de fallos de principio a findocker run --rm ghcr.io/cyrax321/continuum
Usar la CLI a través de Dockerdocker run --rm ghcr.io/cyrax321/continuum continuum --help
Ejecutar la CLI sin clonaruvx --from git+https://github.com/Cyrax321/CONTINUUM.git continuum --help
Windows PowerShell (desde un clon)powershell -ExecutionPolicy Bypass -File .\try-it.ps1 o powershell -ExecutionPolicy Bypass -File .\try-it.ps1 cli --help
Ver la misma recuperación en un notebookOpen In Colab
El mismo notebook, en BinderBinder
Entorno de desarrollo completo en el navegadorOpen in GitHub Codespaces

La imagen de Docker se publica en GHCR por CI en cada push a main y en cada etiqueta de lanzamiento (.github/workflows/docker-publish.yml). El Codespace está definido en .devcontainer/. El notebook es examples/demo.ipynb: su primera celda instala CONTINUUM solo cuando la importación falla, por lo que el único archivo se ejecuta en Colab, en Binder y desde un clon.

git clone https://github.com/Cyrax321/CONTINUUM.git
cd CONTINUUM

uv venv && source .venv/bin/activate     # macOS / Linux; Windows: .venv\Scripts\activate

# Contributors (recommended): library + CLI + test tooling + framework integrations
uv pip install -e ".[dev]"

# Or pick only what you need: . (minimal), [mcp], [browser], [kubernetes],
# [otel], [langgraph], [openai], [langchain], [attest], [postgres]

# Or skip the clone entirely:
uv pip install git+https://github.com/Cyrax321/CONTINUUM.git
uv pip install "continuum-agent[mcp] @ git+https://github.com/Cyrax321/CONTINUUM.git"

Alternativa pip: reemplaza uv pip install con pip install en cada comando anterior.

Adaptadores de entorno opcionales:

  • uv pip install -e ".[browser]" habilita BrowserAdapter; ejecuta playwright install chromium por separado para instalar el binario del navegador.
  • uv pip install -e ".[kubernetes]" habilita KubernetesAdapter; kubectl y un clúster configurado siguen siendo requisitos previos externos.

Si usas pip en lugar de uv, ejecuta pip install -e ".[browser]" o pip install -e ".[kubernetes]" con los mismos requisitos previos externos.

Verifica:

continuum --help                 # CLI entrypoint
continuum-mcp --help             # MCP server entrypoint (needs [mcp] or [dev])
pytest -q                        # ~3680 collected, ~3,680 passed, ~0 skipped on a minimal env (exact counts vary)
ruff check src/ tests/ examples/ && ruff format --check src/ tests/ examples/
mypy src/continuum               # the three gates CI enforces

La biblioteca central tiene una dependencia de tiempo de ejecución (pydantic>=2.7); todo lo demás es opcional. El mapa completo de paquetes, la matriz de extras, la configuración de pruebas de Postgres y la verificación por comando están en references/install.md.

Conecta un agente de codificación en dos minutos

Para Claude Code, Gemini CLI o Codex, no necesitas escribir Python ni un archivo de prompt:

continuum start my-task --goal "What the agent should do"
continuum hooks install claude-code --with-gate   # also: gemini, codex

A partir de entonces, cada archivo que el agente escriba se captura como evidencia encadenada por hash, su sesión comienza con un informe de estado automático, los efectos secundarios no reclamados registrados en .continuum/gate.json se rechazan antes de que se disparen, y una sesión nueva después de cualquier fallo se reanuda con los siguientes pasos ejecutables. No se requiere CLAUDE.md.

Ejemplo mínimo de biblioteca, registrar y recuperar:

from continuum import EventType, Run, SQLiteStorage, project

store = SQLiteStorage("agent.db")
store.create_run(Run(run_id="run_4821", goal="Analyze 10,000 documents"))
store.append_event("run_4821", EventType.RUN_STARTED, {"goal": "Analyze 10,000 documents", "total": 10_000})

for i, doc in enumerate(documents):
    analyze(doc)
    store.append_event("run_4821", EventType.WORK_COMPLETED, {"doc": i})

# After a crash, a new process picks up exactly where it stopped:
state = project("run_4821", store.read_events("run_4821"))
print(state.progress.completed)            # already done, not repeated
print(store.verify_events("run_4821").ok)  # True, chain intact after the crash

Ejecuta la prueba tú mismo:

python examples/crash_recovery_agent.py   # real process kill, real side effect
python examples/context_compaction.py     # transcript lost, checkpoint survives
python examples/model_switch.py           # Model A dies, Model B resumes safely
python scripts/mcp_smoke.py               # real subprocess, real JSON-RPC traffic

El kit e2e-autonomy-test/ automatiza una tarea real de lote de facturas, un cierre forzado a mitad de ejecución y una sesión de reanudación nueva, luego puntúa la bandeja de salida, el libro de contabilidad y la cadena de eventos fuera de banda. La ejecución 1 obtuvo 7/7 mecánicas contra una sesión real de Claude Code. Guía completa en references/e2e.md.

Cómo funciona

CONTINUUM separa el contexto LLM (temporal) del estado de tarea duradero (permanente). En lugar de guardar el historial de conversación, construye un punto de control semántico, la información mínima verificada necesaria para continuar.

CONTINUUM how it works

La explicación detallada, el modelo de proyección y el contexto de recuperación están en references/architecture.md.

Dónde encaja CONTINUUM

Cuatro preocupaciones se superponen en cada agente de larga duración. CONTINUUM solo posee la última y toca las otras tres a través de costuras explícitas. No se nombra a ningún competidor ni se hace ninguna afirmación sin un módulo publicado o una suite publicada que ya lo imprima.

CapaRespondeCómo se conecta (módulos publicados o salida publicada)
Orquestación¿Cómo llama el agente a las herramientas y avanza hacia un objetivo?Fuera de CONTINUUM. Los puntos de conexión se publican en src/continuum/adapters/generic.py (GenericAgentAdapter), src/continuum/adapters/thin.py (hooks de CrewAI, AutoGen, Pydantic AI), src/continuum/mcp/server.py (MCP stdio), src/continuum/hooks.py y src/continuum/clienthooks.py (hooks de ciclo de vida de CLI de codificación), src/continuum/gateway.py (aplicación de proxy HTTP para cualquier lenguaje) y src/continuum/otel.py (puente OpenTelemetry). Las recetas están en docs/recipes/ y references/adapters.md.
Ejecución duradera¿Qué sucedió antes de un fallo y qué se puede reproducir sin perder trabajo?Registro de eventos encadenado por hash src/continuum/events.py con verify() y trusted_through, almacenamiento duradero src/continuum/storage/sqlite.py (WAL, synchronous=FULL, esquema v6) y src/continuum/storage/postgres.py más src/continuum/storage/migrations.py, puntos de control basados en políticas src/continuum/checkpoint/manager.py y src/continuum/checkpoint/policy.py que reproducen la brecha en restore(). La guía está en docs/recovery_walkthrough.md (salida de examples/recovery_walkthrough.py).
Plano de control¿Qué ejecución está activa, quién puede actuar sobre ella y a dónde va la salida?Registro de ejecuciones y jerarquía padre/hijo src/continuum/storage/ y src/continuum/recovery/family.py (continuum tree), autorización por lista de permitidos src/continuum/mcp/authz.py (CONTINUUM_MCP_MUTATING_CLIENTS / CONTINUUM_MCP_TOKEN), superficies de presentación src/continuum/dashboard/app.py y src/continuum/serve/server.py, CLI src/continuum/cli/main.py (continuum runs, continuum tree, continuum health).
Sustrato de verificaciónDado el punto de control en el tiempo T y el mundo tal como es ahora, ¿es aún seguro y correcto continuar?src/continuum/state/validator.py (obsolescencia dependency -> evidence -> finding -> decision más PlanStep.depends_on), src/continuum/provenance_map.py (Origin a REQUIRES_REVIEW hasta REVIEW_CONFIRMED), src/continuum/actions/ledger.py con src/continuum/actions/idempotency.py y src/continuum/gate.py / src/continuum/gateway.py (reclamar antes de disparar, rechaza duplicados, lanza UnknownSideEffect para reconciliación), src/continuum/replayguard.py (guardia portátil), src/continuum/pinning.py y src/continuum/replay_similarity.py (corrección de reproducción), src/continuum/budgets.py (límites de reintentos), src/continuum/recovery/engine.py + src/continuum/recovery/contract.py + src/continuum/recovery/planner.py + src/continuum/recovery/observations.py (severidad máxima RESUME < ... < ABORT, contrato sellado con evidence / reason / next_allowed_action / human_steps), src/continuum/checkpoint/rewind.py (rebobinado atómico de doble estado), src/continuum/analysis/prefix_trust.py (confianza consultiva). Comprobaciones publicadas: docs/recovery_walkthrough.md, benchmarks/fault_injection/ (suite que imprime detection_rate / unsafe_resume_rate), src/continuum/benchmark/phase6/ (suite de corrección de recuperación), docs/RESULTS.md y el visual regenerable a continuación.

Cada fila anterior es rastreable a una ruta que existe en main en el commit etiquetado. Nada en esta tabla reformula un número de referencia; los puntos de referencia solo viven en la salida de la suite que ya imprimen. Consulta docs/research.md para la lista completa de suites publicadas y documentos de diseño.

Recuperación de fallos, de verdad

La imagen a continuación no es un simulacro. Es la salida de python demo-run/generate_crash_visual.py, que ejecuta demo-run/worker.py hasta os._exit(9) en el documento 399, llama a continuum resume --env dataset=v4 y muestra la ruta de rechazo (REQUEST_HUMAN, safe:false, salida 21), reconcilia el efecto secundario incierto con una sonda, luego se reanuda desde la misma base de datos y termina sin trabajo duplicado. La transcripción también se guarda como docs/assets/crash-recovery.txt para auditoría.

Regenérala:

python demo-run/generate_crash_visual.py
# or: python scripts/generate_crash_visual.py

Crash recovery: hard kill mid-batch, refusal, reconcile, resume

Guía completa con código en docs/recovery_walkthrough.md (examples/recovery_walkthrough.py). El banco de pruebas mínimo está en references/bench.md (continuum benchmark).

Características

CapacidadQué te aporta
Puntos de control semánticosEstado compacto, versionado e inspeccionable, no un volcado de transcripción
Libro mayor de acciones idempotentesRechaza efectos secundarios externos duplicados; expone los inciertos para reconciliación
Revalidación del entornoCada componente del punto de control se verifica contra el mundo actual antes de reanudar
Estado consciente de la procedenciaEl progreso reportado por el agente se marca REQUIRES_REVIEW, nunca autocertificado
Motor de recuperaciónSiete modos de recuperación con un contrato determinista y sellado de siguiente acción
Servidor MCP de denegación por defectoTrece herramientas, división de solo lectura/mutación, lista de permitidos del llamador
Adaptadores de frameworksIntegraciones genéricas de Python, OpenAI Agents SDK, LangGraph y LangChain
Bucle de planificación seguroLa verificación de observaciones con dos señales escala ramas de alto riesgo a REQUIRES_REVIEW
Revalidación periódicaEl entorno se reexamina según un cronograma, detectando desviaciones a mitad de ejecución dentro de un ciclo
Registro a prueba de manipulacionesRegistro de eventos encadenado por hash (55 tipos de eventos) con verificación de integridad
Puerta de aplicaciónLas llamadas de efectos secundarios no reclamadas se rechazan antes de ejecutarse; los mensajes de denegación enseñan el protocolo de reclamación
Ganchos de observaciónCada archivo que una CLI de codificación escribe se convierte en evidencia verificada por digest, fuera del control del modelo
Informe de sesiónLas sesiones nuevas aprenden el estado de ejecución de forma determinista al inicio, incluido el resumen de razonamiento de la última sesión
Sondas de reconciliadorLos comandos registrados resuelven efectos secundarios inciertos automáticamente; los humanos solo ven el resto
Guía ejecutableReanudar/validar renderiza los siguientes pasos como comandos ejecutables, no como estados
Puerta de enlace HTTP de aplicaciónLas llamadas salientes en cualquier idioma requieren reclamaciones; las respuestas las resuelven desde la realidad
Puente OpenTelemetryLos tramos de llamadas a herramientas del rastreo de producción se convierten en evidencia sin cambios de código
Índice de accionesLas búsquedas de idempotencia entre ejecuciones son lecturas indexadas, no escaneos completos del registro
Fijación de versionesLos hashes de prompt/herramienta/modelo afirmados por el llamador se almacenan por reclamación; la desviación se muestra al reanudar
Presupuestos de reintentoLos límites de intentos por tipo de acción se aplican en el momento de la reclamación; los agentes ven los intentos restantes
Padre/hijo multiagenteLa reanudación del padre compone el peor estado familiar; el hijo incierto bloquea al padre
Reintento informadoLos resúmenes de fallos redactados por el motor se inyectan en las reanudaciones posteriores a la recuperación
Semántica de bifurcaciónLas continuaciones divergentes se ramifican en ejecuciones hijas con autoridad renovada
Compactación de registrosEl prefijo anterior al ancla se archiva textualmente; el registro en vivo se limita para ejecuciones de un mes
Seguimiento de concesiones consumidasLas referencias de autoridad de un solo uso se marcan como gastadas en estado terminal; la reutilización después de la restauración se rechaza (GRANT_DENIED), defendiendo la ruta de restauración de puntos de control contra la Resurrección de Autoridad
Atestación de cadenacontinuum attest firma la cabeza de la cadena de una ejecución con Ed25519 para que un verificador externo pueda probar que la historia no fue alterada a partir de una clave conocida
Superficie de panel HITLBotones de confirmar/reconciliar/completar con paridad de auditoría con la CLI

Extensión de Seguridad

Dos extensiones de seguridad aditivas se sitúan sobre el sustrato de recuperación y puntos de control. No cambian la reanudación, la reproducción ni la ruta de revalidación en tiempo de fallo existente.

Estado: especificado y probado, no enviado (problema #1030). Los módulos a continuación están completos y pasan sus pruebas, pero nada en el motor ni en ninguna costura los invoca todavía (CONTINUUM revalida solo en fallo/reanudación). Conectarlos es una decisión de hoja de ruta; lea el tiempo presente a continuación como el diseño, no el comportamiento enviado.

  • Bucle de planificación seguro: las observaciones llevan procedencia y se verifican mediante dos señales independientes (verified / unverified / contested). Una rama de planificación condicionada a una observación no verificada o disputada se escala a REQUIRES_REVIEW. Las decisiones se añaden al libro mayor como eventos PERCEPTION_OBSERVED y BRANCH_RESOLVED.
  • Revalidación periódica: reutiliza el motor de recuperación en un intervalo de pasos (predeterminado 25) y al cambiar de aplicación, de modo que la desviación del entorno a mitad de ejecución se detecta dentro de un ciclo en lugar de solo en el próximo fallo.

Consulte docs/PROBLEM.md, docs/RESULTS.md y STATUS.md.

Verificación Empírica

CONTINUUM se verifica contra agentes LLM reales, límites de protocolo en vivo y fallos de proceso duros, no solo pruebas unitarias simuladas.

  • Agentes reales: lotes de facturas de Claude Code de múltiples sesiones con SIGKILL a mitad de ejecución, puntuados 7/7 en mecánica; las sesiones reanudadas consultaron continuum_resume, enrutaron efectos secundarios a través del libro mayor de dos fases, se negaron a duplicar escrituras verificadas y respetaron request_human. Las pruebas en vivo revelaron brechas de deduplicación por desviación de prompt, cerradas mediante normalización de ruta canónica y respaldo basado en tokens en ActionLedger.claim().
  • Clientes de terceros: Gemini CLI y Kilo Code se conectaron a través de stdio JSON-RPC contra el almacén SQLite en vivo, validando la coexistencia multiagente y el aislamiento de autorización.
  • Cumplimiento de protocolo: impulsado de extremo a extremo con @modelcontextprotocol/inspector --cli a través de muertes de procesos; las herramientas mutantes deniegan por defecto detrás de CONTINUUM_MCP_MUTATING_CLIENTS; las reclamaciones externas degradan a REQUIRES_REVIEW (safe: false).
  • Autocuración: los servidores eliminados a la fuerza se recuperan de sidecars huérfanos de SQLite -wal/-shm mediante limpieza de un solo reintento al inicio.
  • Escala: aproximadamente 3680 pruebas recopiladas (~3,680 aprobadas; ~0 omitidas; otros resultados varían según el entorno) en Python 3.11, 3.12 y 3.13 (unitarias, hypothesis basadas en propiedades, concurrencia, adversariales). CONTINUUM-Bench ejecuta cinco escenarios de fallo más un escenario dedicado de desviación de argumentos, midiendo 0 trabajo duplicado y 0 efectos secundarios duplicados para CONTINUUM frente a duplicación completa para reproducción ingenua; una suite separada de 14 escenarios de corrección de recuperación (continuum.benchmark.phase6) codifica los puntos de fallo del estudio de ejecución duradera como aserciones ejecutables, y una suite de inyección de fallos de 7 fallos (benchmarks/fault_injection/) califica el manejo de fallos.
  • Auditoría adversarial: toda la superficie MCP se auditó sobre el protocolo en vivo; se encontraron y corrigieron tres defectos. Método y pasos de reproducción en test.md.

Benchmark de escala de horizonte (ejecuciones reales, sin números inventados)

Generado: 2026-09-30T11:03:24.403017 Escenarios de horizonte: 5 Aprobados: 4 Fallidos: 1

Precisión: 0.8 Escalamiento innecesario: 0.2 Precisión de reparación: 0.8 Efectos secundarios duplicados: 0 Trabajo duplicado: 0.0 Compresión: 0.138

EscenarioCiclosAñosCorrectoActualPrecisión
horizon_steady_progress_year1412.3reanudarreanudar1.0
horizon_quarterly_drift_year1412.3repararsolicitar_humano0.0
horizon_budget_exhaustion_year1412.3solicitar_humanosolicitar_humano1.0
horizon_compaction_stress_year1772.87reanudarreanudar1.0
horizon_abort_condition_year1412.3abortarabortar1.0

Inyección de fallos: 7 escenarios, detección 1.0, inseguro 0.0

Integración MCP

CONTINUUM incluye un servidor MCP para que un agente pueda registrar progreso, crear puntos de control y enrutar efectos secundarios externos a través del libro mayor sin incrustar la biblioteca:

uv pip install -e ".[mcp]"
CONTINUUM_MCP_MUTATING_CLIENTS=your-client-name continuum-mcp

En Windows, la forma de prefijo de entorno no tiene equivalente en PowerShell, así que establezca la variable primero:

uv pip install -e ".[mcp]"
$env:CONTINUUM_MCP_MUTATING_CLIENTS = "your-client-name"
continuum-mcp

Trece herramientas sobre stdio. Tres son de solo lectura (continuum_validate, continuum_resume, continuum_list_actions); diez mutan. Los efectos secundarios son de dos fases (reclamar, realizar, completar), y las herramientas mutantes deniegan por defecto detrás de una lista de permitidos. El estado reportado por el agente se registra con procedencia Origin.EXTERNAL_AGENT y se marca REQUIRES_REVIEW.

Los detalles de verificación, incluida la recuperación de fallos al inicio y la prueba de extremo a extremo de Claude Code, están en references/mcp.md. Si un servidor registrado reporta CONNECTION_CLOSED, la causa casi siempre es la resolución de PATH en lugar del servidor en sí: docs/api/mcp.md tiene el diagnóstico y dos remedios.

Integración de Frameworks

Nueve adaptadores se envían en src/continuum/adapters/ (una fachada en proceso más ocho integraciones), todos instalaciones opcionales para que el núcleo siga siendo solo de biblioteca estándar:

AdaptadorClaseNotas
Agente Python genéricoGenericAgentAdapterFachada en proceso; escribe estado confiable (Origin.DETERMINISTIC).
Sandbox de sistema de archivosFilesystemSandboxAdapterSandbox de directorio local, sin servicio externo, predeterminado para docs y CI.
Python en procesoPythonInProcAdapterEjecuta Python en un directorio de trabajo temporal, registra a través del libro mayor.
ContenedorContainerAdapterRespaldado por Docker, salto protegido cuando docker está ausente.
NavegadorBrowserAdapterRespaldado por Playwright, salto protegido cuando no está instalado.
KubernetesKubernetesAdapterRespaldado por kubectl, salto protegido cuando no está configurado.
OpenAI Agents SDKOpenAIAgentAdapterExperimental. Engancha ToolContext / RunHooks; openai-agents opcional.
LangGraphLangGraphAgentAdapterExperimental. Envuelve un StateGraph; langgraph opcional.
LangChainLangChainAgentAdapterExperimental. Inserta checkpoint_node en un pipeline LCEL Runnable y el bucle de llamadas a herramientas create_agent; langchain opcional.

Cada adaptador registra progreso a través del libro mayor y enruta efectos externos a través del protocolo de dos fases de interceptar/completar. Los tres adaptadores de frameworks tienen pruebas de integración de extremo a extremo y se han impulsado contra un modelo OpenRouter en vivo, donde las ejecuciones revelaron y luego cerraron una brecha de deduplicación por desviación de argumentos de LLM y dos errores del adaptador de OpenAI, incluida una prueba de fallo duro en vivo (os._exit(137) a mitad de efecto secundario) por adaptador. Uso completo, resultados de modelos en vivo y ejemplos ejecutables para cada adaptador están en references/adapters.md.

Las aplicaciones LangGraph de producción también pueden mantener su API de persistencia nativa: make_continuum_checkpointer(storage) implementa el BaseCheckpointSaver de LangGraph sobre el almacenamiento de CONTINUUM, de modo que cada put aterriza en el mismo registro de eventos encadenado por hash y etiquetado con procedencia (consulte references/adapters.md).

Tres frameworks de producción adicionales están cubiertos por superficies de enganche delgadas y sin SDK en adapters/thin.py:

FrameworkSuperficie de intercepciónPunto de entrada
CrewAIenganches globales antes/después de llamadas a herramientasinstall_crewai_hooks(storage, run_id)
AutoGen coreFunctionTool.run_json envuelto en su lugarwrap_autogen_tool(tool, storage, run_id)
Pydantic AIcapacidad de Hooks asíncronosAgent(capabilities=[wrap_pydantic_ai_hooks(storage, run_id)])

Para stacks que ninguno de estos alcanza: continuum gateway aplica reclamaciones en HTTP saliente desde cualquier idioma, continuum.otel.make_span_processor(storage) convierte los tramos de herramientas OpenTelemetry existentes en evidencia, y continuum serve expone las mismas operaciones que las herramientas MCP sobre un protocolo de cable JSON independiente del idioma (stdio, o HTTP a través de --transport http con autenticación CONTINUUM_SERVE_TOKEN).

Reanudación de ejecuciones reportadas por agente o MCP

El estado reportado a través de MCP, o mediante el adaptador de OpenAI, lleva procedencia Origin.EXTERNAL_AGENT y se resuelve a request_human hasta que se confirme. Las ejecuciones de LangGraph y LangChain usan Origin.DETERMINISTIC y se reanudan directamente. Para limpiar la revisión y reanudar:

continuum confirm <run_id>   # records REVIEW_CONFIRMED, then re-assesses
continuum resume <run_id>    # now reports RESUME

A través de MCP, el equivalente es la herramienta continuum_confirm seguida de continuum_resume. La confirmación es un evento único atestiguado por humanos: la vía de escape para la seguridad de autocertificación, de modo que una ejecución impulsada externamente nunca quede permanentemente atascada.

Conceptos Centrales

La referencia profunda para cada concepto vive en references/concepts.md.

  • Semantic Checkpoints - una representación compacta y versionada de lo que el agente necesita para continuar.
  • State Validation - cada componente verificado de forma independiente; la obsolescencia se propaga a través del grafo de dependencias.
  • Idempotent Action Ledger - los efectos secundarios externos se rastrean y deduplican; los resultados inciertos generan una excepción en lugar de reintentar silenciosamente.
  • Recovery Modes - RESUME, REPAIR_AND_RESUME, ROLLBACK, WAIT, REQUEST_HUMAN, ABORT (además de REPLAN).
  • Recovery Contract - una siguiente acción determinista, sellada con integridad y controlada.

Arquitectura

CONTINUUM se organiza en torno a un invariante: cada hecho lleva su origen, y la confianza se gana, nunca se asume. Por qué esto importa para una startup: un agente que se ejecuta durante semanas no debe perder trabajo cuando se pierde su contexto, y no debe desperdiciar tokens, costos ni disparar una herramienta dos veces.

Sistema de un vistazo: adaptador universal, un registro, cualquier marco de trabajo

Cualquier marco de trabajo se conecta al mismo registro encadenado por hash. La misma ejecución puede ser escrita por Claude Code, reanudada por LangGraph, inspeccionada por la CLI y aprobada en el panel de control. No se requiere cooperación del marco de trabajo.

  Claude Code ─┐
  Gemini CLI ──┤
  Codex ───────┤
  LangGraph ───┼── 5 seams ──►  One durable log  ──►  Recovery + Dashboard + CLI
  LangChain ───┤                (hash chained,        (sealed contract,
  OpenAI SDK ──┤                 provenance tagged,     verify, health,
  CrewAI ──────┤                 exactly once)          family)
  Any HTTP ────┤
  Any OTel app ┘

  Seams: 1 In-process  2 MCP  3 CLI hooks  4 Gateway  5 OTel

Las tres garantías (la demo demuestra cada una)

  1. Sin autocertificación. El estado informado por el agente es EXTERNAL_AGENT y se degrada a REQUIRES_REVIEW hasta que un humano REVIEW_CONFIRMED. Solo los escritores de confianza producen estado DETERMINISTIC.
  2. Los efectos secundarios requieren reclamaciones. Cada efecto externo se reclama en un libro de contabilidad idempotente antes de dispararse. Los efectos no reclamados se bloquean en el límite, los duplicados se rechazan y los resultados inciertos generan una excepción para su reconciliación.
  3. La recuperación verifica contra la realidad. La reanudación comprueba los resúmenes de archivos, las versiones de dependencias y la identidad del modelo antes de declarar seguro. La obsolescencia se propaga dependency -> evidence -> finding -> decision más PlanStep.depends_on para que solo los pasos afectados se reparen.

Cinco puntos de integración

PuntoCómo conectarQué te proporciona
1 En procesoGenericAgentAdapter.intercept_action(...) y wrap_tool(key_fn=...) en LangChain, LangGraph, OpenAI Agents SDKMarcos de trabajo Python, escrituras de confianza
2 Servidor MCPcontinuum-mcp 13 herramientas sobre stdio (continuum_record_progress, continuum_intercept_action, continuum_complete_action, etc.)Cualquier cliente compatible con MCP, 3 de solo lectura + 10 de mutación, lista de permitidos CONTINUUM_MCP_MUTATING_CLIENTS
3 Hooks de ciclo de vida CLIcontinuum hooks install claude-code --with-gate también gemini y codexCLIs de codificación: SessionStart briefing, PostToolUse observe, PreToolUse gate; no se necesita CLAUDE.md
4 Puerta de enlace HTTP de aplicacióncontinuum gateway --port 8765 con .continuum/gateway.jsonCualquier lenguaje, cualquier HTTP saliente debe tener una reclamación, la puerta de enlace se liquida desde el código de estado real
5 Puente OpenTelemetrymake_span_processor(storage)Cualquier aplicación rastreada, los spans se convierten en evidencia TOOL_COMPLETED

Superficies de hook delgadas para CrewAI, AutoGen, Pydantic AI viven en adapters/thin.py sin requerir SDK.

Pipeline de aplicación: por qué no hay llamadas duplicadas ni inválidas

La puerta para observar el pipeline cierra la brecha en el límite del marco de trabajo. Esto es lo que ahorra tokens y costos y bloquea llamadas de herramientas inválidas.

PreToolUse hook                    PostToolUse hook
    |                                    |
    v                                    v
continuum gate                    continuum observe
    |                                    |
    |-- no claim? DENY (exit 2)          |-- TOOL_COMPLETED event:
    |   + instructions to claim          |     path, bytes, sha256 on disk now
    |                                    |
    |-- live claim? ALLOW                |-- disk checked status:
    |                                    |     verified / changed / missing
    v
agent performs effect
    |
    v
continuum_complete_action  (settled from reality, not from report)
    |
    v
ledger marked COMPLETED: next replay returns cached result, not a second fire

El host desconocido se deniega con cierre seguro, no es un relé abierto. Shell Bash/curl es el punto ciego documentado de v1.

Árbol de decisión de recuperación: semanas hasta terminar, correcto y exacto

El motor toma la señal más cautelosa, por lo que la seguridad nunca pierde ante la conveniencia.

RESUME < REPAIR_AND_RESUME < REPLAN < WAIT < REQUEST_HUMAN < ROLLBACK < ABORT

Cada continuum resume devuelve un contrato sellado con: estado de recuperación y safe, componentes verificados/invalidados, human_steps ejecutable (shell exacto para ejecutar), observaciones posteriores al checkpoint con disco verificado, deriva de fijación y agregación de familia para multiagente continuum tree. Briefing continuum briefing inyecta ese contrato en cada claude SessionStart fresco, por lo que decir hi después de matar la terminal se reanuda desde el último prefijo bueno.

Por qué esto ahorra tokens, costos y llamadas inválidas

  • Tokens: El checkpoint semántico almacena Goal + Plan + Progress no un volcado de transcripción. El briefing sirve solo el estado verificado más un resumen de razonamiento con tope de 4096, no la cola de errores que el autocondicionamiento muestra que degrada la siguiente sesión. El reintento informado recovery/summary.py inyecta un resumen redactado por el motor, no el historial crudo.
  • Costo: El libro de contabilidad action_index rechaza efectos secundarios duplicados incluso bajo deriva de argumentos como rutas relativas vs absolutas (clave estable invoice:INV-001), por lo que la misma API no se paga dos veces después de una reanudación. Los presupuestos budgets.py limitan las tormentas de reintentos en el momento de la reclamación. continuum benchmark imprime 0 duplicates para continuum vs 50 para ingenuo.
  • Llamadas inválidas: La puerta y la puerta de enlace y replayguard langgraph_protected_node bloquean llamadas de herramientas no reclamadas o reproducidas antes de que se disparen. La fijación pinning.py revela deriva de prompt o herramienta en la reanudación.

Arquitectura de almacenamiento

Esquema v6. SQLite es primario, Postgres está verificado por CI. Un registro, muchas proyecciones.

TablaPropósito
eventsRegistro de solo apéndice encadenado por hash (55 tipos de eventos en v0.2)
runsMetadatos de ejecución con parent_run_id para multiagente
versionsInstantáneas de SemanticState por checkpoint
checkpointsRegistros de checkpoint sellados con anclas RECOVERY
action_indexProyección de idempotencia entre ejecuciones (esquema v3+): lecturas indexadas, no escaneos completos
events_archiveAlmacenamiento de prefijo compactado (esquema v5+): continuum compact limita el registro en vivo durante semanas
lg_checkpoints / lg_writesPersistencia nativa de LangGraph (esquema v4+): make_continuum_checkpointer(storage)

Mapa de módulos: una biblioteca, muchas superficies

CONTINUUM es una biblioteca (src/continuum, 148 módulos) más una gran suite de pruebas (210 archivos de prueba, ~3680 pruebas). Todos los módulos añaden y reproducen un registro de eventos encadenado por hash:

MóduloRol
events.pyRegistro de eventos de solo apéndice encadenado por hash y verify() trusted_through
state/Proyección project(), validación, extracción: propagación de obsolescencia
storage/SQLiteStorage v6, postgres.py, migrations.py, actionindex.py
actions/Libro de contabilidad idempotente claim/complete/reconcile, clave idempotency.py + canonicalización + respaldo de token, seguimiento de concesiones consumidas GRANT_DENIED
checkpoint/Checkpoints impulsados por políticas manager.py policy.py con anclas RECOVERY y prune
recovery/Motor, planificador, contrato sellado contract.py, guidance human_steps, observations disco verificado, family rollup, semántica fork, reintento informado summary
gate.pyAplicación previa al uso de herramientas: permitir o denegar contra reclamaciones del libro de contabilidad
gateway.pyProxy HTTP de aplicación: reclamar antes de disparar para solicitudes salientes
replayguard.pyGuardia portátil: evaluate, protected_call, langgraph_protected_node: cierra el riesgo de reproducción de ACRFence
hooks.py clienthooks.pyHooks de checkpoint compartidos y perfiles de instalador claude-code gemini codex
budgets.pyRegistro de presupuesto de reintentos y evaluación por tipo de acción
pinning.pyNormalización de fijación de versiones y detección de deriva en la reanudación
replay_similarity.pyBackends de similitud semántica exacto/difuso/embedding para reproducción vs bifurcación
reconcilers.pyRegistro de sondas .continuum/reconcilers.json para liquidación automática
adapters/9 adaptadores de clase + hooks delgados thin.py CrewAI AutoGen Pydantic AI + almacén LangGraph
mcp/13 herramientas stdio más autorización authz.py autenticación de token, lista de permitidos, token de confirmación
serve/Cable JSON stdio sidecar + HTTP CONTINUUM_SERVE_TOKEN
dashboard/Panel web app.py hitl.py con botones HITL confirmar/reconciliar/completar, aviso de confianza de prefijo, fijaciones
cli/54 comandos argparse, códigos de salida como veredicto: runs, start, inspect, resume, verify, health, tree, benchmark, attest, lineage-issue, lineage-verify, dashboard
otel.pyPuente de procesador de spans OpenTelemetry
benchmark/Marco de trabajo CONTINUUM-Bench: 5 escenarios de fallo + deriva de argumentos + suite de recuperación de 14 escenarios + inyección de 7 fallos de riesgo

Limitaciones honestas

  • La puerta no ve dentro de los comandos de shell (Bash/curl evaden las reclamaciones de herramientas estructuradas)
  • El backend Postgres está probado por CI pero no probado en batalla en producción
  • Un nivel de jerarquía multiagente en v1
  • Descarga de cargas útiles grandes (#254) aún no implementada
  • El benchmark a escala de semanas con tabla de costos de tokens aterriza en el tablero #550 (#568 a #570)

Referencia completa en references/architecture.md. Y el plano de meses que se construye sobre esto (grafo causal de procedencia, resurrección de autoridad, admisibilidad, vivacidad) está fijado como tablero #550 con 20 subproblemas #551 a #570.

API y CLI

La superficie de Python (EventType, Run, SQLiteStorage, diff_states, project) y la API de adaptadores están documentadas con ejemplos ejecutables en references/api.md. La CLI es la misma superficie en forma de shell:

continuum runs                                   # list runs
continuum inspect <run_id>                       # semantic state
continuum validate <run_id> --env dataset=v4     # validate, read-only
continuum resume <run_id> --env dataset=v4       # recovery decision + contract + next steps
continuum checkpoint <run_id>                    # force a checkpoint, mutates
continuum actions <run_id>                       # external side effects
continuum reconcile <run_id>                     # settle uncertain effects with probes
continuum complete <run_id>                      # close a run as done, from the keyboard
continuum verify <run_id>                        # re-audit the event hash chain
continuum budget <run_id>                        # retry-budget usage per action type
continuum compact <run_id>                       # archive pre-anchor log prefix
continuum tree <parent_run_id>                   # show parent + children with recovery states
continuum attest <run_id> --key signer.pem       # sign the chain head for an external verifier

Todo el cableado está en el lado del host; la cooperación del modelo es opcional:

continuum hooks install claude-code --with-gate   # coding CLIs: evidence, briefing, gate
continuum gateway --port 8765                     # enforcing HTTP proxy for everything else
provider.add_span_processor(continuum.otel.make_span_processor(storage))  # OTel to evidence
continuum-mcp                                     # anything MCP-capable: the twelve-tool server
continuum briefing                                # session-start context injection
continuum budget <run_id>                         # retry-budget usage report
continuum tree <parent_run_id>                    # multi-agent hierarchy view

Los registros opcionales viven junto a tu código y son datos, no código: .continuum/gate.json (herramientas de efectos secundarios + plantillas de clave estable), .continuum/reconcilers.json (sondas que verifican sistemas externos), .continuum/gateway.json (rutas ascendentes).

La mayoría de los comandos aceptan --json global antes del subcomando (por ejemplo, continuum --json resume RUN), y los comandos de solo lectura nunca escriben, por lo que son seguros contra una base de datos en vivo mientras un agente está en medio de una ejecución. Las dos excepciones son solo de auditoría y se disparan únicamente para una ejecución que ya está estacionada: resume registra el resultado de la entrega de su webhook cuando el veredicto es REQUEST_HUMAN y un endpoint está suscrito, y watch registra un cambio de veredicto de vivacidad; ninguno añade proyecciones al estado ni mueve el código de salida. Los códigos de salida son un contrato de seguridad (solo una ejecución verificada como segura sale con 0). Lista completa de comandos, tabla de códigos de salida y salida de diff de estado en references/cli.md.

Hoja de ruta

FaseComponenteEstado
1-11Modelos de datos, estado semántico, persistencia, checkpointing, validación, libro de contabilidad de acciones, motor de recuperación, CLI, ejemplos de recuperación de fallos, instantáneas/diffs de entorno, adaptadores de marco de trabajoCompleto
12Suite de benchmark (CONTINUUM-Bench)Completo (marco mínimo)
13API en la nube (FastAPI + PostgreSQL)Parcial: el backend de almacenamiento PostgreSQL y el transporte sidecar HTTP (continuum serve --transport http) están enviados y probados por CI; el servicio multiinquilino alojado no ha comenzado
14Panel de controlCompleto (continuum dashboard)
15+Durabilidad aplicada: hooks de observación, puerta, briefing de sesión, sondas de reconciliador, puerta de enlace de aplicación, puente OTel, índice de acciones, guía ejecutable, instaladores multicliente, detección de reproducción semántica, fijación de versiones, presupuestos de reintentos, compactación de registros, superficie HITL, semántica de bifurcación, reintento informado, agregación multiagenteCompleto (ver problema #213)
SiguientePlano de durabilidad a escala de meses: planes anclados a hitos (#312), memoria de intentos estructurada (#313), rebobinado atómico de doble estado (#292), benchmark público de corrección de recuperación (#293)Planificado (borrador de especificación en docs/UPGRADE_SPEC.md); notificaciones webhook-out (#305) enviadas

Más allá del plan original: el servidor MCP, las capas de autorización MCP y autenticación de llamantes, procedencia y anti-autocertificación, archivos comunitarios, versionado de esquemas con migraciones hacia adelante, un contexto de recuperación limitado, seguimiento de concesiones consumidas, atestación de cadena de eventos Ed25519, el checkpointer nativo de LangGraph y artefactos wheel en cada push a main están enviados. Ver STATUS.md para el desglose verificado-vs-creído y errores de corrección abiertos.

Lo que CONTINUUM No Es

No estoEsto en su lugar
Un LLMUna capa de confiabilidad para agentes que usan LLMs
Un framework de agentesUna capa de recuperación que se conecta a cualquier framework
Una base de datos vectorialEstado semántico estructurado, no embeddings
Un sistema RAGCheckpoints verificados, no memoria aumentada por recuperación
Un motor de flujo de trabajoUna capa de recuperación, no un orquestador

La abstracción central: semantic state + environment validation + action reconciliation = safe recovery.

El veredicto es informativo, no impuesto

CONTINUUM te dice la verdad sobre una ejecución. No detiene tu proceso cuando la respuesta no es deseada. RecoveryDecision.permits() informa lo que el contrato permite; nada en la biblioteca interviene si un llamador ignora un False y actúa de todos modos. Un trabajador que llama a CheckpointManager.restore directamente puede continuar más allá de un veredicto REQUEST_HUMAN, porque nunca le preguntó al motor si debía hacerlo.

Este es un contrato deliberado para una biblioteca: forzar la aplicación dentro de una llamada que el llamador hizo para inspeccionar un veredicto sorprendería a los llamadores que legítimamente quieren leerlo y luego anularlo.

La aplicación existe, pero como mecanismos separados que puedes optar por activar. Ninguno está habilitado por un pip install continuum-agent simple:

MecanismoCómo habilitarlo
Puerta del hostcontinuum gate
Puerta de enlace HTTPcontinuum gateway
Protección de reproducción para llamadas de frameworkcontinuum.replayguard en proceso
Hooks de observacióncontinuum hooks install

La única aplicación que viene habilitada es el código de salida de la CLI. continuum resume sale con código distinto de cero a menos que la ejecución esté verificada como segura (RESUME), por lo que continuum resume "$RUN" && ./start-agent.sh no puede lanzarse sobre estado obsoleto. Cada otro modo se asigna a un código distinto de cero, y un modo que nadie ha clasificado cae en UNSAFE en lugar de OK.

Si quieres que el veredicto se aplique, conecta un mecanismo o condiciona tu pipeline al código de salida. No asumas que la biblioteca está supervisando el proceso.

Trabajo relacionado

CONTINUUM se sitúa en la intersección de la ejecución duradera, el seguimiento de efectos secundarios idempotentes y la recuperación ante fallos para agentes LLM. Los vecinos más cercanos son los contratos de reanudación verificados por máquina (Khan 2026), el procesamiento de transacciones agénticas con admisión restringida por restricciones (Mnemosyne 2026), el análisis de ataques de checkpoint-rollback (ACRFence 2026) y la defensa contra inyección de prompts a nivel de diseño (CaMeL 2025). La lista anotada completa, los fundamentos y la auditoría de citas están en references/related-work.md.

Estado y limitaciones

  • Probado: 3,680 recopilados, la mayoría pasan; las omisiones exactas varían en una ejecución completa en la auditoría del 2026-08-24 de este árbol; CI aplica la suite en Python 3.11, 3.12 y 3.13, y los conteos varían según la plataforma y los servicios opcionales como Postgres (ver STATUS.md). La superficie MCP también ha sido auditada de manera adversaria sobre el protocolo en vivo; ver test.md.
  • En PyPI como continuum-agent 0.1.2 (pip install continuum-agent; el clon aún funciona vía pip install . ver Quick Start).
  • La autenticación del llamador MCP es opcional por implementación. Cuando CONTINUUM_MCP_TOKEN está configurado, el servidor rechaza cada herramienta mutadora a menos que el llamador presente ese secreto compartido en el initialize del handshake _meta.authToken; los secretos por llamador están disponibles vía CONTINUUM_MCP_CLIENT_TOKENS (pares name:secret). Sin ningún token configurado, la autorización es solo por identidad declarada (el valor predeterminado histórico, preservado para uso local de un solo usuario).
  • Confirmar el estado autoinformado a través de MCP requiere un secreto separado. continuum_confirm rechaza a cada llamador hasta que el operador configure CONTINUUM_MCP_CONFIRM_TOKEN, porque un agente autorizado para registrar progreso no debe poder confirmarlo también. La ruta predeterminada sigue siendo impulsada por humanos: ejecuta continuum confirm <run_id> en el host.
  • Componentes no construidos: Cloud API (Fase 13).
  • Brecha en la aplicación de comandos de shell: la puerta aplica afirmaciones para llamadas de herramientas estructuradas pero no puede ver dentro de comandos Bash/curl. Documentado como rechazo de alcance v1.
  • Los adaptadores de framework siguen siendo experimentales. Los tres adaptadores de framework ahora llevan pruebas de soft-resume y hard-crash con modelos en vivo (OpenRouter, gpt-4o-mini), incluido el contrato de crash que bloquea la reanudación ante un efecto secundario incierto, y ahora tienen pruebas de verificación de crash-and-resume que logran paridad con la fachada genérica (Refs #285). Prefiere GenericAgentAdapter para recuperación en producción.
  • Las ejecuciones de agente/MCP necesitan una confirmación explícita antes de la auto-reanudación. El estado reportado externamente es REQUIRES_REVIEW, por lo que continuum resume devuelve request_human hasta que un humano confirme. Por diseño, no es un error; ver Framework Integration.
  • Serie de pruebas de autonomía e2e (issue #6): tres ejecuciones completas de Claude Code obtuvieron 7/7 en mecánica con comportamiento de recuperación no solicitado observado. Iteraciones adicionales en diversos estilos de prompts siguen abiertas.

Acerca de

A principios de 2026 vi agentes de larga duración fallar en la recuperación, no en el razonamiento. Los checkpoints se trataban como prueba para continuar, no como evidencia para verificar. Al revisar Temporal, LangGraph, ACRFence 2603.20625 y self conditioning 2509.09677, encontré que la brecha era un sustrato de verificación portátil que pregunta, dado el estado en el tiempo T y el mundo tal como es ahora, ¿sigue siendo seguro continuar?

Durante tres semanas construí CONTINUUM a partir de un invariante: cada hecho lleva su origen. El resultado es un registro encadenado por hash con verify(), un libro mayor con deduplicación de claves estable, una puerta y una puerta de enlace que bloquean efectos no reclamados, y un motor de recuperación que sella un contrato. Cinco mecanismos exponen el mismo registro a Claude Code, LangGraph, LangChain, OpenAI, HTTP y OpenTelemetry. Validado con muertes reales y ~3680 pruebas, imprime 0 duplicates donde la reproducción ingenua imprime 50.

CONTINUUM fue creado por Anandhu P Shaji (@Cyrax321 · LinkedIn) y es mantenido por el creador original. Es de código abierto bajo la licencia Apache-2.0. Las contribuciones de la comunidad son bienvenidas vía CONTRIBUTING.md y se acreditan en AUTHORS.md y graphs/contributors.

Contribuir

Este proyecto es de código abierto bajo Apache 2.0 y está deliberadamente construido para ser extendido: por investigadores que validan la semántica de recuperación, por ingenieros que portan el libro mayor o el servidor MCP a otros frameworks o lenguajes, y por cualquiera que convierta la hoja de ruta planificada en realidad. Un buen lugar para comenzar es la etiqueta good first issue en el rastreador de issues, o los errores de corrección abiertos listados en STATUS.md.

Abre un issue antes de enviar PRs grandes. Ver CONTRIBUTING.md para la guía completa de contribución, incluido el Código de Conducta.

Contribuyentes

Gracias a nuestros contribuyentes de la comunidad, ordenados por contribuciones: @Adhi1-2, @abyyxhek, @Amiirhosseini, @yuki-fuyutsuki, @vjymisal0, @adity982, @dchaudhari7177, @tasodoufu, @anya-research, @lesbass, @Parthipashok04, @Samearth17, @stoppo22, @timothyanderson096-ocdealcheck, @unmoha, @aastha-m22, @as950118, @asarakhatun17-lgtm, @challenge456, @gouthamkrishnak2003, @ItzSaurav, @mhaye9545, @Newer1107, @okestroHjJeong, @quangshuynh, @Rahul-pamula, @Shaisolaris, @VedantMadane, @zynx-real.

Patrocinador

Si CONTINUUM ayuda a tus agentes a recuperarse de manera confiable, considera patrocinar para apoyar el mantenimiento a largo plazo.

Sponsor Cyrax321

Conviértete en patrocinador: GitHub Sponsors, o agrega un enlace personalizado en FUNDING.yml si prefieres otra plataforma.

Licencia

Apache 2.0 - ver LICENSE.


Material de referencia profunda:

Enlaces rápidos