Línea de comandos y claves
Lleva la definición de tu proyecto al disco, ejecuta la app en tu máquina y publícala de vuelta sin salir de la terminal.
La línea de comandos de Fabapp es el mismo proyecto que construyes en Studio, visto desde otro lugar. No es un
producto aparte ni una app distinta: pull trae los archivos de definición a tu carpeta, push devuelve lo que
editaste y dev ejecuta la app localmente sobre la misma plantilla que la plataforma usa para publicar.
Viene junto con el servidor MCP, que es como Claude Code, Cursor y otros asistentes leen y escriben en tu proyecto.
Lo que necesitas
- Node 20 o más reciente. Compruébalo con
node --version. - El plan Builder o superior. La línea de comandos se habilita a partir de Builder. Si tu plan todavía no lo incluye, la pantalla de Claves y CLI muestra qué cambia y te lleva directo a la suscripción.
Nada más. La herramienta no tiene una sola dependencia: guarda una credencial y habla con tu cuenta, y cada paquete del grafo podría alcanzar ambas cosas.
Autorizar esta máquina
Nunca creas una clave a mano. Quien la crea es el comando de inicio de sesión:
npx @fabappai/cli login
Abre el navegador en una página de Fabapp con un código corto. Compruebas que el código en pantalla es el mismo que
apareció en la terminal, autorizas, y la máquina queda conectada. En un servidor o en CI, sin navegador, usa
--no-open y abre la dirección tú mismo.
Esto es el flujo de dispositivo, y existe por una razón muy concreta: una clave que copias y pegas pasa por lugares por donde las claves no deberían pasar, como el historial del shell, un canal de chat o un archivo de configuración que termina en un repositorio. Aquí la clave nace dentro de tu máquina y nunca se muestra.
Dónde queda la credencial
En el llavero del sistema operativo. Cuando la máquina no tiene llavero, va a un archivo con permiso 0600, y el
comando lo dice. Una herramienta que elige en silencio el peor lugar te enseña que siempre es seguro.
Permiso de lectura o de escritura
Por defecto, el inicio de sesión pide lectura y escritura. Para una máquina que solo necesita consultar, pide menos:
npx @fabappai/cli login --scopes "read"
Una credencial de solo lectura ni siquiera ve los comandos de escritura, ni en la terminal ni en el servidor MCP. Anunciar una operación que responderá 403 es peor que no anunciarla: el asistente lo intenta, falla e intenta otra vez con otros argumentos, porque el rechazo parece un problema con la petición y no con el permiso.
El primer proyecto en el disco
Si el proyecto todavía no existe, empieza desde la terminal:
npx @fabappai/cli create "Mi app"
Crea el proyecto y su primera pantalla, y deja la carpeta actual vinculada a él. Era el último paso que solo se podía dar en el navegador. Si el proyecto ya existe, vincúlalo por id:
npx @fabappai/cli link <id-del-proyecto>
npx @fabappai/cli pull
link ata la carpeta actual a un proyecto, comprobando tu acceso antes de escribir nada. pull trae los
archivos de definición: fab.schema.json (las entidades y sus campos), fab.automations.json,
fab.settings.json, fab.connectors.json y el fab.config.json de cada pantalla.
Edita y devuélvelo:
npx @fabappai/cli push
Ejecutarla en tu máquina y publicar
npx @fabappai/cli dev
La primera vez, dev descarga la app y arma un área de trabajo en .fabapp/workspace con la misma plantilla con la
que la plataforma publica, instala las dependencias y levanta Vite. Las veces siguientes reutiliza lo que ya está
ahí. Usa --app <pantalla> cuando el proyecto tenga más de una, y --port para cambiar el puerto.
Edita lo que está en src/, míralo en el navegador y publica:
npx @fabappai/cli deploy
deploy hace dos cosas, en este orden: sube lo que tú cambiaste y solo entonces publica. El orden importa.
Publicar antes de subir publicaría lo que está en el servidor, el comando parecería haber funcionado y tu trabajo
quedaría atrás. Para subir sin publicar, y revisar en el Studio antes, usa --no-publish.
Bibliotecas y plugins
Instalar una biblioteca funciona como esperas: npm install <paquete> dentro de .fabapp/workspace, y el deploy
se lleva los paquetes que agregaste desde que se montó el área de trabajo. Sirve cualquier paquete que funcione
en el navegador.
Tres cosas se quedan fuera, y el deploy avisa antes de subir:
- La versión de los paquetes de la plataforma. React, Vite, Tailwind y los componentes Radix vienen siempre en la versión de la plataforma, porque el SDK y los componentes listos están hechos sobre ella. Cambiar la versión aquí no cambia nada en la app publicada.
- La configuración de build. El
vite.config.ts, elindex.htmly eltsconfigson de la plataforma y vuelven al original en cada publicación. Unpostcss.config.js, untailwind.config.jso una línea@pluginen un archivo CSS no se ejecutan en el build. - Archivos que no son texto. El código de la app es texto UTF-8, en el servidor y en el build. Una imagen, una
fuente o un audio en
public/se queda en casa y eldeploydice cuál es; súbelo desde el Studio (Marca o el storage de la app) y referéncialo por la URL. Un logo vectorial puede quedarse en el código como.svg. - Paquetes que solo funcionan en un servidor, como drivers de base de datos o bibliotecas que necesitan una clave secreta. La app corre en el navegador de quien la visita; ese código va en una función de backend.
Los plugins de build salen de una lista. Un plugin ejecuta código dentro del build, así que la plataforma solo
activa los que revisó: para Tailwind, @tailwindcss/typography (textos largos), tailwind-scrollbar,
tailwindcss-safe-area (la muesca del celular) y tailwindcss-motion (animaciones); para Vite, vite-plugin-svgr
(SVG como componente), vite-plugin-node-polyfills, @mdx-js/rollup (páginas en MDX), vite-plugin-wasm y
vite-plugin-glsl. Para activar uno, basta con instalar el paquete. La plataforma registra el plugin con su propia
configuración, y el dev hace lo mismo en tu máquina, así que lo que ves en local es lo que se publica.
Lo que no hace, a propósito
No borra. Ni en pull ni en deploy. Un archivo que desapareció de tu carpeta se informa, nunca se
elimina de la app. Tu copia puede estar desactualizada respecto al servidor (la IA puede haber editado la app en
Studio mientras tanto), y borrar allí por una ausencia aquí destruye trabajo que nadie nos pidió gestionar.
No sobrescribe lo que editaste. dev monta el espacio de trabajo una vez; en las ejecuciones siguientes
compara y avisa cuando la plantilla cambió, en lugar de pasar por encima. Reconstruir es decisión tuya
(--reset), y te avisa de que eso borra tus ediciones.
No envía lo que no es tuyo. deploy manda solo lo que cambiaste. Los componentes de la plataforma, el SDK y el
esqueleto de la app se quedan donde están.
No guarda credenciales de integración. fab.connectors.json y fab.integrations.json son de solo lectura:
dicen qué tiene conectado el proyecto, para que un asistente sepa que existe y qué operaciones llamar, y nunca la
credencial. Conectar y rotar ocurre en la plataforma.
Usarla con Claude Code y otros asistentes
El servidor MCP usa la credencial que login ya guardó. Nunca pide un secreto y nunca muestra uno.
{ "mcpServers": { "fabapp": { "command": "npx", "args": ["-y", "@fabappai/cli", "mcp"] } } }
Ese bloque sirve para la mayoría de los clientes. Lo que cambia es dónde vive:
| Cliente | Dónde ponerlo |
|---|---|
| Claude Code | claude mcp add fabapp -- npx -y @fabappai/cli mcp, o el bloque mcpServers en ~/.claude.json |
| Aplicación de Claude | el bloque mcpServers en claude_desktop_config.json |
| Cursor | .cursor/mcp.json en el proyecto, o ~/.cursor/mcp.json para todos |
| VS Code (Copilot) | .vscode/mcp.json |
| Windsurf | su archivo de configuración de MCP, en la carpeta de Codeium |
| Cline / Roo | el archivo que abre el propio panel de MCP de la extensión |
| Zed | el bloque de context servers de settings.json |
| Codex CLI | su config.toml, que declara el mismo comando en TOML |
| opencode | el bloque mcp de opencode.json, como servidor local que ejecuta ese comando |
| Antigravity | su configuración de MCP, desde el panel de MCP del propio editor |
El comando es nuestra parte y no cambia. El lugar lo decide cada cliente y cambia de versión en versión: cuando esta tabla no coincida con la documentación de tu cliente, la que tiene razón es la documentación.
La herramienta más importante es fabapp_read_definition: sin el esquema a mano, un id de modelo equivocado
responde 404 y un campo inventado responde 422. Es lo primero que un agente debería llamar.
Lo que ve el asistente depende del permiso que concediste: una credencial de solo lectura no recibe las
herramientas de escritura. Y fabapp_write_definition se niega a ejecutarse antes de que fabapp_docs haya sido
llamada en la misma conversación, porque un schema escrito sin el contrato inventa tipos de campo y reglas de
acceso, y ambas cosas fallan en silencio.
Ver y revocar las máquinas conectadas
En el panel, abre Perfil y ve a Claves y CLI. La pantalla lista cada máquina autorizada con el nombre que informó, el permiso que recibió y cuándo se usó por última vez.
Revocar es inmediato y vale para todo el servidor: la máquina revocada deja de funcionar en su siguiente llamada,
aunque la credencial siga en su disco. Lo contrario no es cierto: ejecutar logout en una máquina olvida la
credencial allí, y sigue siendo válida en el servidor hasta que se revoque aquí. Cuando un portátil desaparece,
es esta pantalla la que resuelve, no logout.
Cuando algo no funciona
"Tu plan no incluye la línea de comandos". El inicio de sesión solo emite credenciales a partir de Builder. La pantalla de Claves y CLI indica el plan necesario.
El código del navegador no coincide con el de la terminal. No autorices. Cierra la página y ejecuta login de
nuevo: ambos códigos salen de la misma petición y solo difieren si estás mirando una autorización que no es tuya.
push se queja de un archivo que la app no puede sobrescribir. Dice cuál. Eso es mejor que guardar con un 200
y no cambiar nada.
Otra API. FABAPP_API_URL cambia la dirección base, que por defecto es https://api.fabapp.ai.