Linha de comando e chaves
Traga a definição do seu projeto para o disco, rode o app na sua máquina e publique de volta, sem sair do terminal.
A linha de comando da Fabapp é o mesmo projeto que você constrói no Studio, visto de outro lugar. Ela não é um
produto separado nem um app diferente: pull traz os arquivos de definição para a sua pasta, push devolve o que
você editou, e dev roda o app localmente no mesmo template que a plataforma usa para publicar.
Ela vem junto com o servidor MCP, que é como o Claude Code, o Cursor e outros assistentes leem e escrevem no seu projeto.
O que você precisa
- Node 20 ou mais novo. Confira com
node --version. - O plano Builder ou superior. A linha de comando é liberada a partir do Builder. Se o seu plano ainda não inclui, a tela de Chaves e CLI mostra o que muda e leva direto para a assinatura.
Nada mais. A ferramenta não tem uma única dependência: ela guarda uma credencial e conversa com a sua conta, e cada pacote no caminho poderia alcançar as duas coisas.
Autorizando esta máquina
Você nunca cria uma chave à mão. Quem cria é o comando de login:
npx @fabappai/cli login
Ele abre o navegador numa página da Fabapp com um código curto. Você confere que o código na tela é o mesmo que
apareceu no terminal, autoriza, e pronto: a máquina fica conectada. Em servidor ou CI, sem navegador, use
--no-open e abra o endereço manualmente.
Isso é o fluxo de dispositivo, e ele existe por um motivo bem concreto: uma chave que você copia e cola passa por lugares onde chaves não deveriam passar, como o histórico do shell, um canal de chat ou um arquivo de configuração que acaba num repositório. Aqui a chave nasce já dentro da sua máquina e nunca é exibida.
Onde a credencial fica
No chaveiro do sistema operacional. Quando a máquina não tem chaveiro, ela vai para um arquivo com permissão
0600, e o comando diz que foi para lá. Uma ferramenta que silenciosamente escolhe o lugar pior ensina você a
achar que é sempre seguro.
Permissão de leitura ou de escrita
Por padrão, o login pede permissão de leitura e escrita. Para uma máquina que só precisa consultar, peça menos:
npx @fabappai/cli login --scopes "read"
Uma credencial só de leitura não enxerga os comandos de escrita, nem no terminal nem no servidor MCP. Anunciar uma operação que vai responder 403 é pior do que não anunciar: o assistente tenta, falha, e tenta de novo com outros argumentos, porque a recusa parece um problema com o pedido e não com a permissão.
O primeiro projeto no disco
Se o projeto ainda não existe, comece pelo terminal mesmo:
npx @fabappai/cli create "Meu app"
Ele cria o projeto e a primeira tela, e já amarra a pasta atual a ele. Era o último passo que só dava para fazer no navegador. Se o projeto já existe, amarre pelo id:
npx @fabappai/cli link <id-do-projeto>
npx @fabappai/cli pull
O link amarra a pasta atual a um projeto, conferindo o seu acesso antes de escrever qualquer coisa. O pull
traz os arquivos de definição: fab.schema.json (as entidades e os campos), fab.automations.json,
fab.settings.json, fab.connectors.json e o fab.config.json de cada tela.
Edite, e devolva:
npx @fabappai/cli push
Rodando na sua máquina e publicando
npx @fabappai/cli dev
Na primeira vez, o dev baixa o app e monta uma área de trabalho em .fabapp/workspace com o mesmo template que a
plataforma usa para publicar, instala as dependências e sobe o Vite. Nas vezes seguintes ele reaproveita o que já
está lá. Use --app <tela> quando o projeto tiver mais de uma tela, e --port para trocar a porta.
Edite o que está em src/, veja no navegador, e publique:
npx @fabappai/cli deploy
O deploy faz duas coisas, nessa ordem: sobe o que você mudou e só então publica. A ordem importa. Publicar
antes de subir publicaria o que está no servidor, o comando pareceria ter funcionado e o seu trabalho ficaria para
trás. Se quiser subir sem publicar, para revisar no Studio antes, use --no-publish.
Bibliotecas e plugins
Instalar uma biblioteca funciona do jeito que você espera: npm install <pacote> dentro de .fabapp/workspace, e o
deploy leva junto os pacotes que você acrescentou desde que a área de trabalho foi montada. Qualquer pacote que
rode no navegador serve.
Três coisas ficam de fora, e o deploy avisa antes de subir:
- A versão dos pacotes da plataforma. React, Vite, Tailwind e os componentes Radix vêm sempre na versão da plataforma, porque o SDK e os componentes prontos foram feitos em cima dela. Trocar a versão aqui não muda nada no app publicado.
- Configuração de build. O
vite.config.ts, oindex.htmle otsconfigsão da plataforma e voltam ao original a cada publicação. Umpostcss.config.js, umtailwind.config.jsou uma linha@pluginnum arquivo CSS não rodam no build. - Arquivos que não são texto. O código do app é texto UTF-8, no servidor e no build. Uma imagem, uma fonte ou
um áudio em
public/fica em casa e odeploydiz qual é; suba pelo Studio (Marca ou o storage do app) e referencie pela URL. Um logo vetorial pode ficar no código como.svg. - Pacotes que só funcionam em servidor, como drivers de banco de dados ou bibliotecas que precisam de chave secreta. O app roda no navegador de quem visita; esse código vai numa função de backend.
Plugins de build vêm de uma lista. Um plugin roda código dentro do build, então a plataforma só liga os que ela
revisou: para o Tailwind, @tailwindcss/typography (textos longos), tailwind-scrollbar, tailwindcss-safe-area
(o entalhe do celular) e tailwindcss-motion (animações); para o Vite, vite-plugin-svgr (SVG como componente),
vite-plugin-node-polyfills, @mdx-js/rollup (páginas em MDX), vite-plugin-wasm e vite-plugin-glsl. Para
ligar um deles, é só instalar o pacote. A plataforma registra o plugin com a configuração dela, e o dev faz a
mesma coisa na sua máquina, então o que você vê localmente é o que vai ao ar.
O que ela não faz, de propósito
Não apaga. Nem no pull nem no deploy. Um arquivo que sumiu da sua pasta é reportado, nunca removido do
app. A sua cópia pode estar velha em relação ao servidor (a IA pode ter editado o app no Studio enquanto isso), e
apagar lá por causa de uma ausência aqui destrói trabalho que ninguém pediu para gerenciar.
Não sobrescreve o que você editou. O dev monta a área de trabalho uma vez; nas execuções seguintes ele
compara e avisa quando o template mudou, em vez de passar por cima. Reconstruir é decisão sua (--reset), e ele
avisa que isso apaga suas edições.
Não envia o que não é seu. O deploy manda só o que você mudou. Os componentes da plataforma, o SDK e o
esqueleto do app ficam onde estão.
Não guarda credencial de integração. Os arquivos fab.connectors.json e fab.integrations.json são só de
leitura: eles dizem o que o projeto tem conectado, para que um assistente saiba que existe e quais operações
chamar, e nunca a credencial. Conectar e rotacionar acontece na plataforma.
Usando com Claude Code e outros assistentes
O servidor MCP usa a credencial que o login já guardou. Ele nunca pede um segredo e nunca mostra um.
{ "mcpServers": { "fabapp": { "command": "npx", "args": ["-y", "@fabappai/cli", "mcp"] } } }
Esse bloco serve para a maioria dos clientes. O que muda é onde ele mora:
| Cliente | Onde colocar |
|---|---|
| Claude Code | claude mcp add fabapp -- npx -y @fabappai/cli mcp, ou o bloco mcpServers no ~/.claude.json |
| Aplicativo do Claude | o bloco mcpServers no claude_desktop_config.json |
| Cursor | .cursor/mcp.json no projeto, ou ~/.cursor/mcp.json para todos eles |
| VS Code (Copilot) | .vscode/mcp.json |
| Windsurf | o arquivo de configuração de MCP, na pasta do Codeium |
| Cline / Roo | o arquivo que o próprio painel de MCP da extensão abre |
| Zed | o bloco de context servers do settings.json |
| Codex CLI | o config.toml dele, que declara o mesmo comando em TOML |
| opencode | o bloco mcp do opencode.json, como servidor local rodando esse comando |
| Antigravity | a configuração de MCP, pelo painel de MCP do próprio editor |
O comando é a parte nossa e não muda. O lugar é decisão de cada cliente e muda de versão para versão: quando esta tabela discordar da documentação do seu cliente, quem está certo é ela.
A ferramenta mais importante é a fabapp_read_definition: sem o schema em mãos, um id de modelo errado responde
404 e um campo inventado responde 422. É a primeira coisa que um agente deveria chamar.
O que o assistente enxerga depende da permissão que você concedeu: uma credencial só de leitura não recebe as
ferramentas de escrita. E a fabapp_write_definition se recusa a rodar antes de a fabapp_docs ter sido chamada na
mesma conversa, porque um schema escrito sem o contrato inventa tipo de campo e regra de acesso, e as duas coisas
falham em silêncio.
Vendo e revogando as máquinas conectadas
No painel, abra Perfil e vá em Chaves e CLI. A tela lista cada máquina autorizada com o nome que ela informou, a permissão que recebeu e quando foi usada pela última vez.
Revogar é imediato e vale para o servidor inteiro: a máquina revogada para de funcionar na próxima chamada, mesmo
que a credencial continue no disco dela. O caminho contrário não é verdade: rodar logout numa máquina esquece a
credencial ali, e ela continua válida no servidor até ser revogada aqui. Quando um notebook some, é esta tela
que resolve, não o logout.
Quando alguma coisa não funciona
"Plano não inclui a linha de comando". O login só emite credencial a partir do Builder. A tela de Chaves e CLI mostra o plano necessário.
O código do navegador não bate com o do terminal. Não autorize. Feche a página e rode o login de novo: os dois
códigos são gerados no mesmo pedido e só divergem se você estiver olhando para uma autorização que não é a sua.
push reclama de um arquivo que o app não pode sobrescrever. Ele diz qual é. Isso é melhor do que salvar com um
200 e não mudar nada.
Outra API. FABAPP_API_URL troca o endereço base, que por padrão é https://api.fabapp.ai.