API interna del framework¶
Referencia canónica del API interno que un plugin usa para registrar UI, formularios y metadata SPI. No documenta rutas REST públicas; para HTTP ver API REST.
El código vivo está en plugins/helloworld/ (cortex-plugin-helloworld): sandbox de plataforma con plugin_id helloworld y panel samples. No es plugin de dominio en el catálogo docs/plugins/.
Cuándo leer esta página¶
- Implementas
register_resources,ResourceBuilderoFormBuilder. - Necesitas un ejemplo completo de CRUD CUS sin copiar un plugin de negocio.
- Quieres ver el contrato
PluginDescriptory los hooks opcionales del loader.
Mapa SPI → UI¶
flowchart LR
subgraph spi [SPI plugin]
Desc[PluginDescriptor]
Hooks[register_resources register_forms]
end
subgraph ui [API interna UI]
RB[ResourceBuilder]
FB[FormBuilder]
RR[register_resource]
end
subgraph runtime [Framework]
Loader[load_plugins]
Reg[ResourceRegistry FormRegistrar]
end
Desc --> Loader
Hooks --> Reg
RB --> RR --> Reg
FB --> Hooks PluginDescriptor¶
El plugin sandbox declara identidad y paneles que contribuye:
descriptor = PluginDescriptor(
"helloworld",
"Hello World",
"0.1.0",
provides=("helloworld",),
contributes_panels=("samples",),
stateless=True,
)
| Campo | Sandbox helloworld | Notas |
|---|---|---|
plugin_id | helloworld | Entry point cortex.plugins |
contributes_panels | ("samples",) | Panel dedicado vía cortex.panels |
provides | ("helloworld",) | Capability en grafo de dependencias |
stateless | true | Sin migraciones Alembic |
plugin_id y panel_id pueden diferir: el toggle en /control/plugins usa helloworld; la UI vive bajo /samples/.
Cuando el plugin tiene entry point cortex.panels para un panel que contribuye (mismo paquete Python), el framework delega register_resources / register_forms al ciclo del panel host y evita doble registro. Los plugins que solo inyectan módulos en operations / admin siguen registrando UI desde el hook del plugin.
register_resources + ResourceBuilder¶
CRUD To-Do completo en panel samples:
from cortex_framework.ui import ResourceBuilder, register_resource
from cortex_framework.ui.registry import ResourceRegistry
def register_resources(registry: ResourceRegistry) -> None:
def configure_todo(builder: ResourceBuilder) -> None:
(
builder.id("todo")
.title("To-Do")
.api_base("/api/v1/samples/todo")
.list_path("/api/v1/samples/todo")
.create_path("/api/v1/samples/todo")
.record_title_attribute("title")
.search_path("/api/v1/samples/todo")
.nav_group("samples", nav_sort=10)
.pages(list=True, create=True, edit=True, view=True)
.table(
lambda t: t.columns(
lambda c: (
c.text("title", "Título", sortable=True, searchable=True)
.boolean("completed", "Completada")
)
)
.filters(lambda f: f.ternary("completed", "Completada", field="completed"))
.actions(
lambda a: (
a.create("", "Nuevo")
.edit("/api/v1/samples/todo/{id}/edit", "Editar")
.view("/api/v1/samples/todo/{id}", "Ver")
.delete("/api/v1/samples/todo/{id}", "Eliminar")
)
)
.default_sort("-title")
)
.form(
lambda f: f.text("title", "Título", required=True).toggle("completed", "Completada")
)
.infolist(lambda i: i.text("title", "Título").badge("completed", "Completada"))
)
register_resource(registry, "samples", "todo", configure_todo)
Parámetros de register_resource(registry, panel_id, module_id, configure):
| Parámetro | Sandbox | Descripción |
|---|---|---|
panel_id | samples | Namespace de panel |
module_id | todo | Segmento en navegación y rutas |
configure | callback | Recibe ResourceBuilder encadenado |
Profundizar: Recursos.
register_forms + FormBuilder¶
Formulario mínimo (todo) y demo de todos los tipos de campo (form-demo):
from cortex_core.registrar import FormRegistrar
from cortex_core.spi import FormDefinition, FormField, FormFieldType
from cortex_framework.ui.fields import FormBuilder
from cortex_framework.ui.form_builder import build_form_definition
def register_forms(registry: FormRegistrar) -> None:
registry.register(
FormDefinition(
form_id="todo",
title="To-Do",
fields=(
FormField("title", FormFieldType.STRING, "Título", required=True, order=0),
FormField("completed", FormFieldType.BOOLEAN, "Completada", order=1),
),
)
)
registry.register(
build_form_definition(
form_id="form-demo",
title="Form demo",
builder=_form_demo_builder(),
)
)
Consulta el formulario demo en runtime: GET /api/v1/forms/form-demo.
Profundizar: Form fields.
Panel dedicado (cortex.panels)¶
Entry point separado del dominio:
configure_panel usa PanelBuilder para path /samples, scopes y layout slots (stat-card, actions-bar). El host (create_panel_host) monta el router REST del namespace.
Ver Namespaces y paneles y plugins/helloworld/cortex_plugin_helloworld/provider.py.
Hooks opcionales¶
El loader invoca estos hooks si el módulo los exporta en __init__.py:
| Hook | Uso | Documentación |
|---|---|---|
register_widgets | Widgets en home del panel | Widgets |
configuration/manifest.json | Settings por panel | Configuración |
register_mcp_tools | Tools para agentes MCP | MCP y WebSocket |
register_ws_namespaces | Push bidireccional | MCP y WebSocket |
register_listeners | Reaccionar a eventos | Eventos de dominio |
register_reports | Exportes en panel | ADR 020+ |
El sandbox helloworld implementa dashboard home, stats + chart en el listado To-Do, configuración (/samples/configuration) y CRUD con rutas UI correctas (create, :id/edit).
Qué no cubre esta página¶
- Rutas FastAPI en
plugin.py→ API REST - Composición de producto o bundles pip → ADR 025
- Catálogo de dominio en
docs/plugins/— helloworld está fuera a propósito
Activar el sandbox¶
En desarrollo:
UI: /samples/todo. API: /api/v1/samples/todo. Control: /control/plugins → plugin helloworld.
Siguiente paso¶
Primer plugin — crear un módulo de negocio real a partir de _template.