Saltar a contenido

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, ResourceBuilder o FormBuilder.
  • Necesitas un ejemplo completo de CRUD CUS sin copiar un plugin de negocio.
  • Quieres ver el contrato PluginDescriptor y 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:

[project.entry-points."cortex.panels"]
samples = "cortex_plugin_helloworld:configure_panel"

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.pyAPI 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:

CORTEX_ENABLED_PLUGINS=template,helloworld uv run uvicorn cortex_framework.main:app

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.