Criar um projeto

De uma fonte de dados real a um app no ar, para um agente de código. Cada passo termina em algo que você pode conferir.

0. Pré-requisitos

  • O servidor MCP conectado com --scope user, e o whoami respondendo (Primeiros passos com o MCP).
  • O CLI companion: make cli no checkout da plataforma, depois cortex login. cortex whoami --json sai com 0.
  • Node 22+ no terminal onde o app vai ficar.

O comando cortex. Ele não está no npm, e npx cortex instala outro pacote com o mesmo nome: nunca rode. O make cli deixa o nosso em ~/.local/bin.

1. Criar o projeto

Combine o slug (global) com a pessoa.

Pergunte a região à pessoa; nunca escolha por ela. region é obrigatória e permanente: o lake e o app rodam nela (southamerica-east1 para o Brasil, us-central1 para os Estados Unidos). Em dev, hoje, o runtime existe em us-central1; uma região sem runtime é recusada pelo create_project com um erro que diz quais regiões funcionam. Conte isso à pessoa e pergunte de novo; nunca tente outra região por conta própria.

create_project  { slug: "acme-bi", name: "Acme BI", region: "us-central1" }
get_project     { project_id }     # até o status ser "active"

2. Gerar o app

Só depois de o projeto estar active: o cortex.yaml nomeia o projeto pelo slug, e o deploy o procura.

cortex init bi-nextjs --dir acme-bi --slug acme-bi --region us-central1
cd acme-bi && npm install
npm run dev     # http://localhost:3000, dados de exemplo, login simulado

O cortex init recebe a mesma região, e --region é obrigatório: precisa ser aquela em que o projeto foi criado (o get_project mostra).

O init escreve o template Next.js e o cortex.yaml (spec §8) com o seu slug, nome e região em project:. O template vem com dados de exemplo no formato exato de MetricQueryResult, então roda offline enquanto o projeto ainda está vazio.

3. Descrever os dados no cortex.yaml

  • sources: uma entrada por banco, pasta de arquivos ou API. Strings de conexão são referências a segredos (connection: { secret: ERP_DSN }), nunca valores.
  • pipelines: o que roda, quando, em qual fuso.
  • semantic.datasets e semantic.metrics: o único lugar onde um número é definido.
  • access.row_policies e access.column_masks: quem vê quais linhas e colunas.

Todo segredo citado no arquivo precisa existir antes: set_secret { project_id, name, value }. Depois aplique o arquivo inteiro:

apply_project_config  { project_id, yaml: "<conteúdo do cortex.yaml>", dry_run: true }
apply_project_config  { project_id, yaml: "<conteúdo do cortex.yaml>" }

O primeiro apply também sincroniza o catálogo; antes dele, o run_sql responde que o catálogo ainda não foi sincronizado. Um ambiente protegido responde com um change set que a pessoa aprova (approve_change_set).

4. Carregar os dados

  • Banco acessível pela internet: add_source com type: "database", um connector (postgres, mysql, mssql, oracle) e o nome do segredo; test_source; depois run_pipeline { project_id, pipeline: "<nome em pipelines>" } e get_run { run_id } até terminar.
  • Planilhas e CSVs: upload_file, PUT dos bytes na URL assinada, finalize_upload, get_run. Para arquivos no disco da pessoa, cortex upload <arquivos|pasta> --json faz os quatro e espera; ou deixe para o primeiro deploy (passo 6, --with-data).
  • Uma fonte dentro da rede da pessoa (um ERP local) não é alcançável pela nuvem hoje, e o cortex ingest --local ainda não foi implementado (sai com 9). Diga isso.

Confira: list_tables e sample_table mostram o que entrou. Informe as contagens de linhas.

5. Modelar e consultar

propose_model { project_id } devolve um change set; mostre, obtenha a aprovação, depois run_models { project_id }. Com as métricas de semantic.metrics aplicadas:

query_metrics  { project_id, query: { metrics: ["revenue", "orders"], dimensions: ["orders.channel"], time_grain: "month" } }

Todo número vem com o seu SQL. Mostre os dois.

6. Publicar

cortex deploy --json     # production por padrão; --env preview para uma prévia

.gitignore e .cortexignore decidem o que entra no pacote; arquivos .env* são sempre recusados. approval.required quer dizer ambiente protegido: aprove o change set com a pessoa e rode de novo. O comando espera o certificado de um endereço novo e imprime a URL. Confira o /healthz nela.

Primeiro deploy e dados locais. No primeiro deploy de um projeto (nenhum deployment em nenhum ambiente ainda), a pessoa decide se os arquivos de dados do disco dela sobem junto com o app. Pergunte antes de rodar o comando, ou chame create_deployment { project_id }: ele pergunta e devolve o comando a rodar, cortex deploy --with-data ou cortex deploy.

  • cortex deploy --with-data --json sobe antes todos os arquivos de dados locais (CSV, TSV, Excel .xlsx, Parquet), espera cada um carregar e só então publica o app. Os arquivos são as fontes type: files do cortex.yaml cujo path existe no disco; sem elas, todo arquivo de dados da pasta, com .gitignore e .cortexignore aplicados. O que subiu como dado fica fora do pacote do app (--keep-data-in-app manda também).
  • --data <caminho|glob>[,...] escolhe os arquivos (o .gitignore não se aplica a ele); --no-data publica só o app. --env pr<N> manda os dados para essa prévia.
  • Sem flag e sem terminal (você, um agente), o comando nunca pergunta: publica só o app e imprime em stderr uma dica de --with-data. O --json traz data.decision, data.uploads e data.run_ids.
  • Falha de dados para antes de publicar o app: sai com 7 quando um upload é recusado, com 1 e run.failed quando uma carga falha. Leia get_run_logs { run_id }, corrija o arquivo e rode de novo.
  • .xls não é lido: salve como .xlsx.
  • Nunca sobem como dado, com qualquer flag ou glob: .env*; chaves e arquivos de credencial (*service-account*.json, *credentials*.json, *.pem, *.key, *.p12, *.pfx, id_rsa*, id_ed25519*, .npmrc, .pypirc); arquivos de texto cujos primeiros 4 KiB têm uma chave privada ou um JSON de service account; links simbólicos que resolvem para fora da pasta (glob e varredura de pasta nunca seguem link). Cada um imprime uma linha warning: em stderr e entra em refused (data.refused no deploy) com o reason. Nomeado sozinho, o comando sai com 7. Globs pulam package.json, tsconfig*.json e outros JSON de ferramenta.

O meu app está do tamanho certo?

Pergunte à plataforma, não chute. O get_app_metrics lê CPU, memória, instâncias, requisições, latência p50/p95, 5xx e cold starts do app de um ambiente, o size atual comparado ao teto do plano, e uma recommendation calculada a partir desses números:

get_app_metrics  { project_id, env: "production", window: "24h" }   # window: 1h, 24h ou 7d
recommendation.adviceO que quer dizerO que você faz
okO tamanho aguenta a cargaNada
scale_upO p95 de CPU ou de memória está altoProponha o recommendation.cortex_yaml
scale_outAs instâncias ficam no máximoProponha o recommendation.cortex_yaml
keep_warmCold starts pioram a latênciaProponha min_instances: 1; custa parado
scale_downPaga por um tamanho que não usaProponha o tamanho menor
upgrade_planA solução está acima do teto do planoDiga à pessoa qual plano; não aplique
no_dataNenhum tráfego no períodoAbra o app, ou tente window: "7d"

O tamanho fica no cortex.yaml, em app.resources (plan-default quando ausente):

app:
  resources:
    cpu: 2
    memory: 1Gi
    min_instances: 0

Mostre à pessoa o recommendation.reason e o monthly_cost_delta_usd (só o número que a plataforma mandou; nunca calcule um), depois apply_project_config com dry_run: true e de novo sem ele. Um ambiente protegido responde com um change set para aprovar. O tamanho novo vale a partir do próximo deploy daquele ambiente. Um tamanho acima do teto do plano é recusado com limit.plan_required, e o hint diz qual plano permite. O console mostra os mesmos números na página do projeto (aba Máquina), só para leitura.

Pronto quando

whoami funciona, o cortex.yaml aplica, pelo menos um pipeline ou upload rodou, o query_metrics responde com o SQL, e a URL responde em /healthz.

Estado hoje (24/09/2026, dev)

  • Funciona: cortex login, whoami, init, deploy (com --with-data), upload; toda ferramenta do MCP em tools/list.
  • Ainda não: cortex ingest --local, cortex dev e cortex config push/pull saem com 9 e uma dica; use as ferramentas do MCP acima.
  • Novo em 25/09/2026: get_app_metrics e a region obrigatória. Se o tools/list ainda não tiver o get_app_metrics, este ambiente não foi atualizado: diga isso, não chute o tamanho.
  • O dashboard e o chat do template ainda mostram dados de exemplo. Ligá-los ao query_metrics é a próxima mudança do template; até lá, diga à pessoa que os números da página são exemplos.