Anatomía de un plugin¶
Estructura canónica de un plugin de dominio. La plantilla vive en plugins/_template/ (repo cortex-plugin-template).
Árbol de archivos¶
plugins/{id}/
├── pyproject.toml # entry point cortex.plugins
├── cortex_plugin_{id}/
│ ├── __init__.py # reexporta create_plugin + hooks
│ ├── plugin.py # SPI: descriptor, api_router, resource_paths
│ ├── resources.py # register_resources (CUS)
│ ├── store.py # persistencia o fixtures
│ ├── validators.py # opcional
│ ├── mcp_tools.py # opcional
│ ├── configuration/
│ │ └── manifest.json # settings por panel (opcional)
│ ├── fixtures/ # datos de desarrollo (opcional)
│ └── ui/ # JSON legacy si no usas ResourceBuilder
│ ├── manifest.json
│ └── dashboards/
├── alembic/ # migraciones si persiste en PG
├── tests/
│ └── test_*.py
└── docs/ # documentación de dominio del plugin
├── README.md
├── api.md
└── dependencies.md
Piezas y responsabilidades¶
| Pieza | Responsabilidad | Hook / API |
|---|---|---|
pyproject.toml | Nombre del paquete, dependencias, entry point | cortex.plugins |
plugin.py | REST bajo /api/v1/{namespace} | api_router(), create_plugin() |
resources.py | Pantallas declarativas (list/create/edit) | register_resources |
store.py | Acceso a datos (PG, fixtures, memoria) | Llamado desde plugin.py |
configuration/manifest.json | Ajustes por panel | Cargado en bootstrap; hook register_configuration opcional |
tests/ | Contrato HTTP y registro CUS | create_test_app(enabled_plugins=...) |
docs/ | Comportamiento de dominio | Fuera de cortex-docs |
__init__.py — contrato de exportación¶
El loader importa el módulo raíz del paquete. Reexporta todo lo que el framework debe invocar:
from cortex_plugin_template.plugin import create_plugin
from cortex_plugin_template.resources import register_resources
__all__ = ["create_plugin", "register_resources"]
Si un hook no está en __all__ ni es atributo del módulo importado, el loader no lo ejecuta.
plugin.py — capa HTTP¶
Responsabilidades:
- Definir
PluginDescriptorcon id, versión y dependencias. - Montar rutas REST con prefijo coherente (
/api/v1/{id}/...). - Delegar persistencia a
store.pyu otro servicio. - Devolver segmentos en
resource_paths()para validación CUS.
Referencia mínima: plugins/_template/cortex_plugin_template/plugin.py. Ejemplo CRUD completo (sandbox): plugins/helloworld/cortex_plugin_helloworld/resources.py — ver API interna del framework. Ejemplo CRUD completo (sandbox): plugins/helloworld/cortex_plugin_helloworld/resources.py — ver API interna del framework.
resources.py — capa UI declarativa¶
Registra un módulo en un namespace de panel:
O con registro directo (como en el template):
El panel_id y module_id determinan rutas UI (/operations/template/...) y endpoints de manifest (GET /api/v1/panels/operations/modules/template/manifest).
docs/ — documentación del plugin¶
Toda regla de negocio, tabla de endpoints detallada, eventos y runbooks viven aquí. El handbook de plataforma solo enlaza.
Estructura sugerida: ver Documentación framework vs plugins.
Workspace uv¶
En el monorepo cortex-hive, cada plugin es submódulo bajo plugins/ y miembro del workspace en el pyproject.toml raíz. Sin git submodule update --init, el discovery no encuentra el paquete.
Flujo git: Repositorios y submódulos.
Checklist antes del primer commit¶
- [ ] Entry point
cortex.pluginsapunta acreate_plugin - [ ] Hooks reexportados en
__init__.py - [ ]
list_pathen CUS coincide con ruta enapi_router() - [ ]
docs/README.mdcon propósito y dependencias - [ ] Tests con
create_test_app
Ver Checklist CI y TDD.
Siguiente paso¶
Integración con el framework — cómo el loader ensambla tu plugin en la API y el shell React.