skill-siag skill

v1.0.1 · Agent Skill · pascalai · registry.pascalai.org

Guia de operacion de SIAG (motor de indicadores/BI de PascalAI) para agentes: el DSL de lectura (QUERY/DRILL/INSPECT/NAVIGATE), el de escritura, trampas verificadas (LAST anclado a hoy, LIMIT cambia la forma de la respuesta, sin DROP INDICATOR) y el mapa de operaciones de mcp-siag/mcp-siag-query. Companion skill de los paquetes mcp-siag y mcp-siag-query.

siagbianalyticsindicadoresdslseriesdrillagentmcp-siagskill

Install

ppm install skill-siag
ppm skill install-claude

The second command activates the skill in Claude Code (copies it into .claude/skills/).

Skill content (SKILL.md)

SIAG — guía de operación para agentes

El sistema

SIAG es un motor de indicadores sobre series de tiempo. Backend Delphi/DataSnap REST (/datasnap/rest/TSigServerMethods), datos en PostgreSQL/TimescaleDB.

El modelo tiene tres piezas:

Multi-tenant: la autenticación fija el tenant y su entidad (el schema de datos). Nunca se pasa el tenant en la consulta.

Los MCP

Server Uso
siag-query (mcp-siag-query) Solo lectura. Preferirlo siempre para consultar. Rechaza verbos de escritura del lado del cliente, antes de enviar.
siag (mcp-siag) Full: escrituras del DSL + CRUD de configuración. Usarlo solo cuando la tarea exige modificar. Las escrituras exigen rol=admin en el servidor.

Ambos exponen un solo tool con un parámetro operation y (según la operación) dsl.

La autenticación es automática por variables de entorno (SIAG_URL/SIAG_EMAIL/SIAG_PASSWORD/SIAG_TENANT); el token nunca pasa por el modelo.

Regla #1: INSPECT antes de consultar

Los nombres de tablas, medidas, dimensiones e indicadores son distintos en cada instalación. No los inventes ni los adivines. Empieza siempre por:

INSPECT INDICATORS          -- nombre, fórmula, unidad, grupo de cada indicador
INSPECT TABLES              -- tablas de hechos con su descripción
INSPECT DIMENSIONS OF <tabla>
INSPECT DATA RANGE OF <tabla>   -- desde / hasta / total_registros

INSPECT DATA RANGE es especialmente importante: dice hasta qué fecha hay datos, y eso condiciona qué períodos tiene sentido pedir (ver Trampa #1).

Otras formas: INSPECT INDICATOR <nom>, INSPECT TABLE <nom>, INSPECT VALUES OF DIMENSION <dim> INTO <tabla>, INSPECT DEPENDENCIES OF <indicador>.

El DSL de lectura

Cuatro verbos: QUERY, DRILL, INSPECT, NAVIGATE.

Cláusulas compartidas por QUERY y DRILL

Se pueden combinar en cualquier orden:

FILTER <dim>=<val> [AND <dim>=<val> ...]
PERIOD <año>  |  FROM <año> TO <año>  |  LAST <n> MONTHS  |  LAST <n> YEARS
GRANULARITY MONTHLY | YEARLY

QUERY — una serie de tiempo

QUERY <indicador>                       -- o <tabla>.<medida>
QUERY ingresos PERIOD 2024 GRANULARITY MONTHLY
QUERY ingresos PERIOD 2024 GRANULARITY YEARLY FILTER region=NORTE
QUERY margen_pct FROM 2022 TO 2024 GRANULARITY YEARLY

Devuelve {indicador, granularidad, puntos, series:[{t,v}]}.

DRILL — abrir un indicador

Dos modos, con respuestas de forma distinta:

DRILL <target> BY DIMENSION <dim> [CHILDREN OF <cod>]
DRILL <target> BY FORMULA [DEPTH n] [THEN BY DIMENSION <dim>]

BY DIMENSION reparte el valor entre los valores de la dimensión. BY FORMULA descompone el indicador en los términos de su fórmula — devuelve un árbol con la serie de cada componente. Excelente para explicar por qué se movió un indicador.

<target> puede ser un indicador o tabla.medida. Acepta además LIMIT n.

NAVIGATE — recorrer dimensiones jerárquicas

NAVIGATE <tabla> DIMENSIONS [FILTER ...]     -- qué dimensiones tiene
NAVIGATE <tabla> DIMENSION <dim> [FILTER ...]
NAVIGATE <tabla> DIMENSION <dim> ROOT        -- nivel raíz de un árbol
NAVIGATE <tabla> DIMENSION <dim> FROM <cod>  -- hijos de un nodo

Para dimensiones con es_arbol: true, NAVIGATE es la forma correcta de bajar nivel por nivel en vez de pedir todo de una vez.

Trampas verificadas

#1 — LAST n se ancla a HOY, no a los datos

LAST 24 MONTHS cuenta hacia atrás desde la fecha actual. Si los datos terminaron hace tiempo, el resultado sale vacío o —peor— parcial y sin avisar: en una instalación con datos hasta 2024-11 consultada en 2026, QUERY ingresos LAST 24 MONTHS GRANULARITY YEARLY devolvió 2024 = 6.183.486, que parece la cifra anual pero son solo 4 meses; el año completo era 15.396.878.

Regla: para cualquier cifra que vayas a reportar como anual usa PERIOD o FROM..TO. Reserva LAST n para "los últimos n meses" literales, y verifica antes con INSPECT DATA RANGE OF.

#2 — LIMIT cambia la forma de la respuesta

En DRILL ... BY DIMENSION:

Y en modo NAV la granularidad se ignora: GRANULARITY YEARLY LIMIT 2 devuelve una grilla de 12 casillas mensuales con el total anual en la primera y ceros en el resto. No combines LIMIT con GRANULARITY YEARLY; si necesitas recortar, pide todo y recorta tú.

#3 — No existe DROP INDICATOR

El DSL solo tiene DROP TABLE. Un indicador creado con DEFINE INDICATOR no se puede borrar por el MCP. Antes de crear indicadores, avísale al usuario que deshacerlo requiere SQL directo (DELETE FROM metadata.indicadores WHERE nombre='...').

#4 — Verifica que los números cuadren

Las aperturas deben sumar el total. Si DRILL BY DIMENSION de un año no suma lo mismo que el QUERY de ese año, hay un filtro implícito o datos incompletos: repórtalo, no lo dejes pasar.

Escritura (solo siag, requiere rol admin)

Seis verbos: CREATE TABLE, ALTER TABLE, DROP TABLE [SAFE], LOAD DIMENSION, LOAD DATA, DEFINE INDICATOR.

CREATE TABLE ventas
  DESCRIPTION "Ventas brutas mensuales por región"
  DIMENSIONS: region
  MEASURES:   monto UNIT monto  unidades UNIT unidades

LOAD DIMENSION region INTO ventas
  VALUES:
    NORTE : "Región Norte"
    SUR : "Región Sur"

LOAD DATA INTO ventas
  DIMENSIONS: region=NORTE
  MEASURE: monto
  VALUES:
    2024-01 : 419904
    2024-02 : 447898

DEFINE INDICATOR margen_bruto
  FORMULA: ventas.monto - costos.monto
  UNIT: monto
  DESCRIPTION: "Margen bruto"
  GROUP: "Rentabilidad"

Se pueden mandar muchos statements en una sola llamada execute_dsl separados por saltos de línea; la respuesta trae statements y un results[] con el status de cada uno. Revisa cada elemento: que la llamada no falle no significa que los 25 statements hayan pasado.

DEFINE INDICATOR sobre un nombre existente lo redefine.

Configuración CRUD vs motor

Hay dos mundos que conviene no confundir:

save_indicador intenta sincronizar hacia el motor emitiendo un DEFINE y devuelve el resultado en un campo sync. Si sync.ok es false, el indicador existe en el editor pero NO en el motor — no aparecerá en QUERY/DRILL. Razones típicas en sync.reason: hoja_con_filtros, formula_incompleta, nombre_no_es_identificador. Siempre revisa sync.

Precauciones