Arquitectura del núcleo de BeeverForge
Modelo de extensión
Cada dependencia externa del núcleo, salvo el motor, Temporal, está detrás de un adaptador, y cada adaptador lo elige un registro a partir de la configuración. Un proveedor nuevo se añade instalando un paquete que declara un punto de entrada, sin cambiar el núcleo.
Ejes#
Un eje es un tipo de cosa con la que se puede extender el núcleo. La lista publicada es AXES en beeverforge/plugins.py:
tracker board forge ci harness box event metrics channel
notifier identity role session_store token_pool box_runner
credential board_setup extract embed preview credential_store
Una prueba mantiene esta lista exactamente igual a lo que piden los registros, y otra comprueba que cada registro consulta el cargador de puntos de entrada.
| Eje | Tipos incluidos |
|---|---|
harness | claude_code, codex, kimi, opencode |
tracker | local, github, jira, azure_devops |
board | local, github, jira, azure_devops |
forge | local, github, azure_devops |
ci | none y local, github y github_actions, azure_devops y azure_pipelines; cada par designa un mismo observador |
box | container, worktree, fargate (solo descripción; su ejecutor es un complemento) |
box_runner | Ninguno |
channel | panel |
notifier | panel |
identity | local, oidc |
metrics | null, sqlite, memory |
preview | compose, none |
credential_store | env, file |
El grupo de puntos de entrada#
- Un paquete declara sus adaptadores en un único grupo de puntos de entrada,
beeverforge.adapters. Cada nombre es<axis>.<kind>, por ejemploforge.gitlab. Un nombre con cualquier otra forma se omite con una advertencia que muestra la forma esperada. - Carga diferida. Los registros buscan primero en su propia tabla. Los puntos de entrada se cargan una vez, en la primera búsqueda de un tipo que no está incluido, y se guardan en caché; un despliegue que solo usa tipos incluidos nunca carga ninguno. Listar los complementos instalados lee los metadatos de los paquetes sin importarlos.
- Un complemento defectuoso se registra en el log y se ignora; los demás se siguen cargando.
- Los incluidos ganan una colisión. Declarar
forge.githubno sustituye la fila incluida: responde la incluida y la colisión se registra en el log. Un complemento no puede cambiar lo que significa un tipo existente para todos los proyectos de un despliegue. - Un tipo desconocido provoca un rechazo que lo nombra. El registro lanza un error con el tipo, los tipos conocidos y, cuando el tipo pertenece a un paquete complementario conocido, qué paquete lo incluye. Nunca recurre a un proveedor predeterminado.
Nacer con dos#
ADR-0022 fija el listón: un eje es agnóstico no porque declare una interfaz, sino cuando nace con más de una implementación y un punto de unión que despacha entre ellas. Los protocolos son @runtime_checkable y las pruebas los comprueban con isinstance.
La regla no se cumple hoy en todos los ejes. Los ejes channel, notifier, session_store y token_pool tienen un solo tipo incluido cada uno, y box_runner no tiene ninguno. Ninguna prueba exige dos tipos incluidos por eje; existen pruebas por eje para los ejes preview y credential_store.
Conformidad de adaptadores#
beeverforge conformance-adapter <kind> <factory> ejecuta un adaptador contra la suite de conformidad de la plataforma, beeverforge/conformance/adapters.py. La función fábrica (factory) es una ruta de importación, pkg.module:attr, que nombra una instancia, una clase o una función que devuelve una.
- Las comprobaciones son funciones simples que devuelven hallazgos. No construyen nada remoto ni cambian nada remoto; ejercitan el contrato local: firmas, reglas de degradación y la forma de los rechazos.
- Hay comprobaciones para canales, notificadores, identidad, tableros, trackers, plataformas Git, harnesses, observadores de CI, cajas y vistas previas.
- Ejemplos: una lectura de un tracker debe devolver
Nonecuando no pudo leer y una lista vacía cuando no hay nada; una plataforma Git debe enviar una credencial solo al host que la emitió; la comprobación de salud de un observador devuelve un booleano y nunca lanza errores.
beeverforge conformance <project> es un comando distinto: comprueba el manifiesto de un proyecto, no un adaptador.
El stack no necesita adaptador#
El núcleo no nombra ninguna herramienta de compilación. Las entradas setup: y validate: del manifiesto son comandos de shell, y la caja ejecuta cada uno tal como está escrito: sh -c en un contenedor, un shell en un worktree. Un proyecto en cualquier lenguaje se admite declarando sus propios comandos, sin adaptador.
Ejemplo: un complemento de notificación#
De docs/writing-an-addon.md. El paquete declara un punto de entrada:
[project.entry-points."beeverforge.adapters"]
"notifier.acme" = "beeverforge_acme:build_notifier"
e implementa lo que el núcleo llama:
class AcmeNotifier:
def notify(self, *, message: str, level: str = "info",
about: str = "") -> str | None:
... # your provider
return None # or the provider's own handle for the message
def build_notifier(project=None, **_kw):
return AcmeNotifier()
Cada eje llama a su constructor con sus propios argumentos; la guía los enumera por eje y explica cómo una fila declara su nombre visible y las soluciones que el núcleo muestra para ese proveedor.
Fuentes#
beeverforge/plugins.pybeeverforge/adapters/forge/registry.pybeeverforge/adapters/agent/registry.pybeeverforge/adapters/sandbox/registry.pybeeverforge/adapters/environment/registry.pybeeverforge/conformance/adapters.pybeeverforge/cli.pybeeverforge/orchestrator/validation.pydocs/writing-an-addon.mddocs/core/07-extensibility.mdtests/test_a_stranger_can_add_an_adapter.py- ADR-0022, ADR-0034