Bases de datos
Una tabla de Nirvai es una planilla con reglas. Se ve como filas y columnas, pero cada columna
sabe qué está dispuesta a contener: una columna de estado acepta cuatro palabras y ninguna otra, una
de responsable acepta personas que realmente trabajan contigo, una de vínculo acepta una fila
específica de otra tabla específica. Tu asistente no puede escribir lo que se le ocurra en una celda
— primero le pregunta a la columna. Todo lo de abajo corre a través de nirvai_execute en el área
db; la gramática de alias está en la referencia de MCP.
Casi seguro tienes dos tablas llamadas Leads — una del año pasado y la que realmente usas. Son tablas distintas con la misma etiqueta. Tu asistente resuelve primero el id estable de la tabla, y cada verbo de abajo se dirige por ese id, nunca por el nombre que vio en la conversación.
Los verbos
| Verbo | Permiso | Qué hace |
|---|---|---|
db.select | read | Lee filas, con una cola SELECT-only en crudo — más abajo. |
db.get_rich | read | Lee el cuerpo de página de un registro: el documento que vive dentro de la fila. |
db.insert | write | Agrega filas. Éxito parcial por fila: las buenas entran, las malas vuelven con su motivo. |
db.update | write | Cambia las filas que cumplen una condición. Todo o nada — un valor inválido y no se escribe nada. |
db.update_rich | write | Reemplaza el cuerpo de página de un registro. Protegido para no descartar medios en silencio. |
db.edit | write | Cambia la estructura de la tabla — agregar, eliminar, cambiar el tipo o renombrar columnas. |
db.create_database | create | Crea un espacio nuevo para contener tablas. |
db.create_table | create | Crea una tabla dentro de un espacio, con sus columnas y vistas. |
db.propose | create | Redacta una configuración revisable de varias tablas — un espacio, sus tablas, columnas y vistas. Tú haces clic en Crear. |
db.delete | destructivo | Retenido. Se rechaza con cualquier token — borrar no es posible por la conexión. |
El descubrimiento viene de las herramientas maestras: nirvai_list_resources para "qué tablas
tengo", y nirvai_describe para "qué es exactamente esta" — sus columnas, sus valores permitidos,
quién puede ser asignado, con qué tablas se vincula y tu nivel de permiso. Eso se lee en vivo, cada
vez.
Dónde lo terminas tú
db.propose no construye nada. Te entrega una página en /external/databases/…, y una sola
propuesta puede traer una configuración completa de varias tablas — un espacio más varias tablas,
sus columnas y sus vistas. La página muestra una tarjeta por paquete, cada una con su propio botón
de Crear.
- Es un formulario, no un recibo. Cambia el tipo o el nombre de una columna, descarta una tabla que no quieres, y recién ahí crea — paquete por paquete, en el orden que prefieras.
- Tienes que haber iniciado sesión, y solo tú puedes abrirla. Un enlace de propuesta no se comparte.
db.insertydb.updateno pasan por una página de revisión. Las filas entran directo; la revisión protege la creación de estructura.- Una vez creado, al volver a abrirla verás Creado ✓ y no se hace una segunda copia — ver la referencia de MCP.
Lectura: db.select
condition es una cola SELECT-only en crudo — un WHERE, un ORDER BY, un LIMIT. Cualquier
cosa que modificaría datos se rechaza de plano.
nirvai_execute(
alias = "db.select",
args = { table_session: "…",
condition: "WHERE status = 'Open' ORDER BY id DESC LIMIT 50",
columns: ["id", "name", "status", "owner"] },
description = "Listar los negocios abiertos, del más nuevo al más viejo"
)
→ { rows, row_count, truncated }
Siempre se aplica un techo de filas. truncated: true significa que había más — tu asistente
pagina con su propio LIMIT/OFFSET en vez de suponer que vio todo.
Escribir valores: la gramática de valores etiquetados
Las columnas simples reciben un valor plano. Las columnas estructuradas reciben una etiqueta: un
objeto pequeño cuya única clave empieza con $ y nombra qué tipo de cosa quieres decir.
| Tipo de columna | Cómo lo escribe tu asistente |
|---|---|
| texto, número, fecha, casilla, email, url, teléfono, calificación, moneda, progreso, color | El valor plano — "Acme", 42, "2025-03-01", true |
| opción única / estado | {"$select": "Open"} (o el texto de la opción a secas) |
| opciones múltiples | {"$multi_select": ["Urgent", "Renewal"]} |
| persona | {"$person": "jane@company.com"} |
| vínculo a otro registro | {"$relation": {"table_session": "…", "record_id": 42}} |
| archivo | {"$file": "quote.pdf"} |
| agente | {"$agent": "…"} |
Dos reglas lo hacen seguro. Las opciones son cerradas — las palabras que acepta una columna de
opciones vienen de nirvai_describe, no de la imaginación de tu asistente, y un valor no listado se
rechaza en vez de inventarse; lo mismo vale para un responsable que la tabla no puede asignar o un
vínculo a una fila que no existe. Y los errores son estructurados, nunca errores crudos de la base
de datos: recibes un motivo con nombre — INVALID_OPTION, PERSON_NOT_FOUND, UNKNOWN_COLUMN,
PROTECTED_COLUMN, OUT_OF_RANGE, RELATION_RECORD_NOT_FOUND — con la columna y, cuando
corresponde, el conjunto permitido. Una escritura fallida le dice a tu asistente cómo corregirse.
El id de un registro, sus fechas de creación y actualización, su cuerpo de página y su ícono, y todo
lo que gestiona el sistema de tareas de agente nunca son escribibles por la vía de registros ni
aparecen como campos escribibles. El cuerpo de página se lee y se escribe con db.get_rich /
db.update_rich, que reemplaza el cuerpo completo — por eso tu asistente lo lee primero y se niega a
descartar medios salvo que se lo indiques.
Ejemplo real: encontrar, aprender, leer, escribir
nirvai_list_resources(kind = "databases")
→ las tablas que tienes, cada una con su id estable
nirvai_describe(kind = "databases", ref = "<id de la tabla>")
→ columnas, opciones permitidas, asignables, relaciones, vistas, tu nivel de permiso
nirvai_execute(
alias = "db.select",
args = { table_session: "…", condition: "WHERE stage = 'Qualified' LIMIT 20" },
description = "Ver qué leads ya están calificados"
)
nirvai_execute(
alias = "db.insert",
args = { table_session: "…",
records: [{ "Company Name": "Acme",
"Stage": {"$select": "Qualified"},
"Owner": {"$person": "jane@company.com"},
"Value": 48000 }] },
description = "Agregar a Acme al pipeline como lead calificado"
)
→ { inserted_ids, inserted_count, row_errors }
El paso de describe no es cortesía opcional: es donde se confirma que "Qualified" es una opción
real y que jane@company.com es alguien realmente asignable, antes de escribir nada.
Cambiar la estructura: db.edit
Agregar una columna es seguro. Eliminarla, cambiarle el tipo o renombrarla es destructivo — los
datos que contiene se pierden. Por eso db.edit funciona en dos tiempos: primero una corrida en
seco, que devuelve el plan de cambios (qué se agregaría, eliminaría, cambiaría de tipo o
renombraría, y qué vistas guardadas se verían afectadas) y no toca nada; después la edición real, que
para un cambio destructivo exige una confirmación explícita en la llamada y se rechaza sin ella.
Se espera que tu asistente te muestre el plan antes de confirmar nada.
Límites y garantías
- Tu nivel de permiso viene de la propiedad, no del token. Eres dueño de la tabla → acceso
completo; eres admin de la organización → escritura; eres miembro de la organización → lectura. Una
tabla en nivel lectura rechaza una escritura incluso cuando el token trae el permiso
write. El nivel aparece ennirvai_describe. insertes parcial,updatees total. Insertar diez filas puede escribir ocho e informar dos; una actualización se aplica completa o no se aplica.- Nada se crea a tus espaldas.
db.proposeredacta una forma — espacios, tablas, columnas, vistas — nunca filas, nunca datos. Se vuelve real cuando haces clic en Crear, una sola vez; volver a abrir la página de revisión después la muestra como ya creada y no la crea de nuevo. - Borrar es imposible.
db.deletese rechaza con cualquier token, siempre. - Las escrituras aparecen de inmediato en tu vista de tabla abierta y en el Feed de Actividad.