# bohr > A bohr publica um repositório do GitHub como um Worker da Cloudflare e deixa um agente de IA mudá-lo por conversa (no painel web ou no Telegram). Cada mudança vai primeiro para uma homologação e só chega à produção quando alguém aprova. A bohr é open source e auto-hospedada, ou roda para você como bohr.io Cloud (app.bohr.io). # Documentação da bohr > A bohr faz o deploy do seu repositório do GitHub na Cloudflare e deixa um agente de IA mudá-lo por conversa, com uma homologação que você aprova antes de qualquer coisa chegar à produção. Source: https://docs.bohr.io/pt-br/ **Pergunte mais, programe menos.** A bohr transforma um repositório do GitHub em um site que roda na Cloudflare e que você muda conversando com um agente de IA, no painel web ou no Telegram. Toda mudança vai primeiro para a homologação. Nada chega à produção até alguém aprovar. ## Comece por aqui - [Como funciona](https://docs.bohr.io/pt-br/introduction/how-it-works/): o caminho de um repositório até a produção, passo a passo. - [bohr.io Cloud ou auto-hospedada](https://docs.bohr.io/pt-br/introduction/cloud-and-self-hosted/): as duas formas de rodar a bohr e quanto custa cada uma. - [Primeiros passos](https://docs.bohr.io/pt-br/getting-started/sign-in/): entre, conecte a Cloudflare e o GitHub e crie seu primeiro projeto. ## Use a bohr - [O agente](https://docs.bohr.io/pt-br/agent/chat/): peça mudanças, revise a homologação, aprove ou descarte, reverta. - [Projetos](https://docs.bohr.io/pt-br/projects/overview/): builds, versões, membros, variáveis, proteção por senha e domínios. - [Deploys](https://docs.bohr.io/pt-br/deploys/how-deploys-work/): como um projeto faz o build e publica, e os arquivos que o descrevem. - [Organizações](https://docs.bohr.io/pt-br/organizations/overview/): trabalhe em equipe, com membros que espelham a sua organização do GitHub. ## Automatize - [A CLI `bohr`](https://docs.bohr.io/pt-br/cli/install/): faça deploy do seu terminal, de scripts e do CI. - [Para agentes de IA](https://docs.bohr.io/pt-br/ai-agents/overview/): deixe o Claude Code, o Cursor, o Codex e outros agentes de código fazerem deploy com a CLI. - [GitHub Action](https://docs.bohr.io/pt-br/github-action/reference/): `bohr-io/deploy-action@v1`. ## Rode a sua - [Auto-hospedagem](https://docs.bohr.io/pt-br/self-hosting/overview/): instale a instância open source na sua própria conta da Cloudflare. - [Migrando da bohr v1](https://docs.bohr.io/pt-br/migrating-from-v1/overview/): o que aconteceu com os projetos da v1 e como movê-los para a sua própria conta. :::tip[Para ferramentas de IA] Toda página tem uma cópia em Markdown: acrescente `.md` ao endereço dela (por exemplo [`/pt-br/cli/deploy.md`](https://docs.bohr.io/pt-br/cli/deploy.md)). O índice de todas as páginas está em [`/pt-br/llms.txt`](https://docs.bohr.io/pt-br/llms.txt), e a documentação inteira em um único arquivo em [`/pt-br/llms-full.txt`](https://docs.bohr.io/pt-br/llms-full.txt). ::: --- # Como funciona > De um repositório do GitHub até a produção, passando pelo agente, pela homologação e por uma aprovação. Source: https://docs.bohr.io/pt-br/introduction/how-it-works/ A bohr conecta três coisas que você já tem: um **repositório do GitHub** (o código), uma **conta da Cloudflare** (onde o site roda) e um **provedor de modelo** (o cérebro do agente de IA, como uma chave da API da Anthropic ou a sua assinatura Claude). ``` Você (chat web ou Telegram) │ "Adicione um formulário de contato na página inicial" ▼ Worker do projeto na sua conta da Cloudflare ├─ fila de pedidos, membros, histórico do chat ├─ sandbox do agente (um Cloudflare Container): edita o código, roda o build └─ homologação: o site, rodando a partir do branch "homolog" │ ▼ Aprovar Pull request homolog → branch de produção, com merge │ ▼ O GitHub Actions faz o build e o deploy da produção na sua conta da Cloudflare ``` ## O ciclo 1. **Conecte.** Você entra, conecta a sua conta da Cloudflare e instala o app do GitHub da bohr nos repositórios que a bohr pode usar. Isso é feito uma única vez. 2. **Crie um projeto.** Escolha um dos seus repositórios, ou comece a partir de um [modelo](https://docs.bohr.io/pt-br/getting-started/templates/). A bohr cria o Worker do projeto, o sandbox do agente e a homologação na sua conta da Cloudflare (de um a três minutos). 3. **O agente prepara o repositório.** Na primeira execução, o agente descobre como o seu projeto roda na Cloudflare: escreve o `.bohr/preview.json` (como rodar a homologação) e o `.bohr/deploy.json` (como fazer o build e o deploy da produção), adiciona uma configuração do wrangler se faltar e faz o build de produção passar. 4. **Peça uma mudança.** Escreva o que você quer em palavras simples, no chat do painel ou para o bot do Telegram do projeto. O agente edita o código no sandbox dele e faz push do resultado para o branch `homolog`. 5. **Revise a homologação.** A homologação mostra o site com a mudança, em um endereço próprio. Peça ajustes quantas vezes quiser; os pedidos seguintes continuam a mesma conversa. 6. **Aprove ou descarte.** **Aprovar e publicar** abre um pull request de `homolog` para o branch de produção e faz o merge. Em seguida, o GitHub Actions faz o build e o deploy da produção. **Descartar** joga as mudanças fora, e a homologação volta a ser igual à produção. 7. **Reverta** quando quiser: a bohr faz o merge de um revert da última publicação, e a produção volta para a versão anterior. ## O que roda onde | Parte | Onde roda | | --- | --- | | A instância da bohr (painel, API, cofre de credenciais) | bohr.io Cloud, ou a sua própria conta da Cloudflare se você [hospedar a sua](https://docs.bohr.io/pt-br/self-hosting/overview/) | | O Worker de cada projeto, o sandbox do agente e a homologação | A conta da Cloudflare do dono do projeto | | O site de produção | A conta da Cloudflare do dono do projeto, como um Worker com static assets | | O código, os branches, os pull requests e as execuções de deploy | O repositório do projeto no GitHub e o GitHub Actions | | O modelo de IA | O seu provedor: Anthropic, um endpoint compatível com a Anthropic, ou a sua assinatura Claude | Os projetos migrados da bohr v1 são a exceção: a bohr os hospeda na própria conta da Cloudflare até que os donos [os movam](https://docs.bohr.io/pt-br/migrating-from-v1/move-to-your-cloudflare/). ## Segurança desde o projeto - **Nada chega à produção sem aprovação.** O agente só consegue fazer push para `homolog`. A produção só muda por um pull request aprovado e mesclado, e o merge aponta o commit exato que você revisou. - **O sandbox nunca guarda as suas chaves.** O agente vê apenas marcadores; a bohr acrescenta a chave real do modelo e um token do GitHub de curta duração, restrito a um repositório, na saída. Veja [Modelo de segurança](https://docs.bohr.io/pt-br/reference/security/). - **O agente não consegue mudar os seus workflows.** O GitHub recusa qualquer mudança em `.github/workflows` vinda do sandbox; a própria bohr escreve o workflow de deploy dela. --- # bohr.io Cloud ou auto-hospedada > As duas formas de rodar a bohr, o que cada uma inclui e pelo que você paga. Source: https://docs.bohr.io/pt-br/introduction/cloud-and-self-hosted/ A bohr é open source (MIT). Você pode rodar a **instância** (o painel, a API e o cofre de credenciais) por conta própria, ou usar a que a bohr roda para você em [app.bohr.io](https://app.bohr.io). Em qualquer caso, os seus projetos rodam na sua própria conta da Cloudflare. | | bohr.io Cloud | Auto-hospedada | | --- | --- | --- | | Quem roda a instância | A bohr | Você, na sua conta da Cloudflare | | Endereço | `https://app.bohr.io` | O endereço do seu Worker ou o seu domínio | | Preço da instância | US$20/mês por conta ou organização | Grátis | | Onde os projetos rodam | Na sua conta da Cloudflare | Na conta da Cloudflare de cada usuário | | Recursos | Todos | Todos | | Usuários e projetos | Por assinatura | Ilimitados | | Telemetria | Nada é enviado | Desligada, a menos que um admin a ligue ([detalhes](https://docs.bohr.io/pt-br/self-hosting/telemetry/)) | ## O que você paga Nas duas, a infraestrutura é paga direto aos provedores, nunca pela bohr: | Provedor | O que cobra | | --- | --- | | Cloudflare | O plano **Workers Paid** (US$5/mês), necessário porque o sandbox do agente é um Container. O tempo de Container enquanto o agente trabalha (um container `standard-1` custa centavos por hora e dorme quando está ocioso), e o que os seus sites usarem em produção. | | O seu provedor de modelo | Os tokens do agente, com a sua chave da API da Anthropic ou de um provedor compatível. Com uma assinatura Claude Pro ou Max, o uso conta na sua assinatura. | | GitHub | Nada a mais: minutos do Actions para as execuções de deploy, dentro do seu plano. | Cada pedido tem um limite de gasto (US$5 por padrão), que você pode mudar por projeto. Veja [Custos e limites](https://docs.bohr.io/pt-br/agent/costs-and-limits/). ## bohr.io Cloud - Nada para instalar: entre em [app.bohr.io](https://app.bohr.io), assine e conecte as suas contas. - Uma assinatura por conta pessoal, e uma por [organização](https://docs.bohr.io/pt-br/organizations/overview/), paga por um dos admins dela. Os membros de uma organização não precisam de assinatura própria para trabalhar nos projetos dela. - A cobrança é feita pela Stripe. Veja [Assinatura](https://docs.bohr.io/pt-br/billing/subscription/). ## Auto-hospedada - Faça o deploy da instância com o botão **Deploy to Cloudflare** ou com o `wrangler`, e depois crie o app do GitHub dela em `/setup`. Veja [Auto-hospedagem](https://docs.bohr.io/pt-br/self-hosting/overview/). - A instância em si cabe no plano gratuito da Cloudflare para começar; cada usuário ainda precisa do Workers Paid na conta onde os projetos dele rodam. - Você guarda a chave mestra do cofre de credenciais e decide quem pode entrar. :::note Quem roda uma instância guarda os tokens da Cloudflare dos usuários dela (criptografados) e a chave do app do GitHub. Use uma instância em que você confia: o bohr.io Cloud, ou a sua. ::: --- # O que você precisa > As contas e os planos de que cada pessoa precisa para usar a bohr. Source: https://docs.bohr.io/pt-br/introduction/requirements/ ## Para usar a bohr | Você precisa de | Por quê | | --- | --- | | Uma conta no **GitHub** | O seu código fica nos seus repositórios. A bohr os lê e muda pelo app do GitHub dela, apenas nos repositórios que você escolher. | | Uma conta na **Cloudflare** com **Workers Paid** | O Worker de cada projeto, o sandbox do agente (um Container) e a homologação rodam ali, e o seu site de produção também. A conta também precisa de um subdomínio `workers.dev`: abra **Workers & Pages** uma vez no painel da Cloudflare para criá-lo. | | Um **provedor de modelo** para o agente | Uma chave da API da Anthropic, um endpoint compatível com a Messages API da Anthropic (OpenRouter, DeepSeek, Kimi, GLM, um proxy LiteLLM…), ou uma assinatura Claude Pro/Max. Sem um, os projetos continuam fazendo deploy do que chega ao GitHub, mas o agente fica desligado. | | No bohr.io Cloud: uma **assinatura** | US$20/mês por conta pessoal ou organização. Não é necessária em uma instância auto-hospedada. | | Opcional: **Telegram** | Para falar com o agente e aprovar publicações pelo celular. O chat web faz tudo sem ele. | ## Para trabalhar no projeto de outra pessoa Só uma conta na bohr. O dono do projeto [convida você](https://docs.bohr.io/pt-br/projects/members/) com um código, ou adiciona você pela [organização](https://docs.bohr.io/pt-br/organizations/members/) dele. Os membros usam a conta da Cloudflare e o agente do dono; não precisam de assinatura, conta da Cloudflare nem chave de modelo próprias. ## Projetos suportados O agente mapeia o seu repositório para a Cloudflare na primeira execução: | No repositório | Produção | Homologação | | --- | --- | --- | | JavaScript/TypeScript ou Python sem Dockerfile | Um Worker com static assets, usando o adaptador oficial do framework para a Cloudflare (OpenNext para Next.js 15.5+, o preset `cloudflare` do Nuxt, `@astrojs/cloudflare`, `@sveltejs/adapter-cloudflare`, React Router ou Remix para Cloudflare). Um site estático simples é só assets. | O servidor de desenvolvimento do framework | | Um Dockerfile | Um Container atrás de um Worker | O servidor de desenvolvimento | | Postgres | Neon na sua conta, via Hyperdrive | Um branch do Neon | | Redis | Upstash na sua conta | `redis-server` no sandbox | | Arquivos gravados no disco local | R2 | Um bucket R2 para a homologação | Serviços com estado, como volumes, MongoDB ou Elasticsearch, não são suportados; o agente avisa e sugere a alternativa mais próxima. Quando uma mudança move as suas filas ou gravações em disco para serviços da Cloudflare, o agente pergunta antes de fazer. --- # Entrar > Entre na bohr com o GitHub ou com um código enviado por e-mail e siga o assistente de Primeiros passos. Source: https://docs.bohr.io/pt-br/getting-started/sign-in/ Abra a instância: [app.bohr.io](https://app.bohr.io) para o bohr.io Cloud, ou o endereço da sua própria instância. ## Com o GitHub Clique em **Entrar com GitHub** e autorize a bohr. O seu nome e o seu e-mail vêm do GitHub. ## Com um código por e-mail 1. Digite o seu e-mail e clique em **Receber código por e-mail**. 2. A bohr envia um **código de 6 dígitos**, válido por 10 minutos. 3. Digite o código e clique em **Entrar**. Um código permite 5 tentativas. Se você pedir códigos demais, a bohr responde *"Muitas tentativas. Aguarde alguns minutos e tente de novo."* :::note Em uma instância auto-hospedada, a entrada por e-mail só aparece quando o administrador a configurou ([como](https://docs.bohr.io/pt-br/self-hosting/optional-features/#login-com-um-código-por-e-mail)). A primeira pessoa que entra em uma instância nova vira a administradora dela. ::: A sua sessão dura 30 dias naquele navegador. **Conta › Sair da conta** encerra a sessão. Você pode adicionar ou remover formas de entrar depois, em [Contas conectadas](https://docs.bohr.io/pt-br/account/connections/). ## O assistente de Primeiros passos Depois da primeira entrada, o painel abre **Primeiros passos**. Ele pede só o que todo usuário configura uma vez: | Passo | O que você faz | | --- | --- | | **Assinatura** | Só no bohr.io Cloud: clique em **Assinar**, pague na Stripe e volte. Veja [Assinatura](https://docs.bohr.io/pt-br/billing/subscription/). | | **Cloudflare** | Crie um token de API e cole. Veja [Conectar a Cloudflare](https://docs.bohr.io/pt-br/getting-started/connect-cloudflare/). | | **GitHub** | Instale o app do GitHub da bohr nos seus repositórios. Veja [Instalar o app do GitHub](https://docs.bohr.io/pt-br/getting-started/install-github-app/). | Quando aparecer **Tudo pronto!**, clique em **Novo projeto**, ou antes em **Configurar o agente** se você ainda não escolheu um provedor de modelo ([Provedores de modelo](https://docs.bohr.io/pt-br/agent/providers/)). :::tip Vai trabalhar só em projetos de uma [organização](https://docs.bohr.io/pt-br/organizations/overview/) da qual você faz parte? Você não precisa desta configuração: os admins da organização já conectaram a assinatura, a conta da Cloudflare e o agente dela. Troque para a organização no menu de contexto no topo do painel. ::: --- # Conectar a Cloudflare > Crie o token de API da Cloudflare de que a bohr precisa, com as permissões certas, e conecte a sua conta. Source: https://docs.bohr.io/pt-br/getting-started/connect-cloudflare/ A bohr cria o Worker de cada projeto, o sandbox do agente e a homologação na **sua** conta da Cloudflare, com um token de API que você fornece. A instância guarda o token criptografado e só o usa para criar e atualizar os Workers dos seus projetos. ## Antes de começar - A conta precisa estar no plano **Workers Paid**: o sandbox do agente é um Cloudflare Container. - A conta precisa de um **subdomínio workers.dev**. Se você nunca abriu **Workers & Pages** no painel da Cloudflare, abra uma vez: isso cria o subdomínio. ## Criar o token 1. No passo **Cloudflare**, clique em **Criar o token na Cloudflare**. Isso abre a página de tokens da Cloudflare com as permissões principais preenchidas. 2. **Antes de salvar, adicione a permissão `Containers: Edit`.** O link não consegue preenchê-la. 3. Crie o token, copie, cole em **Token da API da Cloudflare** e clique em **Conectar**. O token precisa destas permissões: | Permissão | Por quê | | --- | --- | | **Workers Scripts: Edit** | Cria os Workers dos projetos. Também cobre Durable Objects e o subdomínio workers.dev. | | **Account Settings: Read** | Lê os dados da conta. | | **Containers: Edit** | O sandbox do agente. Precisa do plano Workers Paid. **Adicione à mão.** | | **D1: Edit** | Cria o banco de dados dos projetos criados a partir de um [modelo](https://docs.bohr.io/pt-br/getting-started/templates/). Já vem preenchida pelo link; só projetos de modelo precisam dela. | Quando falta alguma coisa, o painel mostra *"O token não tem todas as permissões"* com a lista. Edite o token na Cloudflare (ou crie outro pelo modelo), adicione o que falta e cole de novo. ### Várias contas Se o token enxerga mais de uma conta da Cloudflare, a bohr pede **Escolha a conta da Cloudflare**: escolha aquela em que os seus projetos devem rodar e clique em **Usar esta conta**. ## O que a bohr deixa na sua conta Para você distinguir o trabalho da bohr do seu: - Toda chamada à API da Cloudflare que a bohr faz envia `User-Agent: bohr/ (+https://bohr.io)`; isso aparece no audit log da sua conta. - Os Workers que a bohr cria (o Worker do agente e o Worker da homologação de cada projeto) levam as tags `bohr` e `bohr-project:`, e os deployments deles a mensagem `bohr`. - Os deploys de produção rodam `wrangler deploy --message "bohr" --tag "bohr-"`. ## Depois - As contas conectadas ficam listadas em **Conta › Contas conectadas › Cloudflare**. Você pode [desconectar](https://docs.bohr.io/pt-br/account/connections/) uma conta quando nenhum projeto a usar mais; apague também o token no painel da Cloudflare (**My Profile → API Tokens**). - Uma [organização](https://docs.bohr.io/pt-br/organizations/settings-and-billing/) conecta a própria conta da Cloudflare, separada da sua. --- # Instalar o app do GitHub > Dê à bohr acesso aos repositórios que ela pode usar, pelo app do GitHub dela. Source: https://docs.bohr.io/pt-br/getting-started/install-github-app/ A bohr lê e muda os seus repositórios pelo **app do GitHub** dela, apenas nos repositórios que você selecionar. 1. No passo **GitHub**, clique em **Instalar no GitHub**. A instalação abre em uma nova aba. 2. Escolha a sua conta (ou uma organização de que você é dono) e escolha **Only select repositories** ou **All repositories**. 3. Confirme, volte ao painel e clique em **Já instalei**. ## O que o app pode fazer O GitHub mostra estas permissões antes de você confirmar: | Permissão | Por quê | | --- | --- | | Contents: write | O agente faz push para o branch `homolog`; as aprovações fazem merge na produção | | Pull requests: write | As aprovações abrem pull requests e fazem merge deles; as reversões abrem pull requests de revert | | Workflows: write | A bohr escreve o workflow de deploy. O sandbox do agente nunca recebe esta permissão. | | Secrets: write | Remove os secrets do Actions que versões antigas da bohr escreveram | | Actions: read | A bohr avisa quando o deploy de produção termina e mostra os [Builds](https://docs.bohr.io/pt-br/projects/builds/) | | Metadata: read | Lista os seus repositórios | | Organization › Members: read | As [organizações](https://docs.bohr.io/pt-br/organizations/overview/) espelham os membros da organização do GitHub | | Administration: write | Cria repositórios a partir de [modelos](https://docs.bohr.io/pt-br/getting-started/templates/), só com a sua autorização | Os tokens que a bohr cria a partir do app são de curta duração e restritos a um repositório. O token que o sandbox do agente usa só pode escrever conteúdo. ## Dar acesso a mais repositórios Ao criar um projeto, um repositório que não aparece na lista geralmente significa que o app não o enxerga. Clique em **Dê acesso a mais repositórios no GitHub**, adicione o repositório no GitHub e depois clique em **Atualizar a lista**. Os repositórios que já são projetos da bohr não aparecem na lista. ## Remover o acesso **Conta › Contas conectadas › App do GitHub** lista as contas em que o app está instalado. **Desconectar** desinstala o app daquela conta; os projetos que ainda o usam precisam ser excluídos antes. Os seus repositórios não são alterados. --- # Criar um projeto a partir de um repositório > Transforme um dos seus repositórios do GitHub em um projeto da bohr. Source: https://docs.bohr.io/pt-br/getting-started/create-project/ Um **projeto** é um repositório, um site de produção e um agente. Para criar um, clique em **Novo projeto** na barra lateral. ## 1. Escolha o repositório 1. Em **Como começar**, mantenha **Um repositório meu**. 2. Busque na lista pelo nome ou pela organização e escolha o repositório. Os repositórios privados mostram o selo **Privado**. 3. Confira os dois campos: - **Nome do projeto**: como o projeto aparece na bohr. - **Branch de produção**: as mudanças aprovadas são mescladas neste branch, e o deploy de produção parte dele. O padrão é o branch padrão do repositório. 4. Clique em **Criar o projeto**. O repositório que você quer não aparece? Veja [Dar acesso a mais repositórios](https://docs.bohr.io/pt-br/getting-started/install-github-app/#dar-acesso-a-mais-repositórios). :::note[bohr.io Cloud] Criar projetos exige uma assinatura ativa. Sem ela, o painel mostra *"Para criar projetos no bohr.io Cloud, você precisa de uma assinatura ativa."* com um link para assinar. ::: ## 2. Configuração A bohr cria, na sua conta da Cloudflare: - o **Worker do projeto**, com a fila de pedidos, os membros e o chat; - o **sandbox do agente**, um Container que dorme quando está ocioso; - o **Worker da homologação**, um endereço `workers.dev` não listado que mostra o branch `homolog`. O painel mostra o progresso (*Criando o Worker do projeto*, *Preparando o sandbox do agente*, *Ligando a homologação*, *Quase lá*). Costuma levar de um a três minutos; mantenha a página aberta. Se der errado, o painel mostra *"A configuração do projeto falhou"* com o motivo e uma forma de tentar de novo. As causas mais comuns estão em [Solução de problemas](https://docs.bohr.io/pt-br/reference/troubleshooting/#configuração-do-projeto). ## 3. Bot do Telegram (opcional) A bohr oferece criar um **bot do projeto** no Telegram, para que você e a sua equipe peçam mudanças e aprovem publicações pelo Telegram. Siga os passos (BotFather, `/newbot`, colar o token) ou clique em **Pular e abrir o projeto**. Você pode conectar um bot depois em **Configurações › Agente**. Veja [Telegram](https://docs.bohr.io/pt-br/agent/telegram/). ## 4. O agente prepara o repositório Assim que o projeto fica pronto e o seu [provedor de modelo](https://docs.bohr.io/pt-br/agent/providers/) está configurado, o agente começa a **preparar o repositório** sozinho. Continue em [Primeiro deploy](https://docs.bohr.io/pt-br/getting-started/first-deploy/). ## Projetos em uma organização Para criar o projeto em uma organização, troque para ela primeiro (menu de contexto no topo do painel) e clique em **Novo projeto** ali. O projeto roda na conta da Cloudflare da organização e usa as configurações de agente dela, não importa quem o crie. Veja [Organizações](https://docs.bohr.io/pt-br/organizations/overview/). --- # Começar por um modelo > Crie um projeto a partir de um dos sites prontos da bohr, com repositório e banco de dados D1 próprios. Source: https://docs.bohr.io/pt-br/getting-started/templates/ Um modelo é um site pequeno e útil que você pode publicar na hora e depois mudar pedindo ao agente. A bohr cria um **repositório no GitHub** a partir do modelo, um **banco de dados D1** na sua conta da Cloudflare, e publica o site. ## Criar 1. Clique em **Novo projeto** e, em **Como começar**, escolha **Um modelo**. 2. Escolha um modelo. 3. Preencha: - **Nome do projeto**: também é o nome do repositório no GitHub (letras, números, `.`, `-` e `_`). - **Dono**: onde o repositório é criado no GitHub, **Minha conta pessoal** ou uma das suas organizações. O projeto roda na conta da Cloudflare desse dono. - **Repositório privado**: só quem tem acesso ao repositório vê o código. O site publicado fica aberto de qualquer forma. 4. Clique em **Criar o projeto**. O GitHub pede que você autorize a bohr a criar o repositório em seu nome. O seu token da Cloudflare precisa da permissão **D1: Edit**. Sem ela, o painel diz *"O token da Cloudflare não pode criar bancos de dados D1."* e oferece o link **Editar o token na Cloudflare**. ## A senha de admin Todo modelo tem uma área administrativa em `/admin`. A bohr gera a senha dela e a mostra **uma única vez**, em **Senha da área administrativa**: guarde-a nessa hora. Ela é a [variável do site](https://docs.bohr.io/pt-br/projects/variables/) `ADMIN_PASSWORD`, onde você pode trocá-la depois. O site fica no ar assim que o primeiro deploy termina (alguns minutos). ## Os modelos Todo modelo é um Cloudflare Worker (API em [Hono](https://hono.dev) mais arquivos estáticos) com um banco de dados D1. As páginas falam português do Brasil, inglês e espanhol, conforme o navegador do visitante. | Modelo | O que você ganha | | --- | --- | | **Lista de espera** | Uma página de lançamento que coleta nomes e e-mails de interessados, sem duplicados, com um admin para ver, buscar e exportar as inscrições em CSV. Cada visitante vê a posição dele na fila. | | **Agendamentos** | Uma página de agendamento online em que os clientes escolhem um serviço, um dia e um horário livre, com um admin para confirmar os agendamentos e gerenciar serviços e horários de funcionamento. Os agendamentos nunca se sobrepõem. | | **Link na bio** | Uma página com a sua foto, a sua bio e todos os seus links, com contagem de cliques por link e um admin para editar, esconder e reordenar os links. | | **Formulários e pesquisas** | Monte formulários com perguntas de texto, e-mail, múltipla escolha e avaliação por estrelas, compartilhe o link e veja as respostas em gráficos ou exporte em CSV. | | **Cardápio digital** | Um cardápio online com carrinho, em que os clientes montam o pedido e enviam pelo WhatsApp, com um admin para gerenciar pedidos, itens e preços. | | **Links curtos** | Um encurtador de URLs no seu próprio domínio, com links personalizados, cliques por dia e um admin para criar, editar e desligar links. | O código dos modelos é público nos repositórios `bohr-io/template-` no GitHub (por exemplo `bohr-io/template-waitlist`). ## Como um projeto de modelo é configurado - O `wrangler.jsonc` recebe o nome do Worker (o nome do projeto) e o novo banco de dados. - O `.bohr/deploy.json` e o `.bohr/preview.json` dizem à bohr como fazer o deploy e a homologação. - As mudanças no schema do banco de dados são novos arquivos em `migrations/`; cada deploy de produção os aplica primeiro (veja [Bancos de dados D1](https://docs.bohr.io/pt-br/deploys/d1-databases/)). A partir daí, é um projeto como qualquer outro: peça mudanças ao agente. O README de cada modelo lista ideias, como *"Envie um e-mail de boas-vindas para cada nova inscrição"* na lista de espera. Se algo falhar depois que o GitHub criou o repositório, a bohr desfaz o que criou (banco de dados, projeto), exceto o repositório, e a mensagem de erro informa o nome dele. --- # Primeiro deploy > Como o agente prepara o seu repositório e como o seu site chega à produção pela primeira vez. Source: https://docs.bohr.io/pt-br/getting-started/first-deploy/ Um projeto novo a partir de um dos seus repositórios não faz deploy de nada até o repositório estar **preparado** para a bohr. O agente faz isso na primeira execução. ## Preparando o repositório Quando o projeto fica pronto e o seu [provedor de modelo](https://docs.bohr.io/pt-br/agent/providers/) está configurado, o agente começa sozinho. No chat, você vê o pedido *"Prepare este repositório para a bohr…"* e o andamento dele. O agente: 1. Inspeciona o repositório e decide como ele roda na Cloudflare: static assets, um Worker, ou um Container atrás de um Worker. 2. Escreve o [`.bohr/preview.json`](https://docs.bohr.io/pt-br/deploys/preview-json/), para que a homologação consiga rodar o servidor de desenvolvimento do projeto. 3. Adiciona um `wrangler.jsonc` se o repositório não tiver. 4. Escreve o [`.bohr/deploy.json`](https://docs.bohr.io/pt-br/deploys/deploy-json/), a partir do qual a bohr gera o workflow de produção, `.github/workflows/bohr-deploy.yml`. 5. Faz o build de produção passar. 6. Remove os workflows da bohr v1 (`bohr-io/action`), que falham a cada push. 7. Conta o que encontrou, o que mudou e o que não pode ser suportado. Leva alguns minutos. Enquanto isso, a **Visão geral** do projeto mostra *Preparando o repositório* em **O que falta**. Ainda sem provedor? O projeto espera: assim que você salva as configurações do agente, o agente prepara todos os projetos que estavam esperando. Você também pode começar à mão com **Preparar o repositório** no chat, ou **Preparar repositório** na lista de pendências. ## Publicando pela primeira vez A preparação termina como qualquer outro pedido: com uma **homologação** e os botões **Aprovar e publicar** e **Descartar**. 1. Abra a homologação e confira o site. 2. Clique em **Aprovar e publicar**. A bohr abre um pull request de `homolog` para o seu branch de produção e faz o merge. 3. O merge roda o `bohr-deploy.yml` no GitHub Actions. Ele pede à bohr as suas credenciais da Cloudflare na hora da execução, faz o build do site e roda `wrangler deploy` na sua conta. 4. O chat diz *Produção atualizada* quando a execução termina. Acompanhe em [Builds](https://docs.bohr.io/pt-br/projects/builds/). Agora o seu site é um Worker na sua conta da Cloudflare, no endereço `workers.dev` dele. Adicione o seu próprio domínio em [Domínios](https://docs.bohr.io/pt-br/projects/domains/). :::tip Os projetos de modelo pulam esta etapa: o repositório deles já tem tudo, então o primeiro deploy começa assim que o projeto é criado. ::: ## Quando o agente está desligado Sem um provedor de modelo, um projeto só publica o que chega ao GitHub: um push para o branch de produção roda o workflow de deploy, se o repositório tiver um. O projeto aparece como **Só deploys** na lista. --- # O seu primeiro pedido > Peça uma mudança ao agente, revise na homologação e publique. Source: https://docs.bohr.io/pt-br/getting-started/first-request/ Com o repositório preparado, peça algo pequeno para ver o ciclo inteiro. 1. Abra o projeto e vá em **Agente** (ou abra a visualização do site na **Visão geral** e clique em **Chat**). 2. Em **Peça uma mudança…**, escreva o que você quer, por exemplo: > Mude o título da página inicial para "Pão fresquinho toda manhã" e deixe o botão principal laranja. 3. Aperte Enter para enviar (Shift + Enter quebra a linha). 4. O chat mostra **O agente está trabalhando** com linhas curtas de status (*Editando src/pages/index.astro*, *Executando: npm run build*…). Você pode clicar em **Cancelar o pedido** enquanto ele roda. 5. Quando termina, o agente escreve um resumo do que mudou e do que conferir, e um cartão **Homologação pronta · versão 1** com: - **Ver a homologação**: o site com a mudança, no endereço da homologação; - **Ver as mudanças no GitHub**: o diff exato que você está aprovando; - **Aprovar e publicar** e **Descartar**. 6. Não ficou bem como queria? É só mandar outra mensagem, como *"Deixe o botão um pouco maior"*. O agente continua a mesma conversa e a homologação ganha uma nova versão. 7. Clique em **Aprovar e publicar**. A bohr faz o merge da mudança na produção e o GitHub Actions faz o deploy. O chat avisa quando a produção é atualizada. Pronto. A seguir: - [Dicas para bons pedidos](https://docs.bohr.io/pt-br/agent/tips/) - [A homologação, aprovar e descartar](https://docs.bohr.io/pt-br/agent/previews/) - [Peça pelo Telegram](https://docs.bohr.io/pt-br/agent/telegram/) - [Convide a sua equipe](https://docs.bohr.io/pt-br/projects/members/) --- # Chat no painel > Converse com o agente na página Agente do projeto ou ao lado da visualização do site, acompanhe o trabalho dele e responda às perguntas dele. Source: https://docs.bohr.io/pt-br/agent/chat/ Todo projeto tem uma conversa com o agente, compartilhada por todos os membros, na web e no [Telegram](https://docs.bohr.io/pt-br/agent/telegram/). ## Onde conversar - **Agente** (menu do projeto): a conversa completa, com as decisões sobre a homologação. - **Visão geral › visualização do site**: abra o site em tela cheia e clique em **Chat** para conversar com o agente ao lado dele. **Fechar o chat** esconde de novo. ## Enviando um pedido Digite em **Peça uma mudança…** e aperte Enter (Shift + Enter para uma nova linha). Um pedido pode ter até 20.000 caracteres. - Os pedidos rodam **um de cada vez**, em ordem. Enquanto um roda, os novos esperam; o chat mostra **Pedidos na fila: N**. - Cada membro pode ter até **5 pedidos esperando**. - **Cancelar o pedido** interrompe o que está rodando (ou o tira da fila). Os membros cancelam os próprios pedidos; o dono pode cancelar os de qualquer um. ## Enquanto o agente trabalha **O agente está trabalhando** mostra uma linha curta de status que muda conforme ele avança: *Editando src/App.vue*, *Executando: npm run build*, *Buscando…*. O agente também pode escrever mensagens para você durante a execução. Um pedido pode rodar por no máximo 2 horas, dentro do [orçamento](https://docs.bohr.io/pt-br/agent/costs-and-limits/) dele. ## Quando termina | Resultado | O que você vê | | --- | --- | | Mudanças feitas | Um resumo para quem não é técnico (um título e alguns tópicos) e o cartão **Homologação pronta · versão N** com **Ver a homologação**, **Ver as mudanças no GitHub**, **Aprovar e publicar** e **Descartar**. | | Nada a mudar | O resumo e *Nada mudou na homologação.* | | Uma pergunta | O agente precisa de uma decisão que só você pode tomar. Ele mostra a pergunta com opções em botões; toque em uma ou escreva a sua resposta. A resposta continua o mesmo trabalho. | | Falhou ou foi cancelado | Por que parou. A homologação não foi alterada. | Os pedidos seguintes na mesma homologação continuam a mesma conversa, então *"deixe maior"* tem contexto. Depois que você aprova ou descarta, o próximo pedido começa do zero. ## Quando o agente está desligado *"O agente está desligado porque ainda não tem um provedor."* O dono do projeto (ou um admin da organização) precisa escolher um [provedor de modelo](https://docs.bohr.io/pt-br/agent/providers/). Até lá, o projeto continua publicando o que chega ao GitHub. ## Idioma O agente escreve para você no **Idioma do agente** do projeto (português do Brasil, inglês ou espanhol), definido em **Configurações › Agente**. No Telegram, o bot segue o idioma do Telegram de cada pessoa. --- # Telegram > Converse com o agente e aprove publicações pelo bot do Telegram do projeto, e os comandos que ele entende. Source: https://docs.bohr.io/pt-br/agent/telegram/ Cada projeto pode ter o próprio **bot do Telegram**. É a mesma conversa do chat web: você pede mudanças, abre a homologação e aprova ou descarta com botões. ## Conectar um bot 1. No Telegram, abra o **@BotFather** e mande `/newbot`. 2. Escolha um nome e um nome de usuário que termine em `bot`. 3. Copie o token que o BotFather manda (ele se parece com `123456789:AA…`). 4. No projeto, abra **Configurações › Agente**, cole o token em **Telegram** e clique em **Conectar o bot**. (O fluxo de novo projeto oferece o mesmo passo.) Só o dono do projeto conecta o bot. Para deixar de usá-lo, apague o bot com o BotFather; a bohr não apaga bots de projeto. ## Vincular a sua conta do Telegram O bot reconhece as pessoas pela conta delas na bohr. Em **Conta**, clique em **Vincular o Telegram**, depois em **Abrir no Telegram** e toque em **Iniciar**. O link vale por alguns minutos. (Isso exige o bot da plataforma da instância, que o bohr.io Cloud tem; em uma instância auto-hospedada, o administrador o configura.) Quem ainda não é membro recebe: *"Você ainda não tem acesso ao projeto … Peça um convite ao dono e mande /entrar <código>."* ## Conversando com o bot - **Em uma conversa privada**, toda mensagem é um pedido. - **Em um grupo**, o bot responde às mensagens que o mencionam (`@seu_bot`), às respostas às mensagens dele e aos comandos. Enquanto o agente trabalha, o bot mantém uma mensagem de status atualizada. Quando termina, ele manda o resumo e os botões **Aprovar e publicar**, **Descartar**, **🔎 Ver a homologação** e **Ver as mudanças no GitHub**, presos àquela versão da homologação: um botão apertado em uma versão antiga responde *"A homologação mudou desde esta mensagem."* ## Comandos Cada comando também tem um nome em inglês e em espanhol. | Comando | Também | O que faz | | --- | --- | --- | | `/status` | `/estado` | O pedido em andamento, a fila e a homologação | | `/aprovar`, `/descartar` | `/approve`, `/aprobar`, `/discard` | Mostra as mudanças da homologação atual com os botões para decidir | | `/cancelar` | `/cancel` | Cancela o seu pedido em andamento ou na fila | | `/rollback` | `/reverter`, `/revertir` | Volta a produção para a versão anterior | | `/convidar` | `/invite`, `/invitar` | Cria um código de convite (dono) | | `/entrar ` | `/join`, `/unirse` | Entra no projeto com um código de convite | | `/membros` | `/members`, `/miembros` | Lista os membros com números | | `/revogar ` | `/revoke`, `/revocar` | Remove um membro (dono) | | `/modelo ` | `/model` | Define o modelo do projeto (dono) | | `/orcamento ` | `/budget`, `/presupuesto` | Define o orçamento por pedido, de 0,10 a 1000 (dono) | | `/ajuda` | `/help`, `/ayuda` | Lista os comandos | Os comandos `/aprovar` e `/descartar` digitados nunca agem sozinhos: eles mostram os botões da versão que você está vendo, para que você sempre decida sobre o que revisou. ## O bot da plataforma As instâncias com um bot da plataforma (como a do bohr.io Cloud) também deixam você fazer a configuração inicial pelo Telegram: `/novo` cria um projeto, `/status` lista os seus projetos e `/tentar` refaz o último passo que falhou. As configurações do agente continuam sendo escolhidas no painel web. --- # A homologação > Revise as mudanças do agente na homologação e depois aprove para a produção ou descarte. Source: https://docs.bohr.io/pt-br/agent/previews/ A **homologação** é o seu site rodando a partir do branch `homolog`, onde o agente faz commit do trabalho dele. Ela junta as mudanças de todos os pedidos concluídos até alguém aprovar ou descartar. ## O estado dela O projeto mostra a homologação em um de três estados: | Estado | Significado | | --- | --- | | **Igual à produção** | `homolog` é igual à produção. Nada para revisar. | | **Mudanças para revisar** | O agente fez push de mudanças sobre as quais ninguém decidiu ainda. Cada push é uma nova **versão** (1, 2, 3…). | | **Publicando** | Alguém aprovou; a bohr está fazendo o merge e o GitHub Actions está fazendo o deploy. | ## Revisando Use **Ver a homologação** na Visão geral ou no chat, ou escolha **Homologação** no seletor da visualização do site em tela cheia (abrir o **Chat** ali muda para ela): - Ao lado do seletor, *Igual à produção* ou *Com 2 alterações* (passe o mouse para ver o que mudou). - Troque entre **Computador**, **Tablet** e **Celular**, ou abra numa nova aba. - O cartão da homologação na Visão geral lista o que o agente fez, com **Aprovar e publicar** e **Descartar**. - **Ver as mudanças no GitHub**, no chat, abre o diff exatamente do commit que a aprovação publica. O chat nunca mostra o endereço da homologação: no Telegram, ela abre pelo botão **🔎 Ver a homologação**. O endereço da homologação é público, mas não listado: um nome `workers.dev` impossível de adivinhar, marcado como `noindex` para os buscadores. Compartilhe com quem precisa revisar. A homologação é o **servidor de desenvolvimento** do projeto rodando no sandbox do agente, como configurado em [`.bohr/preview.json`](https://docs.bohr.io/pt-br/deploys/preview-json/). O sandbox dorme quando está ocioso: a primeira visita depois de um tempo mostra *"A homologação está iniciando. Esta página recarrega sozinha."* enquanto ele instala e inicia de novo. ## Aprovar e publicar Qualquer membro pode aprovar. **Aprovar e publicar**: 1. abre (ou reaproveita) um pull request de `homolog` para o branch de produção; 2. faz squash merge dele **só se o head ainda for a versão que você revisou**, para que mudanças enviadas depois da sua revisão não passem junto; 3. redefine `homolog` para o merge, e o próximo pedido começa uma conversa nova; 4. o GitHub Actions faz o deploy da produção. O chat diz *Produção atualizada* quando a execução termina, ou *O deploy de produção falhou* com um link para a execução. Você não pode decidir enquanto um pedido está rodando (*"Aguarde o pedido em andamento terminar antes de decidir."*). Um pedido que termina enquanto uma aprovação está publicando espera a próxima aprovação. ## Descartar **Descartar** (confirme em *Descartar as mudanças?*) redefine `homolog` para a produção. As mudanças que não foram publicadas se perdem, e o próximo pedido começa uma conversa nova. ## Aprovando pelo Telegram O bot do projeto manda os mesmos botões, presos à versão com que foram enviados. Veja [Telegram](https://docs.bohr.io/pt-br/agent/telegram/). --- # Versões e reversão > Todas as publicações que a bohr fez, e como voltar a produção para a versão anterior. Source: https://docs.bohr.io/pt-br/agent/versions-and-rollback/ Cada aprovação vira um pull request mesclado no branch de produção, e o GitHub Actions o publica. **Versões** (menu do projeto) lista essas publicações, das mais novas para as mais antigas. ## A lista Cada publicação mostra quando foi **Publicada**, o pull request **via** o qual veio (**PR #N**, ou um **commit direto**), links para **Ver PR** e **Ver commit**, e o status: | Status | Significado | | --- | --- | | **Publicando** | A execução do GitHub Actions está fazendo o deploy | | **No ar** | A execução terminou; a produção a serve | | **Falhou** | A execução falhou; a produção manteve a versão anterior | | **Revertida** | Uma reversão a desfez | ## Reverter Clique em **Reverter a última publicação** e confirme. A bohr abre e faz o merge de um pull request que **desfaz** o pull request da última publicação, usando o revert do GitHub. Em seguida, o GitHub Actions publica a versão anterior. No Telegram, mande `/rollback` (ou `/reverter`). - Reverter também é uma publicação: aparece na lista e também pode ser revertida. - A reversão desfaz o código. Os dados que o seu site gravou (por exemplo, linhas em um banco de dados D1) e as migrações de schema que já rodaram não são desfeitos. - Se o GitHub não consegue reverter de forma limpa (uma mudança posterior mexeu nas mesmas linhas), a bohr diz *"Não consegui reverter"* com o motivo. Nesse caso, peça ao agente para desfazer a mudança. ## Mudanças feitas fora da bohr Os pushes para o branch de produção que não vieram de uma aprovação (seus, da sua equipe ou de outra ferramenta) também fazem deploy, pelo mesmo workflow. Eles aparecem em [Builds](https://docs.bohr.io/pt-br/projects/builds/). --- # Provedores de modelo > Dê vida ao agente com uma chave da API da Anthropic, um endpoint compatível com a Anthropic ou a sua assinatura Claude Pro/Max. Source: https://docs.bohr.io/pt-br/agent/providers/ O agente precisa de um modelo. Você o escolhe uma vez em **Conta › Agente** (**Configurar o agente**), e ele vale para todos os projetos de que você é dono. Uma [organização](https://docs.bohr.io/pt-br/organizations/settings-and-billing/) escolhe o dela para os projetos dela. A chave fica guardada criptografada e chega ao Worker de cada projeto como um secret. O sandbox do agente nunca a vê: ele guarda um marcador, e a bohr acrescenta a chave real na saída. ## Chave da API da Anthropic (recomendado) 1. Crie uma chave no [Anthropic Console](https://console.anthropic.com). Ela começa com `sk-ant-`. 2. Em **Provedor**, escolha **Chave da API da Anthropic** e cole a chave em **Chave da API da Anthropic**. 3. **Modelo**: deixe em branco para usar o padrão da bohr, `claude-opus-5-5`, ou digite o id de outro modelo Claude. 4. **Esforço**: o quanto o modelo pensa antes de agir. **Padrão do modelo**, **Baixo**, **Médio**, **Alto**, **Muito alto** ou **Máximo**. Mais esforço significa um trabalho mais cuidadoso e mais tokens. 5. Clique em **Salvar**. A bohr confere a chave com a Anthropic antes de salvar. ## Provedor compatível Qualquer API compatível com a Messages API da Anthropic: OpenRouter, DeepSeek, Kimi, GLM, um proxy LiteLLM na frente de outros provedores… | Campo | Valor | | --- | --- | | **URL base** | O endereço da API antes de `/v1/messages`, com `https`. Por exemplo `https://openrouter.ai/api` ou `https://api.deepseek.com/anthropic`. | | **Chave da API do provedor** | A chave que o seu provedor deu. A bohr confere se o provedor a aceita. | | **Modelo** | Obrigatório: o nome do modelo no provedor, como `deepseek-chat` ou `moonshotai/kimi-k2`. | | **Esforço** | Opcional. Provedores compatíveis podem ignorá-lo. | O quanto o agente funciona bem depende do modelo: ele edita arquivos, roda comandos e segue instruções longas. ## Assinatura Claude (Pro/Max) Use o seu plano Claude Pro ou Max em vez de uma chave de API. O agente roda pelo Claude Code oficial, e o uso está sujeito aos termos e limites da sua assinatura. 1. Escolha **Assinatura Claude (Pro/Max)** e clique em **Conectar assinatura Claude**. 2. Clique em **Autorizar no claude.ai** e autorize com a sua conta Claude. 3. Copie o código que o claude.ai mostra, cole em **Código de autorização** e clique em **Concluir conexão**. Por trás, a bohr roda o `claude setup-token` da CLI oficial em um container isolado e guarda o token de longa duração que ele cria (começa com `sk-ant-oat01-`). **Já tenho um token**: em um terminal com o Claude Code instalado, rode: ```sh claude setup-token ``` entre com a sua conta e cole o token que ele mostra em **Token do Claude Code**. :::note Em algumas instâncias auto-hospedadas, a conexão roda no container de um dos seus projetos. Se nenhum estiver pronto ainda, o painel avisa: crie um projeto primeiro, ou cole um token do `claude setup-token`. ::: Com uma assinatura, nada é cobrado por pedido. O [orçamento por pedido](https://docs.bohr.io/pt-br/agent/costs-and-limits/) continua valendo, como um limite de segurança estimado a preços da API. ## Mudar ou remover - Salvar aplica as novas configurações a todos os projetos prontos de uma vez (*Salvo e aplicado a N projetos.*). Os projetos que estavam esperando um agente começam a [preparar o repositório](https://docs.bohr.io/pt-br/getting-started/first-deploy/). - Para manter a chave guardada e mudar só o modelo ou o esforço, deixe o campo da chave em branco. - **Remover** (*Desligar o agente?*) apaga a chave e desliga o agente em todos os seus projetos. Os deploys pelo GitHub continuam funcionando. - Um projeto pode usar um **modelo** diferente do da sua conta: veja [Configurações do projeto](https://docs.bohr.io/pt-br/projects/settings/#agente). --- # O que o agente pode e não pode fazer > As ferramentas do agente, o sandbox dele e os limites que a bohr coloca em volta dele. Source: https://docs.bohr.io/pt-br/agent/capabilities/ O agente é construído com o Claude Agent SDK e roda em um **sandbox** isolado (um Cloudflare Container na conta do dono do projeto) com uma cópia nova do seu repositório. ## O que ele pode fazer - **Ler e mudar qualquer arquivo** do repositório, e criar novos. - **Rodar comandos**: instalar dependências, fazer o build, rodar testes, checagem de tipos e linters. Ele é instruído a rodar as checagens do projeto antes de terminar e a corrigir o que a mudança dele quebrou. - **Buscar** no código, e pesquisar na web quando o modelo suporta. - **Rodar a homologação**: manter o `.bohr/preview.json` funcionando para você ver a mudança. - **Configurar a produção**: manter o `.bohr/deploy.json` e a configuração do wrangler funcionando quando uma mudança afeta o build. - **Perguntar a você** quando uma decisão é sua (uma escolha entre alternativas que ele não consegue deduzir), com opções em botões. - **Seguir as instruções do seu repositório**: ele lê o `CLAUDE.md` e o `.claude/settings.json` do repositório. - **Manter o contexto** entre os pedidos seguintes na mesma homologação. No fim de cada pedido, ele escreve um resumo para quem não é técnico: um título (que vira a mensagem do commit) e alguns tópicos sobre o que mudou e o que conferir. ## O que ele não pode fazer | Ele não pode | Porque | | --- | --- | | Publicar na produção | Ele só consegue fazer push para `homolog`. A produção só muda quando alguém aprova. | | Fazer push, pull, merge, rebase ou trocar de branch | A bohr faz commit de tudo o que ficou na working tree e faz push para `homolog` quando o agente termina. | | Mudar workflows do GitHub Actions | O GitHub recusa mudanças em `.github/workflows` vindas do token do sandbox, e a bohr restaura esses arquivos antes do commit. Se um workflow precisar de mudança, o agente avisa no resumo. | | Mudar remotes do git, credenciais ou o `.git` | Recusado pelas proteções da bohr. | | Escrever fora do repositório e do `/tmp` | Recusado pelas proteções da bohr. | | Ver as suas chaves | O sandbox só guarda marcadores; a bohr acrescenta a chave real do modelo e um token do GitHub de curta duração na saída, só enquanto um pedido roda. | | Guardar arquivos entre sessões | O disco do sandbox é apagado quando ele dorme; só fica o que foi enviado ao GitHub. | | Rodar git hooks | Os commits e pushes pulam os hooks; em vez disso, o próprio agente roda as checagens. | Arquivos que nunca entram no commit, mesmo quando o `.gitignore` não os cobre: `node_modules/`, `.venv/`, `__pycache__/` e `.wrangler/`. ## Quando um pedido falha Um pedido para quando atinge o **orçamento** ou o **máximo de turnos**, por um erro, ou quando alguém o cancela. Aí `homolog` volta para onde estava antes do pedido: nada feito pela metade é enviado. O chat explica o motivo, no seu idioma. Veja [Custos e limites](https://docs.bohr.io/pt-br/agent/costs-and-limits/). ## Serviços com estado e bancos de dados Na primeira execução, o agente mapeia o projeto para a Cloudflare (veja [O que você precisa](https://docs.bohr.io/pt-br/introduction/requirements/#projetos-suportados)). Quando um projeto precisa de um banco de dados ou de Redis e não há dados de conexão configurados, o agente explica o que você precisa fornecer. Mudanças que movem filas para o Cloudflare Queues ou gravações em disco para o R2 mudam o seu código, então o agente pergunta antes de fazê-las. --- # Custos e limites > Quanto custa cada pedido, os limites de orçamento e de turnos, e como mudá-los. Source: https://docs.bohr.io/pt-br/agent/costs-and-limits/ ## Custo de cada pedido O agente gasta tokens do modelo aos preços do seu provedor, e você paga isso ao seu provedor, não à bohr; com uma [assinatura Claude](https://docs.bohr.io/pt-br/agent/providers/#assinatura-claude-promax), eles fazem parte dela. O chat nunca fala de custo: o console do seu provedor mostra quanto você gastou. O tempo de Container é cobrado pela Cloudflare da conta que roda o projeto: o sandbox roda enquanto o agente trabalha e enquanto a homologação está sendo visitada, e depois dorme. ## Limites por pedido | Limite | Padrão | Onde mudar | | --- | --- | --- | | **Orçamento por pedido (US$)** | 5 | **Configurações › Agente** (dono), ou `/orcamento` no Telegram: de 0,10 a 1000. | | **Máximo de turnos** | 200 | **Configurações › Agente** (dono): de 1 a 1000. Um turno é uma rodada de trabalho do agente. | | Tempo de execução | 2 horas | Fixo | | Tamanho do pedido | 20.000 caracteres | Fixo | | Pedidos esperando | 5 por membro | Fixo | Quando um pedido atinge o orçamento, ele para e nada é enviado: *"o pedido chegou ao limite por pedido antes de o trabalho terminar. O dono pode aumentar esse limite nas configurações do agente."* Com uma assinatura Claude, o orçamento é um limite de segurança estimado a preços da API; nada é cobrado à parte. ## Mantendo os custos baixos - Peça uma coisa de cada vez e seja específico (veja as [Dicas](https://docs.bohr.io/pt-br/agent/tips/)). - Diminua o **Esforço** em [Provedores de modelo](https://docs.bohr.io/pt-br/agent/providers/) para projetos simples. - Escolha um modelo menor para um projeto em **Configurações › Agente › Modelo**. - Aprove ou descarte quando terminar: os pedidos seguintes em uma homologação longa carregam a conversa inteira. --- # Dicas para bons pedidos > Como pedir para o agente acertar de primeira. Source: https://docs.bohr.io/pt-br/agent/tips/ O agente escreve para quem não programa, e funciona melhor com pedidos que dizem **o que** você quer e **onde**, em palavras simples. ## Faça - **Diga o lugar.** *"Na página de preços, abaixo dos três planos…"* é melhor que *"adicione um aviso em algum lugar"*. - **Descreva o resultado, não o código.** *"Os visitantes devem conseguir mandar uma mensagem com nome e e-mail, e a gente recebe por e-mail"*. - **Dê o texto exato** quando as palavras importam: *"Mude o título para: Pão fresquinho toda manhã"*. - **Uma mudança por pedido**, e depois ajuste. Pedidos pequenos são mais rápidos, mais baratos e mais fáceis de revisar. - **Diga o que manter.** *"Mantenha as cores atuais"*, *"Não mude o menu"*. - **Use pedidos seguintes.** O agente lembra a conversa até você aprovar ou descartar: *"Agora deixe menor no celular"*. - **Cite os segredos pelo nome, nunca pelo valor.** *"Use a variável RESEND_API_KEY para mandar o e-mail"*, e depois adicione a variável em [Variáveis de ambiente](https://docs.bohr.io/pt-br/projects/variables/). ## Evite - Colar senhas, chaves de API ou tokens no chat. O chat fica guardado e é compartilhado com todos os membros. - Pedidos enormes e vagos (*"refaça o site inteiro"*). Divida em etapas. - Pedir ao agente para fazer deploy ou merge: aprovar já faz isso. - Pedir para ele mudar workflows do GitHub: ele não consegue (veja [o que ele pode fazer](https://docs.bohr.io/pt-br/agent/capabilities/)). ## Exemplos > Adicione uma seção de perguntas frequentes no fim da página inicial com estas três perguntas e respostas: … > O formulário de contato mostra um erro no celular. Corrija e confira se funciona em uma tela pequena. > Adicione uma página /equipe com foto, nome e cargo de cada pessoa desta lista: … > Crie um formulário de lista de espera que salve nome e e-mail no banco de dados, e uma página /admin protegida pela variável ADMIN_PASSWORD para ver as inscrições. ## Revise bem - Abra a homologação também no **Celular**. - Leia o resumo: ele lista o que conferir. - Na dúvida, use **Ver as mudanças no GitHub**: mostra exatamente o que a aprovação publica. --- # A página do projeto > A lista de projetos, o menu do projeto e a visão geral. Source: https://docs.bohr.io/pt-br/projects/overview/ ## A lista de projetos **Projetos** mostra os seus projetos (ou os da organização atual). Cada cartão mostra o repositório, os endereços de produção e de homologação, o bot do Telegram, se houver, e uma situação: | Situação | Significado | | --- | --- | | **Agente pronto** | O Worker do projeto está rodando e o agente pode trabalhar | | **Configurando** | A bohr está criando o Worker, o sandbox e a homologação do projeto | | **Falha na configuração** | Abra o projeto para ver o motivo e tente de novo | | **Só deploys** | Sem agente: o projeto publica o que chega ao GitHub | | **Migrando** | Um projeto da bohr v1 sendo transferido | | **Suspenso** | O projeto não faz deploy; fale com o administrador da instância | Projetos em que você é membro, mas não dono, mostram o selo **Membro**. ## O menu do projeto | Página | Para que serve | | --- | --- | | **Visão geral** | Endereços, a atividade do agente, a homologação, a última versão e o que falta | | **Agente** | O [chat](https://docs.bohr.io/pt-br/agent/chat/) com o agente | | **Versões** | [Publicações e reversão](https://docs.bohr.io/pt-br/agent/versions-and-rollback/) | | **Builds** | As [execuções do GitHub Actions](https://docs.bohr.io/pt-br/projects/builds/) com os logs | | **Membros** | [Quem participa do projeto](https://docs.bohr.io/pt-br/projects/members/) e os convites | | **Configurações** | [Geral, Domínios, Variáveis de ambiente, Autenticação, Agente, Hospedagem](https://docs.bohr.io/pt-br/projects/settings/) | O cabeçalho tem links para o site em produção, a homologação e o repositório no GitHub. ## Visão geral - **Endereços**: **Produção** e **Homologação**. A homologação fica *Disponível quando o agente estiver ligado*. - **Agente**: *Trabalhando em:* o pedido atual, ou *Nenhum pedido em andamento.*, o número de pedidos na fila e **Abrir o agente**. - A situação da homologação: *A homologação está igual à produção.* ou o que mudou, com **Aprovar e publicar** e **Descartar**, e **Ver a homologação**. - **Última versão**: a última publicação e **Ver as versões**. - **O que falta**: uma lista do que ainda depende de você, por exemplo *O agente não está configurado*, *Repositório não preparado* (com **Preparar repositório**), *Nenhum build ainda* ou *A configuração do projeto falhou*. ### A visualização do site Clique no site na Visão geral para abri-lo em tela cheia. A barra mostra a **Versão mostrada** (**No ar**, branch, **Última atualização**, **Hash**, **Ver logs**), deixa você girar o dispositivo e **Abrir em nova aba**, e **Chat** abre o agente ao lado do site, mudando a visualização para a homologação. Ao lado do seletor, a homologação aparece *Igual à produção* ou com alterações (*Com 2 alterações*; passe o mouse para ver o que mudou). ## Quem pode fazer o quê | | Dono | Membro | | --- | --- | --- | | Pedir mudanças, aprovar, descartar, reverter | Sim | Sim | | Cancelar pedidos | De qualquer pessoa | Os próprios | | Convidar e remover membros | Sim | Não | | Configurações (variáveis, domínios, autenticação, agente) | Sim | Só leitura | | Excluir o projeto | Sim | Não | Numa [organização](https://docs.bohr.io/pt-br/organizations/overview/), os admins da organização são donos de todos os projetos; os membros dela são membros. --- # Builds > As execuções do GitHub Actions no repositório do projeto, com os jobs e os logs. Source: https://docs.bohr.io/pt-br/projects/builds/ **Builds** lista as execuções do GitHub Actions no repositório: cada deploy, com os passos e os logs, sem sair da bohr. - Cada execução mostra o título, o número, o branch, a situação e quando rodou. **Ver no GitHub** abre a execução lá. - Abra uma execução para ver os jobs e o **Log** de cada job. Enquanto uma execução está em andamento, *esta página se atualiza sozinha*. - **Atualizar** recarrega a lista. | Situação | Significado | | --- | --- | | **Na fila** | Esperando um runner | | **Rodando** | Em andamento | | **Sucesso** | Terminou; num deploy, a produção já serve essa versão | | **Falhou** | Um passo falhou; abra o log dele | | **Cancelado** | Cancelado no GitHub | | **Ignorado** | O GitHub pulou a execução | | **Precisa de ação** | O GitHub precisa que alguém aja (por exemplo, aprovar uma execução) | *Nenhum build ainda* quer dizer que o GitHub Actions ainda não rodou no repositório. Num projeto novo, o primeiro deploy roda depois que você aprova a [preparação do repositório](https://docs.bohr.io/pt-br/getting-started/first-deploy/) feita pelo agente. Quando um deploy falha, o chat avisa *"O deploy de produção falhou"* com um link para a execução, e a produção continua servindo a versão anterior. Peça ao agente para corrigir, colando a linha do erro se quiser: *"O deploy falhou com: …. Corrija."* Veja também [Solução de problemas](https://docs.bohr.io/pt-br/reference/troubleshooting/#deploys). --- # Membros e papéis > Convide pessoas para um projeto com códigos de uso único e gerencie quem tem acesso. Source: https://docs.bohr.io/pt-br/projects/members/ Todos num projeto podem pedir mudanças e aprovar publicações. Só o **dono** gerencia chaves, configurações e acessos. | Papel | Pode | | --- | --- | | **Dono** | Tudo: configurações, variáveis, domínios, autenticação, convites, remover membros, excluir o projeto | | **Membro** | Pedir mudanças, aprovar, descartar e reverter, cancelar os próprios pedidos, ver as configurações | O dono do projeto é quem o criou. Numa [organização](https://docs.bohr.io/pt-br/organizations/members/), os admins da organização são os donos de todos os projetos dela, e os membros dela são membros: eles não precisam de convite. ## Convidar alguém 1. Abra **Membros** e, em **Convidar alguém**, clique em **Gerar código de convite**. 2. Compartilhe o código (**Copiar o código**) ou o link (**Copiar o link**). O código é de uso único e vale por **24 horas**. 3. A pessoa: - abre o link, entra com a própria conta e encontra o código já preenchido (**Entrar no projeto**); ou - manda `/entrar ` para o bot do projeto no Telegram. Os códigos têm o formato `K7P2-9QXM` e são tolerantes quando digitados à mão: maiúsculas e minúsculas, espaços e as letras `I`, `L` e `O` não atrapalham. No Telegram, o dono também pode mandar `/convidar`. ## Remover alguém Clique em **Remover** ao lado da pessoa e confirme. Ela perde o acesso ao projeto na web e no Telegram na hora, e os pedidos dela que estavam esperando são cancelados. O dono não pode ser removido. No Telegram: `/membros` lista as pessoas com números, e `/revogar ` remove uma delas. --- # Configurações do projeto > As páginas Geral, Agente e Hospedagem das configurações de um projeto. Source: https://docs.bohr.io/pt-br/projects/settings/ **Configurações** tem um menu próprio: **Geral**, **Domínios**, **Variáveis de ambiente**, **Autenticação**, **Agente** e **Hospedagem**. Os membros podem ler; só o dono muda. - [Domínios](https://docs.bohr.io/pt-br/projects/domains/) - [Variáveis de ambiente](https://docs.bohr.io/pt-br/projects/variables/) - [Autenticação](https://docs.bohr.io/pt-br/projects/password-protection/) ## Geral Os dados do projeto nesta instância: | Campo | | | --- | --- | | **Nome** | O nome do projeto na bohr | | **Repositório** | `owner/name` no GitHub | | **Branch de produção** | As mudanças aprovadas são mescladas aqui, e o deploy de produção parte dele | | **Endereço de produção** | O endereço do site, ou *Ainda não publicado* | | **Hospedagem** | **Sua conta da Cloudflare**, ou **Hospedado pela bohr** para projetos migrados da v1 | | **Agente** | Se o agente está ligado | | **ID do projeto** | O id que a [CLI](https://docs.bohr.io/pt-br/cli/commands/) e a API usam, como `p3k9x0a7qd2m` | O fim desta página tem a [Zona de perigo](https://docs.bohr.io/pt-br/projects/delete/). ## Agente | Configuração | | | --- | --- | | **Modelo** | O modelo que o agente usa neste projeto, no lugar do escolhido nas configurações da conta | | **Orçamento por pedido (US$)** | O agente para quando o custo de um pedido chega a este valor. Padrão: 5. | | **Máximo de turnos** | Quantas rodadas o agente pode fazer em um pedido, de 1 a 1000. Padrão: 200. | | **Idioma do agente** | Idioma das respostas do agente e do bot do projeto: Português, English ou Español | **Telegram** mostra o bot do projeto (**Abrir no Telegram**) ou deixa o dono conectar um com um token do BotFather. Veja [Telegram](https://docs.bohr.io/pt-br/agent/telegram/). **Provedor e chave** ficam nas configurações da sua conta e valem para todos os seus projetos: **Abrir as configurações do agente** ([Provedores de modelo](https://docs.bohr.io/pt-br/agent/providers/)). ## Hospedagem - **Na sua conta da Cloudflare**: o site, o agente e a homologação do projeto rodam na sua conta da Cloudflare. Não há nada a fazer. - **Hospedado pela bohr**: um projeto migrado da bohr v1, ainda na conta da Cloudflare da bohr. Esta página permite movê-lo para a sua própria conta. Veja [Mover para a sua conta da Cloudflare](https://docs.bohr.io/pt-br/migrating-from-v1/move-to-your-cloudflare/). --- # Variáveis de ambiente > Variáveis do site para o Worker de produção e variáveis do build para o build no GitHub Actions, inclusive secrets. Source: https://docs.bohr.io/pt-br/projects/variables/ **Configurações › Variáveis de ambiente** tem duas listas. Só o dono muda as variáveis; os membros veem os nomes e os valores das variáveis comuns. ## Variáveis do site Elas chegam ao **Worker de produção** do site em tempo de execução (`env.NAME` num Worker). - **Na sua conta da Cloudflare**, toda variável do site fica guardada como um secret do Worker de produção, então sobrevive aos deploys, e as mudanças valem na hora. A bohr guarda os valores comuns só para mostrá-los. - **Hospedado pela bohr** (migrado da v1): as secretas valem na hora; as comuns, a partir do próximo deploy. Uma variável do site só pode ser definida depois que o Worker do site existe: publique o site uma vez antes. Se o mesmo nome já estiver como uma entrada comum de `vars` no seu `wrangler.jsonc`, a bohr responde *"… is already set in the site's wrangler config: change it there."* ## Variáveis do build Elas ficam guardadas **criptografadas** na bohr e são entregues ao GitHub Actions quando ele instala e faz o build do site (por exemplo `NEXT_PUBLIC_API_URL`, `SENTRY_AUTH_TOKEN`). Valem a partir do próximo deploy. O workflow de deploy pede essas variáveis à bohr durante a execução, com o token OIDC do GitHub da execução, junto com as credenciais da Cloudflare. Nada fica guardado nos secrets do seu repositório. Veja [O workflow de deploy](https://docs.bohr.io/pt-br/deploys/deploy-workflow/). ## Adicionar uma variável 1. Clique em **Nova variável**. 2. Digite o **Nome** e o **Valor**. Os nomes usam letras, números e `_`, começando por uma letra ou `_`. 3. Marque **Secreta** para tudo o que for sensível: depois de salvo, o valor fica oculto e não pode ser mostrado de novo (*Valor oculto — digite para trocar*). 4. Clique em **Salvar**. Nomes que a bohr ou o GitHub já usam são recusados: tudo o que começa com `GITHUB_`, `CLOUDFLARE_` ou `BOHR_`, e `CI`. ## No seu código ```ts // Um Worker: as variáveis do site ficam em env export default { async fetch(request: Request, env: { RESEND_API_KEY: string }) { // use env.RESEND_API_KEY return new Response('ok'); }, }; ``` As variáveis do build são variáveis de ambiente comuns durante o `install` e o `build` (`process.env.NEXT_PUBLIC_API_URL`). :::caution Os valores em `vars` comuns do `wrangler.jsonc` vão para o commit no seu repositório. Coloque secrets em **Variáveis do site** marcadas como **Secreta**, nunca no repositório nem no chat. ::: ## Projetos de modelo Projetos criados a partir de um [modelo](https://docs.bohr.io/pt-br/getting-started/templates/) têm uma variável do site `ADMIN_PASSWORD` (secreta) com a senha da área administrativa. Troque-a aqui. --- # Proteção por senha > Peça usuário e senha (Basic Auth) aos visitantes antes de abrirem o site. Source: https://docs.bohr.io/pt-br/projects/password-protection/ **Configurações › Autenticação** coloca usuário e senha (HTTP Basic Auth) na frente do seu site de produção. Use para um site que ainda não é público, ou para o site de staging de um cliente. 1. Em **Método**, escolha **Basic Auth** (ou **Nenhum** para desligar a proteção). 2. Em **Usuários**, adicione pelo menos um **Usuário** e **Senha** (**Novo usuário** adiciona mais). Os nomes de usuário não podem ter espaços nem `:`. 3. Opcional: em **URLs liberadas**, adicione caminhos que abrem sem senha (**Nova URL**). Cada caminho começa com `/`: o caminho exato, ou todos os caminhos que começam com ele quando termina com `*` (por exemplo `/api/webhooks/*`). 4. Clique em **Salvar**. A proteção passa a valer em alguns segundos, sem deploy. Para trocar uma senha, digite uma nova; deixar em branco mantém a atual (*Senha mantida — digite para trocar*). A bohr guarda só hashes PBKDF2-SHA256 com salt, nunca as senhas. ## Como funciona - **Na sua conta da Cloudflare**: o workflow de deploy da bohr envolve o seu site numa pequena barreira que confere as credenciais. As configurações ficam num secret do seu Worker de produção (`BOHR_SITE_AUTH`), então ligar ou desligar a proteção não exige deploy. A barreira gera `.bohr-gate.mjs` e `wrangler.bohr-gate.json` na hora do deploy; eles nunca vão para o commit. - **Hospedado pela bohr**: a borda da bohr confere as credenciais antes de o seu Worker rodar. :::caution[Comandos de deploy próprios] A barreira só envolve sites publicados com o comando padrão, `npx wrangler deploy`. Se o seu [`.bohr/deploy.json`](https://docs.bohr.io/pt-br/deploys/deploy-json/) define um comando `deploy` próprio, o painel mostra *"A proteção não vale para este site"*: a bohr não consegue colocar a proteção na frente dele. ::: A homologação tem um endereço próprio, não divulgado, e não é coberta por esta configuração. A proteção vale para o site de produção. --- # Domínios próprios > Ligue domínios da sua conta da Cloudflare ao site de produção. Source: https://docs.bohr.io/pt-br/projects/domains/ **Configurações › Domínios** liga domínios ao seu site de produção como **Custom Domains** da Cloudflare no Worker dele. A Cloudflare cria o registro DNS e o certificado automaticamente. ## Antes de começar - O site precisa ter sido **publicado uma vez**: os domínios se ligam ao Worker do site, que nasce no primeiro deploy. Até lá, a página mostra *"O site ainda não foi publicado"*. - O domínio precisa ser uma **zona na mesma conta da Cloudflare** em que o projeto roda. Se o domínio estiver em outro lugar, adicione-o à Cloudflare antes (e aponte os nameservers dele para a Cloudflare). Se a conta não tiver zonas, a página mostra *"Sua conta da Cloudflare ainda não tem domínios."* ## Adicionar um domínio 1. Em **Adicionar domínio**, escolha a zona em **Domínio na Cloudflare**. 2. Opcional: digite um **Subdomínio** (`www`, `loja`…). Deixe vazio para usar a própria zona. 3. Confira *O site vai abrir em …* e clique em **Adicionar**. O certificado pode levar alguns minutos. A página também mostra o **Worker** do site e o **Endereço workers.dev** dele, que continua funcionando. Curingas (`*.example.com`) não são aceitos. ## Remover um domínio Clique em **Remover** ao lado dele e confirme. O site deixa de abrir nesse domínio; o registro DNS sai junto. ## Projetos hospedados pela bohr Projetos migrados da bohr v1 mantêm os domínios que tinham na v1, servidos pela bohr (cada um mostra **No ar** ou **Pendente**). Para mudá-los, [mova o projeto para a sua conta da Cloudflare](https://docs.bohr.io/pt-br/migrating-from-v1/move-to-your-cloudflare/). --- # Excluir um projeto > Remova um projeto e tudo o que a bohr criou para ele, mantendo ou apagando o site publicado. Source: https://docs.bohr.io/pt-br/projects/delete/ A **Zona de perigo**, no fim de **Configurações › Geral**, exclui o projeto. Só o dono pode fazer isso, e não dá para desfazer. 1. Clique em **Excluir projeto**. 2. Leia o que sai e o que fica. 3. Opcional: marque **Também apagar o site publicado na minha conta Cloudflare**. 4. Digite o nome do projeto para confirmar e excluir. ## O que sai - O agente do projeto: os Workers dele (o Worker do projeto e o Worker da homologação) e o container. - A homologação, a hospedagem da bohr e as rotas da bohr, nos projetos hospedados pela bohr. - O projeto na bohr: os membros, o chat, as configurações e as variáveis. ## O que fica - **O repositório no GitHub não é alterado.** - **O site publicado na sua conta da Cloudflare continua no ar**, a menos que você tenha marcado a opção acima. Essa opção remove o Worker de produção do site e os secrets de Actions `CLOUDFLARE_API_TOKEN` e `CLOUDFLARE_ACCOUNT_ID` que versões antigas da bohr podem ter deixado no repositório, para que ele não seja publicado de novo. - **O bot do projeto no Telegram continua existindo.** Apague-o no @BotFather se quiser. O `.github/workflows/bohr-deploy.yml` do repositório também fica. Depois que o projeto é excluído, a bohr não entrega mais credenciais de deploy a ele, então as execuções falham; apague o arquivo se não precisar dele. Se algo não pôde ser removido, o painel avisa *"O projeto foi excluído, mas algo ficou para trás"* com a lista, para você limpar à mão. --- # Como os deploys funcionam > Como um projeto da bohr faz o build e publica na Cloudflare, e os arquivos que descrevem isso. Source: https://docs.bohr.io/pt-br/deploys/how-deploys-work/ O site de produção de um projeto da bohr é um **Cloudflare Worker com static assets**. O build e a publicação são feitos pelo **GitHub Actions**, a partir do branch de produção, depois de cada mudança aprovada. ``` .bohr/deploy.json ──(a bohr escreve)──▶ .github/workflows/bohr-deploy.yml │ no push para o branch de produção ▼ checkout → setup Node.js → bohr credentials (OIDC) → install → build │ ▼ D1 migrations (se houver) → wrangler deploy → sua conta da Cloudflare ``` ## Os arquivos | Arquivo | Quem escreve | O que diz | | --- | --- | --- | | [`.bohr/deploy.json`](https://docs.bohr.io/pt-br/deploys/deploy-json/) | O agente (você pode editar) | Como fazer o build de produção: pasta, versão do Node.js, gerenciador de pacotes, comandos de install, build e deploy | | [`.github/workflows/bohr-deploy.yml`](https://docs.bohr.io/pt-br/deploys/deploy-workflow/) | A bohr, a partir de `.bohr/deploy.json` | O workflow do GitHub Actions que roda nos pushes para o branch de produção | | [`wrangler.jsonc`](https://docs.bohr.io/pt-br/deploys/wrangler-config/) | O agente ou você | O Worker: nome, ponto de entrada, static assets, bindings | | [`.bohr/preview.json`](https://docs.bohr.io/pt-br/deploys/preview-json/) | O agente (você pode editar) | Como a homologação roda o servidor de desenvolvimento no sandbox | ## O que dispara um deploy - **Aprovar uma homologação**: a bohr faz o merge de `homolog` no branch de produção; o push roda o workflow. - **Reverter**: o revert é mesclado; mesma coisa. - **Qualquer push para o branch de produção**, feito por você ou por outra ferramenta. - **`bohr deploy --prod`** pela [CLI](https://docs.bohr.io/pt-br/cli/deploy/#projetos-na-sua-própria-conta-da-cloudflare), feito por um dono do projeto. No GitHub Actions, só o branch de produção faz deploy. A homologação do agente não é um deploy: é o servidor de desenvolvimento no sandbox do agente. Os donos também podem enviar versões de homologação de qualquer branch com o `bohr deploy`; elas nunca mudam a produção. ## Credenciais Nenhum token da Cloudflare fica guardado no seu repositório. Quando o workflow roda, o primeiro passo da bohr pede à instância da bohr as suas credenciais da Cloudflare e as [variáveis do build](https://docs.bohr.io/pt-br/projects/variables/#variáveis-do-build) do projeto, provando quem é com um **token OIDC do GitHub**. A bohr só responde a execuções do `bohr-deploy.yml` num push (ou execução manual) para o branch de produção de um projeto na conta do dono dele. Veja [Modelo de segurança](https://docs.bohr.io/pt-br/reference/security/#credenciais-de-deploy). ## O site nunca sai do ar O `wrangler deploy` envia a nova versão e passa a servi-la num único passo. Se o build ou o deploy falhar, a produção continua servindo a versão anterior, e o chat mostra o link da execução que falhou. ## Projetos hospedados pela bohr Projetos migrados da bohr v1 fazem deploy de outro jeito: o workflow da v1 continua funcionando e publica na hospedagem da bohr, e cada branch enviado ganha um endereço próprio. Eles também podem ser publicados com a [CLI](https://docs.bohr.io/pt-br/cli/deploy/). Veja [Migrar da bohr v1](https://docs.bohr.io/pt-br/migrating-from-v1/what-changes/). --- # O workflow de deploy > O workflow do GitHub Actions que a bohr escreve a partir do .bohr/deploy.json, passo a passo. Source: https://docs.bohr.io/pt-br/deploys/deploy-workflow/ A bohr escreve o `.github/workflows/bohr-deploy.yml` a partir do [`.bohr/deploy.json`](https://docs.bohr.io/pt-br/deploys/deploy-json/), com um modelo fixo. **Mude o `.bohr/deploy.json`, não o workflow**: a bohr reescreve o workflow sempre que o trabalho do agente muda as configurações de deploy, e a primeira linha dele avisa isso: ```yaml # Written by bohr from .bohr/deploy.json. Change that file instead: bohr rewrites this one. ``` A bohr só substitui um `bohr-deploy.yml` que começa com essa linha. Um workflow que a sua equipe escreveu com esse nome continua fazendo deploy como está. ## Como ele é Para `{"install": "npm ci", "build": "npm run build"}` no branch de produção `main` (scripts longos encurtados): ```yaml name: bohr deploy on: push: branches: ["main"] concurrency: group: bohr-deploy cancel-in-progress: false permissions: contents: read id-token: write jobs: deploy: runs-on: ubuntu-latest timeout-minutes: 30 defaults: run: working-directory: "." steps: - uses: actions/checkout@v5 with: persist-credentials: false - uses: actions/setup-node@v5 with: node-version: "24" - name: Build variables # carrega as variáveis do build que versões antigas da bohr guardavam como secrets de Actions BOHR_BUILD_ - name: bohr credentials id: bohr-credentials uses: bohr-io/deploy-action@v1 with: credentials: "true" - name: Install run: "npm ci" - name: Build run: "npm run build" - name: D1 migrations # só quando a config do wrangler tem bancos D1 com migrations_dir - name: Deploy # envolve o site na barreira de senha e depois roda: # npx wrangler deploy --message "bohr" --tag "bohr-${GITHUB_SHA::12}" env: CLOUDFLARE_API_TOKEN: ${{ steps.bohr-credentials.outputs.cloudflare-api-token }} CLOUDFLARE_ACCOUNT_ID: ${{ steps.bohr-credentials.outputs.cloudflare-account-id }} ``` ## Os passos | Passo | O que faz | | --- | --- | | Gatilho | Só pushes para o branch de produção. Pushes ali só vêm de merges aprovados, reversões ou pessoas com acesso de escrita. | | `concurrency` | Um deploy por vez; um novo push espera o que está rodando em vez de cancelá-lo. | | `permissions` | `contents: read` e `id-token: write` (para pedir o token OIDC do GitHub). Nada mais. | | Preparação | `oven-sh/setup-bun@v2` quando o gerenciador de pacotes é `bun`; `actions/setup-node@v5` com a versão de `node`; `actions/setup-python@v6` quando `python` está definido; `corepack enable` para `pnpm` e `yarn`. | | **bohr credentials** | [`bohr-io/deploy-action@v1`](https://docs.bohr.io/pt-br/github-action/reference/#modo-credenciais) com `credentials: "true"`: pede à bohr as [variáveis do build](https://docs.bohr.io/pt-br/projects/variables/#variáveis-do-build) do projeto (exportadas, mascaradas, para os passos seguintes) e o token e a conta da Cloudflare (saídas do passo, só para o passo de deploy). Instâncias self-hosted adicionam a própria `instance-url`. | | **Install**, **Build** | Os seus comandos, em `directory`. Os secrets do repositório listados em `secrets` são passados só para esses dois passos. | | **D1 migrations** | `npx wrangler d1 migrations apply --remote` para cada banco D1 com `migrations_dir`. Veja [Bancos de dados D1](https://docs.bohr.io/pt-br/deploys/d1-databases/). | | **Deploy** | Com o comando padrão, envolve o site na [barreira de senha](https://docs.bohr.io/pt-br/projects/password-protection/) e roda `npx wrangler deploy`. Um comando `deploy` próprio roda como está. O token da Cloudflare chega só a este passo (e às migrations). | ## Por que é seguro - Os comandos são linhas únicas sem expressões do GitHub (`${{ }}`), então não conseguem ler outros secrets nem contextos. - O token da Cloudflare nunca fica no repositório: a bohr entrega o token só para execuções deste workflow, num push ou numa execução manual (`workflow_dispatch`) no branch de produção. Um pull request, outro branch ou outro workflow não recebe nada. - O agente não pode editar workflows; a bohr escreve este ela mesma. ## Rodar de novo Rode de novo uma execução que falhou no GitHub (**Re-run jobs**); a página [Builds](https://docs.bohr.io/pt-br/projects/builds/) tem o link de cada execução. Rodar de novo um push para o branch de produção recebe as credenciais outra vez. ## Mudar à mão Edite o `.bohr/deploy.json` e deixe a próxima mudança do agente gerar o workflow de novo, ou peça direto ao agente: *"Mude o comando de build no .bohr/deploy.json para …"*. Se você precisar de um workflow que a bohr não consegue gerar, escreva o seu próprio `.github/workflows/bohr-deploy.yml` sem a primeira linha da bohr: a bohr não mexe nele. Ele ainda pode pegar as credenciais da Cloudflare com o [passo de credenciais](https://docs.bohr.io/pt-br/github-action/reference/#modo-credenciais), já que a bohr confere o caminho e o branch do workflow, não o conteúdo. --- # .bohr/deploy.json > Referência do arquivo que descreve como a bohr faz o build e o deploy de produção. Source: https://docs.bohr.io/pt-br/deploys/deploy-json/ O `.bohr/deploy.json` diz à bohr como fazer o build e o deploy do seu site de produção. O agente escreve o arquivo quando prepara o repositório e o mantém funcionando; você também pode editá-lo. A bohr gera [o workflow de deploy](https://docs.bohr.io/pt-br/deploys/deploy-workflow/) a partir dele, e a [CLI](https://docs.bohr.io/pt-br/cli/deploy/) roda o `install` e o `build` dele antes do deploy. ```json { "directory": ".", "node": "24", "packageManager": "npm", "install": "npm ci", "build": "npm run build" } ``` ## Campos | Campo | Padrão | Descrição | | --- | --- | --- | | `directory` | `"."` | Pasta com o `package.json` e a config do wrangler do projeto, relativa à raiz do repositório. `"."` ou um caminho relativo como `"apps/web"`: sem `..`, sem pastas que começam com ponto. | | `node` | `"24"` | Versão major do Node.js para o build, com dois dígitos (`"22"`, `"24"`). | | `packageManager` | `"npm"` | `npm`, `pnpm`, `yarn` ou `bun`. `pnpm` e `yarn` vêm do Corepack; `bun` é configurado com `oven-sh/setup-bun`. | | `python` | — | Versão do Python quando o build precisa dele (Python Workers), como `"3.12"`. | | `install` | — | Instala as dependências, por exemplo `"npm ci"`. Omita para pular. | | `build` | — | Faz o build de produção, por exemplo `"npm run build"`. Omita para pular. | | `deploy` | `"npx wrangler deploy"` | Publica o build na sua conta da Cloudflare. Mantenha o padrão, a menos que o framework precise de um comando próprio (por exemplo `"npx opennextjs-cloudflare deploy"`): a [proteção por senha](https://docs.bohr.io/pt-br/projects/password-protection/) só vale com o padrão. | | `secrets` | `[]` | Nomes de **secrets do repositório no GitHub** de que os passos de install e build precisam, por exemplo `["SENTRY_AUTH_TOKEN"]`. Até 50. | ### Regras para os comandos `install`, `build` e `deploy` são linhas únicas de shell com até 500 caracteres, sem quebras de linha e sem expressões do GitHub (`${{ … }}`). Encadeie comandos com `&&`. ### Regras para os secrets Os nomes usam `A-Z`, `0-9` e `_`. Nomes que começam com `GITHUB_` (reservado pelo GitHub) ou `CLOUDFLARE_` (as credenciais da Cloudflare só vão para o passo de deploy, que a bohr escreve) são recusados. Raramente você precisa de `secrets`: prefira as [variáveis do build](https://docs.bohr.io/pt-br/projects/variables/#variáveis-do-build), que você define no painel da bohr e que chegam ao install e ao build sem mexer nas configurações do repositório. Use `secrets` para valores que você já guarda como secrets do GitHub Actions. ## Quando ele é inválido Se o arquivo tiver um problema, o workflow de deploy não é atualizado e o chat avisa: *"O arquivo .bohr/deploy.json tem um problema (…), então o deploy de produção não foi atualizado. Peça para eu corrigi-lo."* A CLI para com `.bohr/deploy.json is invalid: …` (código de saída 2). ## Exemplos Um site estático feito com Vite: ```json { "install": "npm ci", "build": "npm run build" } ``` Um app num monorepo pnpm: ```json { "directory": "apps/web", "packageManager": "pnpm", "install": "pnpm install --frozen-lockfile", "build": "pnpm build" } ``` Next.js com OpenNext: ```json { "node": "22", "install": "npm ci", "build": "npx opennextjs-cloudflare build", "deploy": "npx opennextjs-cloudflare deploy" } ``` --- # .bohr/preview.json > Referência do arquivo que diz à bohr como rodar o servidor de desenvolvimento da homologação no sandbox do agente. Source: https://docs.bohr.io/pt-br/deploys/preview-json/ A [homologação](https://docs.bohr.io/pt-br/agent/previews/) é o **servidor de desenvolvimento** do seu projeto, rodando no sandbox do agente a partir do branch `homolog`. O `.bohr/preview.json` diz como iniciá-lo. O agente escreve o arquivo quando prepara o repositório e o mantém funcionando. ```json { "install": "npm ci", "command": "npm run dev -- --host 0.0.0.0 --port 8080", "port": 8080, "env": {} } ``` ## Campos | Campo | Obrigatório | Descrição | | --- | --- | --- | | `command` | Sim | O comando do servidor de desenvolvimento, que fica rodando (até 1000 caracteres). Roda com `bash -lc` na raiz do repositório. | | `port` | Sim | A porta em que o servidor de desenvolvimento escuta, de 1024 a 65535. A porta `4840` é reservada para o agente da bohr. | | `install` | Não | Instala as dependências. Roda no primeiro início e sempre que um manifesto de dependências ou lockfile muda. | | `env` | Não | Variáveis de ambiente extras para `install` e `command`. Nunca secrets: este arquivo vai para o commit. | Os comandos também recebem `PORT` (a porta), `HOST=0.0.0.0`, `BROWSER=none` e `CI=1`. ## Requisitos do servidor de desenvolvimento - Escutar em `0.0.0.0` (todas as interfaces) na `port`. Servidores de desenvolvimento que só escutam em `localhost` também funcionam. - Aceitar qualquer cabeçalho `Host`. O Vite, por exemplo, precisa de `server.allowedHosts: true`. - Ficar pronto em até **3 minutos**. Senão, a homologação é marcada como falha, com o fim da saída. - O `install` precisa terminar em até 15 minutos. ## Quando ela reinicia - Depois de cada pedido e de cada sincronização, a homologação reinicia se o `.bohr/preview.json` ou as dependências mudaram (`package.json`, lockfiles, `requirements*.txt`, `pyproject.toml`, `go.mod`, `Cargo.toml` e afins, em qualquer lugar do repositório), ou se ela não estiver rodando. Caso contrário, o próprio reload do servidor de desenvolvimento pega a mudança. - Parar mata o grupo de processos inteiro: tudo o que o comando iniciou para junto. ## Estados A homologação passa por estes estados: | Estado | Significado | | --- | --- | | `starting` | Instalando ou esperando a porta | | `running` | A porta aceita conexões | | `failed` | O comando terminou, ou a porta não abriu a tempo; o log mostra o fim da saída | | `stopped` | Ainda não há checkout, não há `.bohr/preview.json` ou ele é inválido | Mensagens que você pode ver: *"A homologação ainda não está configurada: o agente prepara isso ao importar o repositório."* (ainda sem arquivo) e *"A homologação não conseguiu iniciar. Peça ao agente para verificar o arquivo .bohr/preview.json."* ## Exemplos Um Worker com banco de dados D1 (os modelos): ```json { "install": "npm ci", "command": "npx wrangler d1 migrations apply DB --local && npx wrangler dev --ip 0.0.0.0 --port 8080", "port": 8080 } ``` Astro: ```json { "install": "npm ci", "command": "npx astro dev --host 0.0.0.0 --port 4321", "port": 4321 } ``` --- # Config do wrangler e bindings > A config do wrangler que a bohr publica, os bindings que cada tipo de projeto aceita e o que é ignorado. Source: https://docs.bohr.io/pt-br/deploys/wrangler-config/ O seu site é descrito por uma **config do wrangler** padrão da Cloudflare, `wrangler.jsonc` (ou `wrangler.json`), na pasta para a qual o `.bohr/deploy.json` aponta. O agente adiciona uma se o repositório não tiver. ```jsonc { "name": "my-site", "main": "src/index.ts", "compatibility_date": "2026-10-01", "compatibility_flags": ["nodejs_compat"], "assets": { "directory": "./dist", "binding": "ASSETS", "not_found_handling": "single-page-application", "run_worker_first": ["/api/*"] } } ``` `name` é o nome do seu Worker de produção. A bohr usa esse nome para encontrar o site nas [variáveis](https://docs.bohr.io/pt-br/projects/variables/), na [proteção por senha](https://docs.bohr.io/pt-br/projects/password-protection/) e nos [domínios](https://docs.bohr.io/pt-br/projects/domains/). ## Projetos na sua própria conta da Cloudflare Eles fazem deploy com `wrangler deploy` na sua conta, então **todo binding que o wrangler aceita funciona**: D1, KV, R2, Durable Objects, Queues, Workflows, Containers, Hyperdrive, AI, cron triggers, routes… Os recursos a que um binding se refere precisam existir na sua conta (o agente pode criá-los, ou você cria no dashboard). O que é bom saber: - As `vars` da config vão para o commit no repositório; secrets ficam em **Variáveis do site** marcadas como **Secreta**. - Com a [proteção por senha](https://docs.bohr.io/pt-br/projects/password-protection/) ligada, o deploy envolve o seu Worker numa barreira e define `assets.run_worker_first` como `true`, para que os arquivos estáticos também passem por ela. - As migrations do D1 rodam antes de cada deploy: veja [Bancos de dados D1](https://docs.bohr.io/pt-br/deploys/d1-databases/). ## Projetos hospedados pela bohr Projetos migrados da bohr v1 (até serem [movidos](https://docs.bohr.io/pt-br/migrating-from-v1/move-to-your-cloudflare/)) fazem deploy na hospedagem da bohr, que aceita um subconjunto: | Chave | Aceita | | --- | --- | | `main` | Sim. Empacotado com `wrangler deploy --dry-run`. Deixe de fora num site estático. | | `compatibility_date` | Obrigatória | | `compatibility_flags` | Sim | | `vars` | Só valores de texto | | `assets.directory`, `binding`, `not_found_handling`, `html_handling`, `run_worker_first` | Sim, como no wrangler | | Secrets | Sim, como [variáveis do site](https://docs.bohr.io/pt-br/projects/variables/) | | Qualquer outro binding (`kv_namespaces`, `d1_databases`, `r2_buckets`, `durable_objects`, `queues`, `services`, `hyperdrive`, `ai`…) | Não: o deploy para com *"bohr.io Cloud managed projects support static assets, vars and secrets for now; … is not supported."* | | `routes`, `triggers.crons`, seções `env`, `assets.base_path` | Ignorados, com um aviso | Também nesses projetos: - O `wrangler.toml` não é lido: converta para `wrangler.jsonc` (mesmas chaves, em JSON com comentários). - Uma config do Cloudflare Pages (`pages_build_output_dir`) é recusada: use `"assets": { "directory": "…" }`. - Quando o build deixa um `.wrangler/deploy/config.json` apontando para uma config gerada (como faz o plugin Vite da Cloudflare), essa config é usada. ## Static assets Em qualquer projeto, os arquivos em `assets.directory` seguem as regras do wrangler: - Um `.assetsignore` na raiz da pasta exclui arquivos (sintaxe do gitignore). - `_redirects` e `_headers` na raiz são aplicados como regras de roteamento, não servidos como arquivos (até 256 KiB cada quando hospedado pela bohr). - Cada arquivo pode ter no máximo **25 MiB** (limite da Cloudflare). - A CLI e a action da bohr nunca publicam arquivos ou pastas `.git`, `.env` ou `.env.`, diga o que disser o `.assetsignore`. --- # Bancos de dados D1 e migrations > Use o Cloudflare D1 num projeto da bohr, e como as migrations rodam em cada deploy. Source: https://docs.bohr.io/pt-br/deploys/d1-databases/ Projetos na sua própria conta da Cloudflare podem usar o **D1**, o banco de dados SQL da Cloudflare. Projetos criados a partir de um [modelo](https://docs.bohr.io/pt-br/getting-started/templates/) já vêm com um. ## O binding ```jsonc { "d1_databases": [ { "binding": "DB", "database_name": "my-site", "database_id": "", "migrations_dir": "migrations" } ] } ``` No Worker, o banco de dados é `env.DB`. ## Migrations Coloque as mudanças de schema em arquivos SQL numerados dentro de `migrations_dir`, um por mudança: ``` migrations/ 0001_init.sql 0002_add_city.sql ``` Em todo deploy de produção, **antes** do `wrangler deploy`, o [workflow de deploy](https://docs.bohr.io/pt-br/deploys/deploy-workflow/) roda, para cada banco D1 que declara um `migrations_dir` existente no repositório: ```sh npx wrangler d1 migrations apply --remote ``` O D1 registra quais migrations já aplicou, então cada uma roda uma única vez. O workflow só ganha esse passo quando a config tem bancos assim. Peça mudanças de schema ao agente com palavras simples (*"Salve a cidade do visitante em cada cadastro"*): ele adiciona um novo arquivo de migration em vez de mudar os antigos. ## A homologação A homologação roda `wrangler dev`, com uma cópia **local** do banco de dados no sandbox. As homologações dos modelos aplicam as migrations localmente antes: ```sh npx wrangler d1 migrations apply DB --local && npx wrangler dev --ip 0.0.0.0 --port 8080 ``` Os dados da homologação são separados dos de produção e se perdem quando o sandbox dorme. As homologações publicadas com o [`bohr deploy`](https://docs.bohr.io/pt-br/cli/deploy/#homologações) são diferentes: são versões do Worker de produção, com os mesmos bindings, então **usam os bancos de produção**, e nenhuma migration é aplicada para elas. O `bohr deploy --prod` aplica as migrations como o workflow, antes do deploy. ## Permissões Criar um banco de dados exige a permissão **D1: Edit** no seu token da Cloudflare (a bohr pede essa permissão quando você cria um projeto a partir de um modelo). Aplicar as migrations no deploy usa o mesmo token. :::caution [Reverter](https://docs.bohr.io/pt-br/agent/versions-and-rollback/) desfaz o código, não os dados: as migrations que já rodaram continuam aplicadas. Para desfazer uma mudança de schema, peça ao agente uma nova migration que a reverta. ::: --- # Monorepos e pastas de trabalho > Faça o deploy de um projeto que fica numa subpasta do repositório. Source: https://docs.bohr.io/pt-br/deploys/monorepos/ Um projeto não precisa ficar na raiz do repositório. Aponte o `directory` do [`.bohr/deploy.json`](https://docs.bohr.io/pt-br/deploys/deploy-json/) para a pasta com o `package.json` e a config do wrangler do site: ```json { "directory": "apps/web", "packageManager": "pnpm", "install": "pnpm install --frozen-lockfile", "build": "pnpm build" } ``` - O workflow de deploy roda todos os passos (`install`, `build`, migrations e `deploy`) nessa pasta (`defaults.run.working-directory`). - As ferramentas de workspace encontram a raiz do repositório a partir dali: `pnpm install` em `apps/web` instala o workspace inteiro. - A bohr encontra o nome do Worker de produção no `wrangler.jsonc` dessa pasta. - A [CLI](https://docs.bohr.io/pt-br/cli/deploy/) lê o `.bohr/deploy.json` na raiz do repositório e faz o deploy a partir de `directory`, ou de `--dir`. O `.bohr/deploy.json` e o `.bohr/preview.json` em si ficam sempre na raiz do repositório. ## A homologação Os comandos do `.bohr/preview.json` rodam a partir da raiz do repositório. Mude de pasta no comando quando precisar: ```json { "install": "pnpm install", "command": "pnpm --filter web dev --host 0.0.0.0 --port 5173", "port": 5173 } ``` ## Um repositório, um projeto Cada repositório pode ser um projeto da bohr. Para publicar dois sites a partir de um repositório, divida-os em dois repositórios, ou publique o segundo você mesmo, com um workflow próprio. --- # Instalar a CLI > Instale a CLI do bohr (pacote npm bohr) ou rode com npx. Source: https://docs.bohr.io/pt-br/cli/install/ A **CLI do bohr** faz deploy de projetos da bohr pelo seu terminal, por scripts, por CI e por agentes de IA de programação. É o mesmo código que roda dentro da GitHub Action [`bohr-io/deploy-action`](https://docs.bohr.io/pt-br/github-action/reference/). Ela precisa do **Node.js 20 ou mais recente**. ## Rodar com npx Sem instalar nada; sempre a versão mais recente: ```sh npx bohr@latest --version npx bohr@latest deploy ``` ## Instalar globalmente ```sh npm install --global bohr bohr --version ``` Atualize com `npm install --global bohr@latest`. ## Como dependência do projeto ```sh npm install --save-dev bohr npx bohr deploy ``` ## Primeiros passos ```sh bohr login # uma vez por computador: aprove no navegador bohr projects # os projetos dos quais você pode fazer deploy bohr deploy # faz o build e o deploy de uma homologação do branch atual ``` ## Ajuda ```sh bohr --help # todos os comandos, opções globais, códigos de saída bohr deploy --help # as opções de um comando bohr help deploy # o mesmo ``` :::caution[bohr v1] Esta é a CLI da bohr v2 (versão 4.x no npm: as versões 2.x e 3.x de lá são de um pacote de 2016 sem relação). Num repositório que ainda está na bohr v1, ela repassa o comando, sem mudanças, para a CLI da bohr v1 (`bohr@1.0.577`), então os workflows da v1 que rodam `npx bohr@latest deploy` continuam fazendo deploy como antes; o mesmo vale para comandos da bohr v1 como `bohr dev`. Veja [Migrar da bohr v1](https://docs.bohr.io/pt-br/migrating-from-v1/overview/). ::: :::note[Projetos na sua própria conta da Cloudflare] O `bohr deploy` publica projetos que **a bohr hospeda** (projetos migrados da bohr v1) e, desde a CLI 4.1.0, projetos na sua própria conta da Cloudflare, dos quais só os donos podem fazer deploy pela CLI: o wrangler faz o deploy com a conexão da Cloudflare do dono. Veja [Projetos na sua própria conta da Cloudflare](https://docs.bohr.io/pt-br/cli/deploy/#projetos-na-sua-própria-conta-da-cloudflare). Os outros comandos funcionam com todos os projetos. ::: --- # Autenticação > Entre na CLI com bohr login, use um token do painel com BOHR_TOKEN, ou o OIDC do GitHub no Actions. Source: https://docs.bohr.io/pt-br/cli/authentication/ A CLI se autentica de uma de três formas, nesta ordem: 1. **`BOHR_TOKEN`**, quando definida: um token do painel. Para scripts, CI e agentes de IA. 2. **O login guardado pelo `bohr login`**, para aquela instância. Para pessoas no próprio computador. 3. **OIDC do GitHub**, no GitHub Actions sem `BOHR_TOKEN` (precisa de `permissions: id-token: write`). ## bohr login ```sh bohr login ``` A CLI mostra um link e um código, e abre o navegador: ``` To sign in, open https://app.bohr.io/cli?code=BCDF-GHJK and approve "CLI on my-laptop" with the code BCDF-GHJK. ``` No painel (**Entrar na CLI do bohr**), confira se o código é o mesmo do seu terminal e clique em **Aprovar**. Aprove só uma entrada que você mesmo começou: senão, quem mandou um link desses poderia fazer deploy como você. O código vale por 10 minutos. Depois disso a CLI guarda um token próprio, chamado **"CLI on <seu computador>"**, com acesso a todos os seus projetos e sem expiração. Ele fica em `credentials.json` na sua pasta de configuração, que só você consegue ler: | Sistema | Pasta | | --- | --- | | Linux | `$XDG_CONFIG_HOME/bohr` ou `~/.config/bohr` | | macOS | `~/Library/Application Support/bohr` | | Windows | `%APPDATA%\bohr` | `BOHR_CONFIG_DIR` substitui a pasta. Fica guardado um login por instância. ```sh bohr whoami # em nome de quem a CLI age, e com qual token bohr logout # revoga o token deste computador e o esquece ``` ## Tokens para scripts e agentes Crie um token no painel, em **Conta › Tokens** ([detalhes](https://docs.bohr.io/pt-br/account/tokens/)): um nome, os projetos que ele pode usar e uma expiração. O painel mostra o token uma única vez. Depois: ```sh export BOHR_TOKEN=bohr_… bohr deploy --json ``` - Tokens começam com `bohr_`. Qualquer outra coisa em `BOHR_TOKEN` é recusada (código de saída 3). - Um token age como você, nos projetos dos quais você é membro, limitado aos que ele lista. Ele nunca carrega o papel de administrador da instância. - `BOHR_TOKEN` tem prioridade sobre o login guardado. O `bohr login` avisa quando ela está definida. - Revogue o token no painel quando quiser; os scripts que o usam param na hora (código de saída 3). ## GitHub Actions com OIDC Num workflow com `permissions: id-token: write` e sem `BOHR_TOKEN`, o `bohr deploy` entra com o token OIDC do GitHub da execução e faz deploy **do repositório da execução e do branch que recebeu o push**, como a deploy action. `--prod`, `--branch` e `--project` precisam de `BOHR_TOKEN`. Veja [Uso em CI](https://docs.bohr.io/pt-br/cli/ci/). ## Instâncias auto-hospedadas Todo comando aceita `--instance `, ou a variável `BOHR_INSTANCE_URL`. O padrão é `https://app.bohr.io`. O endereço precisa usar `https` (exceto `localhost`). ```sh bohr login --instance https://bohr.example.com ``` --- # bohr deploy > Faça o build e o deploy de uma pasta como homologação de um branch, ou como produção com --prod. Source: https://docs.bohr.io/pt-br/cli/deploy/ ```sh bohr deploy [--prod] [--branch ] [--project ] [--dir ] [--no-build] [--yes] [--json] [--instance ] ``` Faz o build do projeto e o publica. **Homologações por padrão**; produção só com `--prod`. ## Opções | Opção | Descrição | | --- | --- | | `--prod` | Faz deploy de produção (só donos do projeto). | | `--branch ` | O branch da homologação. Padrão: o branch em checkout. | | `--project ` | O id do projeto (veja `bohr projects`). Padrão: o vínculo da pasta, ou o remote do GitHub. | | `--dir ` | Pasta com a configuração do wrangler. Padrão: `directory` do `.bohr/deploy.json`, ou a pasta atual. | | `--no-build` | Faz deploy do que já foi construído: pula o install e o build do `.bohr/deploy.json`. | | `-y`, `--yes` | Não pergunta antes de fazer deploy de produção. | | `--json` | Imprime um objeto JSON com o resultado ([schema](https://docs.bohr.io/pt-br/cli/json-output/#bohr-deploy)). | | `--instance ` | A instância da bohr. Padrão: `BOHR_INSTANCE_URL`, o vínculo da pasta, ou `https://app.bohr.io`. | | `-h`, `--help` | Mostra a ajuda do comando. | ## O que ele faz 1. **Qual projeto**: `--project `, senão o vínculo da pasta (`.bohr/project.json`, escrito pelo [`bohr link`](https://docs.bohr.io/pt-br/cli/commands/#bohr-link)), senão o projeto do remote do GitHub do repositório (`origin`). 2. **Qual branch**: `--branch`, senão o branch em checkout. No **branch de produção** sem `--prod`, ele publica uma homologação em `-preview` e avisa. 3. **Build**: roda `install` e `build` do [`.bohr/deploy.json`](https://docs.bohr.io/pt-br/deploys/deploy-json/) na pasta dele, a não ser com `--no-build`. O seu ambiente é o do build: as variáveis de build guardadas na bohr não são baixadas. Ele avisa quando a versão major do seu Node.js é diferente de `node`, ou quando um nome em `secrets` não está definido. 4. **Bundle**: o Worker é empacotado com `wrangler deploy --dry-run` (não precisa de credenciais da Cloudflare). Adicione `wrangler` às suas `devDependencies` para fixar a versão. 5. **Upload**: os arquivos estáticos recebem hash como o wrangler faz; só arquivos novos ou alterados são enviados. 6. **Publicação**: a URL é impressa no stdout. O progresso vai para o stderr. Os passos 3 a 6 são os de um projeto que **a bohr hospeda**. Um projeto na conta Cloudflare do dono faz o build com as variáveis do build dele e o deploy com o wrangler: veja [Projetos na sua própria conta da Cloudflare](#projetos-na-sua-própria-conta-da-cloudflare). ```console $ bohr deploy Deploying a preview of feature/new-menu of my-site (p3k9x0a7qd2m) on https://app.bohr.io. … 42 files (1.3 MiB), 3 uploaded; 1 Worker module. https://feature-new-menu-my-site-acme.bohr.io ``` ## Produção ```sh bohr deploy --prod ``` - Só os **donos** do projeto (admins da organização dele) podem fazer deploy de produção. Os outros recebem o código de saída 5 (`production_not_allowed`). - Num terminal, a CLI pergunta `Deploy this folder to production (…)? [y/N]` (`… in the owner's Cloudflare account? [y/N]` para um projeto na conta do dono). `--yes` pula a pergunta; sem terminal, ou com `--json`, ela nunca pergunta: o próprio `--prod` é a confirmação. - `--prod` com um `--branch` diferente do branch de produção é um erro de uso. - Um projeto cujo endereço de produção a bohr v1 ainda serve fica a cargo do workflow do repositório, cujo primeiro deploy de produção move o endereço (`production_on_v1`, código de saída 5). Até lá, faça deploy de homologações. ## Nada sai do ar O que é servido só muda depois que todos os arquivos foram enviados e a Cloudflare aceitou a nova versão. Qualquer falha antes disso deixa a versão anterior no ar. O passo final nunca é repetido, então um deploy não tem como publicar duas vezes. Para projetos na sua própria conta da Cloudflare, veja [abaixo](#nunca-tira-um-site-do-ar). ## O que nunca é publicado Arquivos ou pastas `.git` e `.env` (`.env`, `.env.production`…), em qualquer profundidade, não importa o que diga o `.assetsignore`. Cada `.env` ignorado é informado com um aviso. ## Quais projetos O `bohr deploy` publica os dois tipos de projeto da bohr v2: - **Projetos que a bohr hospeda** (migrados da bohr v1) sobem pelo caminho de upload da bohr, como descrito acima. - **Projetos na conta Cloudflare do dono** recebem o deploy do wrangler nessa conta, [como descrito abaixo](#projetos-na-sua-própria-conta-da-cloudflare). Só os donos podem fazer deploy deles pela CLI. A CLI 4.0.0 e anteriores recusavam o segundo tipo com o código de saída 5 (`own_account`). Se você vir esse código, atualize a CLI: `npx bohr@latest`. Uma pasta que não é um projeto da bohr v2 (sem configuração do wrangler, sem `.bohr/project.json`, sem `.bohr/deploy.json`) para com *"This repository is not a bohr v2 project"* (código de saída 4); repositórios que ainda estão na bohr v1 são reconhecidos, e o comando vai sem mudanças para a CLI da bohr v1. ## Projetos na sua própria conta da Cloudflare Um projeto na conta Cloudflare do dono (`own account` no [`bohr projects`](https://docs.bohr.io/pt-br/cli/commands/#bohr-projects), `mode: "byo"` no JSON dele) recebe o deploy do wrangler, nessa conta, de um jeito parecido com o do [workflow de deploy](https://docs.bohr.io/pt-br/deploys/deploy-workflow/) dele. Isso exige a CLI 4.1.0 ou mais nova, o Node.js 20 ou mais novo e o `npx`. ### Quem pode fazer deploy Só os **donos** do projeto (num projeto de organização: os admins da organização) podem fazer deploy dele pela CLI, **homologações incluídas**: o wrangler faz o deploy com o token da API da Cloudflare que o dono conectou à bohr. Os membros recebem o código de saída 5 (`own_account_not_allowed`); eles fazem push num branch, e o workflow do projeto faz o deploy do branch de produção. O token (`BOHR_TOKEN` ou `bohr login`) também precisa alcançar o projeto: um token limitado a alguns projetos precisa listá-lo. ### O que roda 1. **Credenciais**: a CLI pede à instância o token da API da Cloudflare e o id da conta do dono, só para este deploy. 2. **Build**: a não ser com `--no-build`, os comandos `install` e `build` do [`.bohr/deploy.json`](https://docs.bohr.io/pt-br/deploys/deploy-json/) rodam com as [variáveis do build](https://docs.bohr.io/pt-br/projects/variables/#variáveis-do-build) guardadas na bohr no ambiente (para o branch do deploy: os valores do projeto todo, sobrescritos pelos do branch). O build nunca recebe o token da Cloudflare nem o `BOHR_TOKEN`. 3. **Proteção**: quando o `.bohr/deploy.json` usa o comando `deploy` padrão, o portão de proteção da bohr envolve o site como no workflow de deploy, então a [proteção por senha](https://docs.bohr.io/pt-br/projects/password-protection/) também cobre as homologações. 4. **wrangler**: o wrangler do próprio projeto quando ele tem um instalado, senão `npx wrangler@4.149.0`. Homologações precisam do wrangler 4.21.0 ou mais novo (que trouxe os aliases de preview): com um wrangler mais antigo no projeto, as homologações rodam o 4.149.0. ### Homologações ```sh bohr deploy ``` envia uma nova versão do Worker com `wrangler versions upload --preview-alias --message "bohr" --tag "bohr-"`. Enviar uma versão **nunca muda o que a produção serve**. - O alias vem do branch: letras minúsculas, dígitos e hífens, começando com uma letra, encurtado para que `-` caiba num rótulo DNS de 63 caracteres. - A URL impressa é a URL de preview do alias, senão a URL de preview da própria versão. - As homologações só têm endereço quando o Worker tem as URLs de preview ativadas (`"preview_urls": true` na configuração do wrangler dele). Sem elas, a CLI avisa e imprime a versão que enviou (`url` é `null` no [JSON](https://docs.bohr.io/pt-br/cli/json-output/#bohr-deploy)). :::caution[D1 nas homologações] Uma versão de homologação tem os mesmos bindings da produção: os [bancos D1](https://docs.bohr.io/pt-br/deploys/d1-databases/) dela **são os bancos da produção**, e as migrations do D1 não são aplicadas nas homologações. A homologação de uma mudança de schema roda contra o schema e os dados atuais da produção. Cuidado com homologações que gravam dados ou que dependem de uma migration. ::: ### Produção ```sh bohr deploy --prod ``` 1. Num terminal, ele pergunta `Deploy this folder to production (…) in the owner's Cloudflare account? [y/N]`; `--yes` pula a pergunta, e sem terminal ou com `--json` o próprio `--prod` é a confirmação. 2. **Migrations do D1**, como no workflow de deploy: `wrangler d1 migrations apply --remote` para cada banco D1 do `wrangler.jsonc` (ou `wrangler.json`) que declara um `migrations_dir` existente na pasta. 3. **Deploy**: `wrangler deploy --message "bohr" --tag "bohr-"`. Se o `.bohr/deploy.json` tem um comando `deploy` próprio, a produção roda esse comando no lugar, com as credenciais no ambiente dele, e o portão de proteção não é adicionado (como no workflow). A bohr lê o nome do Worker da configuração do wrangler no branch de produção. Se a configuração do wrangler da pasta der outro nome de Worker, o `--prod` para antes do deploy com o código de saída 5 (`worker_mismatch`); uma homologação só avisa. ### Nunca tira um site do ar - Uma homologação nunca toca a produção. - Se uma migration do D1 falhar, o Worker não recebe o deploy: a produção continua servindo a versão anterior. - Se o `wrangler deploy` falhar, a Cloudflare continua servindo a versão anterior. ### Commit e tag A tag é `bohr-` quando a árvore de trabalho não tem mudanças não commitadas em arquivos versionados. Senão, ela é `bohr-local`, e nenhum commit é registrado com o deploy. ### Credenciais e secrets - O token da Cloudflare vai só para o ambiente dos processos do wrangler (`CLOUDFLARE_API_TOKEN`, `CLOUDFLARE_ACCOUNT_ID`). Ele nunca é impresso, registrado em log, colocado numa linha de comando nem gravado em disco, e as mensagens de erro o mostram como `***`. No GitHub Actions ele também é mascarado com `::add-mask::`. - Toda vez que a instância entrega as credenciais, o log de auditoria dela registra o usuário, o token e o projeto. No máximo 30 por usuário e projeto em 10 minutos; acima disso a instância responde HTTP 429 (código de saída 1): espere alguns minutos. - A bohr só entrega a conexão da Cloudflare do próprio dono, nunca o token da conta da própria bohr, e nunca para projetos que a bohr hospeda (esses continuam fazendo deploy pelo caminho de upload da bohr). ### Histórico A CLI registra cada deploy na bohr: branch, produção ou homologação, nome do Worker, id da versão, URL e commit (`deploymentId` no JSON). Se o registro falhar, o deploy foi feito mesmo assim e a CLI só avisa. O painel ainda não mostra esses registros; os membros do projeto podem lê-los pela API da instância (`GET /api/projects//cli-deploys`). O painel da Cloudflare também lista as versões do Worker, com a mensagem `bohr` e a tag `bohr-…`. --- # Comandos > Todos os comandos da CLI do bohr, com opções e exemplos. Source: https://docs.bohr.io/pt-br/cli/commands/ ``` bohr [options] ``` | Comando | O que faz | | --- | --- | | [`deploy`](https://docs.bohr.io/pt-br/cli/deploy/) | Faz o build e o deploy desta pasta (uma homologação, ou produção com `--prod`) | | [`login`](#bohr-login) | Entra a partir deste computador (aprove no navegador) | | [`logout`](#bohr-logout) | Sai: revoga o token deste computador e o esquece | | [`whoami`](#bohr-whoami) | Mostra em nome de quem a CLI age, e com qual token | | [`projects`](#bohr-projects) | Lista os projetos que o token alcança | | [`link`](#bohr-link) | Vincula esta pasta a um projeto (`.bohr/project.json`) | | [`open`](#bohr-open) | Imprime a URL do projeto e a abre no navegador | ## Opções de todos os comandos | Opção | Descrição | | --- | --- | | `--instance ` | A instância da bohr (padrão: `$BOHR_INSTANCE_URL`, o vínculo da pasta, ou `https://app.bohr.io`) | | `--json` | Imprime um objeto JSON com o resultado, para scripts e agentes de IA ([schemas](https://docs.bohr.io/pt-br/cli/json-output/)) | | `-h`, `--help` | Mostra a ajuda | | `-v`, `--version` | Imprime a versão (`bohr --version`) | Opções desconhecidas e argumentos a mais são erros de uso (código de saída 2). ## bohr login ```sh bohr login [--instance ] ``` Inicia uma entrada, mostra o link e o código, abre o navegador (num terminal) e espera até você aprovar no painel. Guarda um token chamado "CLI on <computador>". Veja [Autenticação](https://docs.bohr.io/pt-br/cli/authentication/#bohr-login). Falha com o código de saída 3 quando a entrada é recusada (`login_denied`) ou quando o código expira depois de 10 minutos (`login_expired`). ## bohr logout ```sh bohr logout [--instance ] ``` Revoga o token guardado na instância e o apaga do `credentials.json`. Se não conseguir falar com a instância, ainda assim esquece o token e pede para você revogá-lo no painel. Avisa quando `BOHR_TOKEN` ainda está definida. ## bohr whoami ```sh bohr whoami [--instance ] [--json] ``` ```console $ bohr whoami Ada Lovelace on https://app.bohr.io Token "deploy agent" (BOHR_TOKEN): 2 selected projects, expires 2027-01-10T12:00:00.000Z ``` ## bohr projects ```sh bohr projects [--instance ] [--json] ``` Lista os projetos que o token alcança: ```console $ bohr projects ID NAME REPOSITORY HOSTED ROLE URL p3k9x0a7qd2m my-site acme/my-site bohr owner https://my-site-acme.bohr.io p8b2m4c6d1ef shop acme/shop own account member - ``` **HOSTED** é `bohr` para projetos que a bohr hospeda e `own account` para projetos na conta Cloudflare do dono. O `bohr deploy` publica os dois; os projetos na conta do dono, só para os donos ([detalhes](https://docs.bohr.io/pt-br/cli/deploy/#projetos-na-sua-própria-conta-da-cloudflare)). ## bohr link ```sh bohr link [--project ] [--instance ] [--json] ``` Escreve `.bohr/project.json` na raiz do repositório, para que `bohr deploy` e `bohr open` saibam o projeto sem um remote do GitHub. Sem `--project`, usa o projeto do remote `origin`. O arquivo também registra a instância, quando ela não é a padrão. ```json { "projectId": "p3k9x0a7qd2m" } ``` Faça commit dele se todo mundo que trabalha na pasta deve fazer deploy no mesmo projeto. ## bohr open ```sh bohr open [--branch ] [--print] [--project ] [--instance ] [--json] ``` Imprime a URL de produção (ou a homologação do `--branch`) e a abre no navegador. `--print` só imprime. Falha com o código de saída 4 (`no_address`) quando aquele branch nunca teve deploy. ```sh bohr open --branch feature/new-menu --print ``` ## Depuração Defina `BOHR_DEBUG=1` para imprimir o stack trace de um erro no stderr. --- # Saída JSON > A saída --json de cada comando, para scripts e agentes de IA. Source: https://docs.bohr.io/pt-br/cli/json-output/ Com `--json`, um comando imprime **exatamente um objeto JSON no stdout** e mais nada ali; progresso e logs vão para o stderr. Ele também nunca faz perguntas e nunca abre o navegador. ## Sucesso e falha Sucesso: ```json { "ok": true, "...": "the command's fields" } ``` Falha: ```json { "ok": false, "error": { "code": "production_not_allowed", "message": "Only owners of my-site (admins of its organization) can deploy production. Deploy a preview: bohr deploy", "exitCode": 5 } } ``` O processo sai com o mesmo `exitCode` ([códigos de saída](https://docs.bohr.io/pt-br/cli/exit-codes/)). Decida com base em `error.code`, não na mensagem. ## bohr deploy ```json { "ok": true, "instanceUrl": "https://app.bohr.io", "url": "https://feature-new-menu-my-site-acme.bohr.io", "deploymentId": "d_…", "project": { "id": "p3k9x0a7qd2m", "name": "my-site" }, "branch": "feature/new-menu", "production": false, "mode": "managed", "files": 42, "bytes": 1363148, "uploadedFiles": 3, "uploadedBytes": 20480, "modules": 1 } ``` | Campo | Descrição | | --- | --- | | `url` | Onde o branch publicado é servido | | `deploymentId` | O id do deployment na instância | | `project` | O projeto, ou `null` no GitHub Actions com OIDC | | `branch`, `production` | O que foi publicado (`null` com OIDC) | | `mode` | `managed`: um projeto que a bohr hospeda. `byo`: um projeto na conta Cloudflare do dono (abaixo) | | `files`, `bytes` | Arquivos estáticos na pasta de assets, e o tamanho total deles | | `uploadedFiles`, `uploadedBytes` | O que de fato foi enviado (arquivos novos ou alterados) | | `modules` | Módulos do Worker (0 para um site estático) | ### Projetos na sua própria conta da Cloudflare Um projeto na conta Cloudflare do dono [recebe o deploy do wrangler](https://docs.bohr.io/pt-br/cli/deploy/#projetos-na-sua-própria-conta-da-cloudflare), então as contagens do upload são `null` e no lugar vem a versão do wrangler: ```json { "ok": true, "instanceUrl": "https://app.bohr.io", "url": "https://feature-new-menu-my-site.acme.workers.dev", "deploymentId": "…", "project": { "id": "p8b2m4c6d1ef", "name": "my-site" }, "branch": "feature/new-menu", "production": false, "mode": "byo", "versionId": "…", "previewUrl": "https://1a2b3c4d-my-site.acme.workers.dev", "workerName": "my-site", "commitSha": "…", "files": null, "bytes": null, "uploadedFiles": null, "uploadedBytes": null, "modules": null } ``` | Campo | Descrição | | --- | --- | | `url` | A URL do alias de uma homologação (senão a URL de preview da versão), ou o endereço da produção. `null` para uma homologação de um Worker sem URLs de preview | | `deploymentId` | O registro do deploy na bohr, ou `null` se não foi possível registrá-lo (o deploy foi feito mesmo assim) | | `versionId` | A versão do Worker que o wrangler enviou ou publicou | | `previewUrl` | A URL de preview da própria versão, quando o wrangler imprimiu uma | | `workerName` | O Worker que recebeu o deploy | | `commitSha` | O commit publicado, ou `null` quando a árvore de trabalho tinha mudanças não commitadas (tag `bohr-local`) | ## bohr projects ```json { "ok": true, "instanceUrl": "https://app.bohr.io", "projects": [ { "id": "p3k9x0a7qd2m", "name": "my-site", "repository": "acme/my-site", "productionBranch": "main", "mode": "managed", "status": "active", "role": "owner", "productionUrl": "https://my-site-acme.bohr.io", "hostnames": [ { "hostname": "my-site-acme.bohr.io", "branch": "main", "isProduction": true, "status": "live" } ] } ] } ``` | Campo | Valores | | --- | --- | | `mode` | `managed`: a bohr hospeda. `byo`: a conta Cloudflare do dono (só os donos podem fazer `bohr deploy` dele). | | `status` | `active`, `migrating` ou `suspended` | | `role` | `owner` (pode fazer deploy de produção) ou `member` | | `hostnames[].status` | `live`, ou `pending` enquanto a bohr v1 ainda serve o endereço | ## bohr whoami ```json { "ok": true, "instanceUrl": "https://app.bohr.io", "user": { "id": "u_…", "name": "Ada Lovelace", "email": "ada@example.com" }, "token": { "id": "tok_…", "name": "deploy agent", "projects": ["p3k9x0a7qd2m"], "expiresAt": "2027-01-10T12:00:00.000Z", "source": "BOHR_TOKEN" } } ``` `token.projects` é `null` para um token que alcança todos os seus projetos; `source` é `BOHR_TOKEN` ou `bohr login`. ## Outros comandos | Comando | Campos depois de `"ok": true` | | --- | --- | | `bohr link` | `instanceUrl`, `project` (como em `projects`), `path` (o arquivo escrito) | | `bohr open` | `instanceUrl`, `url`, `project` (`{ id, name }`), `branch` | | `bohr login` | `instanceUrl`, `user` | | `bohr logout` | `instanceUrl`, `signedOut` (`false` quando não havia login) | ## Como ler a saída ```sh out=$(bohr deploy --json) status=$? if [ "$status" -eq 0 ]; then echo "Deployed to $(echo "$out" | jq -r .url)" else echo "Failed: $(echo "$out" | jq -r .error.code)" >&2 fi ``` --- # Códigos de saída e erros > O que significa cada código de saída e código de erro da CLI do bohr, e o que fazer. Source: https://docs.bohr.io/pt-br/cli/exit-codes/ | Código | Significado | O que fazer | | --- | --- | --- | | **0** | Pronto | — | | **1** | Falhou: o build, um upload, o wrangler, uma migration do D1, a instância, a rede, ou deploys demais em poucos minutos | Leia a mensagem. Corrija o build, ou tente de novo mais tarde em erros de rede e limites de taxa. | | **2** | Uso errado: uma opção desconhecida, opções que não combinam, nenhum branch num HEAD destacado, um `.bohr/deploy.json` ou `.bohr/project.json` inválido | Corrija o comando ou o arquivo. | | **3** | Não entrou, ou o token foi rejeitado (expirado, revogado, malformado) | Rode `bohr login`, ou defina `BOHR_TOKEN` com um token válido de **Conta › Tokens**. | | **4** | Projeto não encontrado para este token, nenhum endereço para aquele branch, ou a pasta não é um projeto da bohr v2 | Confira `bohr projects`, os projetos do token, ou rode na pasta certa. | | **5** | Não permitido: produção sem o papel de dono, um projeto na conta Cloudflare do dono sem o papel de dono, um projeto suspenso, uma pasta cuja configuração do wrangler dá outro nome de Worker | Faça deploy de uma homologação, faça push num branch para o workflow do projeto, ou faça deploy de produção pelo painel. | ## Códigos de erro Com `--json`, `error.code` diz exatamente o que aconteceu: | `error.code` | Saída | Significado | | --- | --- | --- | | `usage` | 2 | Comando ou opção desconhecida, ou opções que não combinam | | `no_project` | 2 | Sem `--project`, sem vínculo e sem remote do GitHub: *"Which project? … Pass --project <id> (see "bohr projects"), or run "bohr link"."* | | `no_branch` | 2 | HEAD destacado: passe `--branch` | | `invalid_deploy_config` | 2 | `.bohr/deploy.json` não é um JSON válido ou quebra [as regras dele](https://docs.bohr.io/pt-br/deploys/deploy-json/) | | `invalid_link` | 2 | `.bohr/project.json` é inválido: rode `bohr link` de novo | | `not_signed_in` | 3 | Sem token: rode `bohr login` ou defina `BOHR_TOKEN` | | `invalid_token` | 3 | `BOHR_TOKEN` não começa com `bohr_` | | `login_denied`, `login_expired` | 3 | O `bohr login` foi recusado, ou o código dele expirou | | `http_401` | 3 | A instância rejeitou o token (expirado ou revogado) | | `project_not_found`, `http_404` | 4 | Nenhum projeto para este repositório ou id que este token alcance | | `not_a_v2_project` | 4 | A pasta não é um projeto da bohr v2 (inclusive repositórios da bohr v1). Nada foi alterado. | | `no_address` | 4 | `bohr open`: o branch nunca teve deploy | | `own_account_not_allowed` | 5 | O projeto roda na conta Cloudflare do dono, e só os donos (admins da organização dele) podem fazer deploy dele pela CLI, homologações incluídas. Faça push num branch: o workflow dele faz o deploy do branch de produção | | `worker_mismatch` | 5 | `--prod`: a configuração do wrangler da pasta dá outro nome de Worker que não o do site do projeto. Nada recebeu deploy | | `own_account` | 5 | Só na CLI 4.0.0 e anteriores, que não faziam deploy de projetos na conta Cloudflare do dono: atualize com `npx bohr@latest` | | `production_not_allowed` | 5 | Produção exige o papel de dono | | `production_branch` | 5 | O branch de produção exige `--prod` | | `production_on_v1` | 5 | A bohr v1 ainda serve o endereço de produção: faça deploy de homologações até o workflow do repositório movê-lo | | `suspended`, `http_403` | 5 | O projeto está suspenso, ou a instância recusou a ação | | `cancelled` | 1 | Você respondeu não à pergunta de produção | | `network_error` | 1 | Não foi possível falar com a instância | | `rate_limited` | 1 | Deploys demais de um projeto na sua própria conta da Cloudflare nos últimos minutos (HTTP 429): espere alguns minutos | | `error`, `http_` | 1 | Todo o resto: o build falhou, um upload falhou, o wrangler ou uma migration do D1 falhou, a Cloudflare recusou o deploy… | As mensagens são feitas para pessoas e podem mudar; os códigos são estáveis. --- # Uso em CI > Rode bohr deploy no GitHub Actions e em outros sistemas de CI. Source: https://docs.bohr.io/pt-br/cli/ci/ A CLI percebe quando está em CI: sem terminal, ou com `CI` definida, ela nunca faz perguntas e nunca abre o navegador. ## GitHub Actions com OIDC (sem secret) Com `permissions: id-token: write` e sem `BOHR_TOKEN`, a CLI entra com o token OIDC do GitHub da execução e faz deploy do repositório da execução e do branch que recebeu o push: ```yaml name: Deploy on: { push: { branches: ['**'] } } permissions: { contents: read, id-token: write } jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: { node-version: 22 } - id: bohr run: npx --yes bohr@latest deploy - run: echo "Deployed to ${{ steps.bohr.outputs.url }}" ``` - A CLI roda primeiro o install e o build do `.bohr/deploy.json` (adicione `--no-build` se um step anterior já fez o build do site). - No GitHub Actions a CLI escreve os step outputs `url` e `deployment-id`, mascara secrets com `::add-mask::` e agrupa o log. - `--prod`, `--branch` e `--project` precisam de `BOHR_TOKEN`: com OIDC, quem decide é o branch da execução. - Workflows disparados a partir de forks nunca recebem tokens OIDC. É isso que a [`bohr-io/deploy-action@v1`](https://docs.bohr.io/pt-br/github-action/reference/) faz também. ## Com um token (qualquer CI) Crie um token em **Conta › Tokens** limitado ao projeto, guarde como secret do CI e passe como `BOHR_TOKEN`: ```yaml - run: npx --yes bohr@latest deploy --project p3k9x0a7qd2m --branch "$GITHUB_REF_NAME" --json env: BOHR_TOKEN: ${{ secrets.BOHR_TOKEN }} ``` GitLab CI, com `BOHR_TOKEN` definida como uma variável de CI/CD mascarada: ```yaml deploy: image: node:22 script: - npx --yes bohr@latest deploy --project p3k9x0a7qd2m --branch "$CI_COMMIT_REF_NAME" --json ``` Produção a partir do CI precisa de um token de um **dono** do projeto e de `--prod` (sem terminal, nenhuma pergunta é feita): ```sh BOHR_TOKEN=bohr_… npx --yes bohr@latest deploy --prod --json ``` ## Detecção do branch Sem `--branch`, a CLI usa o branch em checkout; num HEAD destacado (comum em CI) ela recorre a `GITHUB_HEAD_REF` e depois a `GITHUB_REF`. Em outros lugares, passe `--branch` explicitamente. ## Fixar uma versão `npx bohr@latest` sempre roda a versão mais recente. Para fixar uma, use `npx --yes bohr@4.1.0 deploy`, ou adicione `bohr` às suas `devDependencies`. :::note Com `BOHR_TOKEN`, deploys pelo CI também alcançam projetos na sua própria conta da Cloudflare, quando o token é de um dono ([como eles fazem deploy](https://docs.bohr.io/pt-br/cli/deploy/#projetos-na-sua-própria-conta-da-cloudflare)); no GitHub Actions os step outputs `url` e `deployment-id` também são escritos. Com OIDC (sem `BOHR_TOKEN`), a CLI só faz deploy de projetos que a bohr hospeda: projetos na sua própria conta da Cloudflare fazem deploy pelo [workflow de deploy](https://docs.bohr.io/pt-br/deploys/deploy-workflow/) deles. ::: --- # Variáveis de ambiente > As variáveis de ambiente que a CLI do bohr lê. Source: https://docs.bohr.io/pt-br/cli/environment-variables/ | Variável | Descrição | | --- | --- | | `BOHR_TOKEN` | Um token de **Conta › Tokens** (`bohr_…`). Tem prioridade sobre o login guardado pelo `bohr login`. | | `BOHR_INSTANCE_URL` | A instância da bohr, para instâncias auto-hospedadas. Padrão `https://app.bohr.io`. `--instance` tem prioridade sobre ela. | | `BOHR_CONFIG_DIR` | Onde fica o `credentials.json`. Padrão: `$XDG_CONFIG_HOME/bohr`, `~/.config/bohr` (Linux), `~/Library/Application Support/bohr` (macOS), `%APPDATA%\bohr` (Windows). | | `XDG_CONFIG_HOME` | Usada para a pasta de configuração quando `BOHR_CONFIG_DIR` não está definida. | | `BOHR_DEBUG` | Qualquer valor imprime os stack traces dos erros no stderr. | | `CI` | Quando definida, a CLI nunca pergunta e nunca abre o navegador. | Variáveis que a CLI lê no GitHub Actions: | Variável | Uso | | --- | --- | | `GITHUB_ACTIONS` | Liga o formato de log do Actions, os outputs e as máscaras | | `ACTIONS_ID_TOKEN_REQUEST_URL`, `ACTIONS_ID_TOKEN_REQUEST_TOKEN` | Presentes com `id-token: write`: a CLI consegue entrar com OIDC | | `GITHUB_SHA` | O commit registrado com o deployment | | `GITHUB_HEAD_REF`, `GITHUB_REF` | O branch, num HEAD destacado | | `GITHUB_OUTPUT` | Para onde vão os step outputs `url` e `deployment-id` | ## Precedência da instância 1. `--instance ` 2. `BOHR_INSTANCE_URL` 3. `instanceUrl` no `.bohr/project.json` da pasta (`bohr deploy` e `bohr open`) 4. `https://app.bohr.io` --- # Referência da bohr-io/deploy-action > Inputs, outputs e modos da GitHub Action bohr-io/deploy-action@v1. Source: https://docs.bohr.io/pt-br/github-action/reference/ A `bohr-io/deploy-action@v1` faz deploy de projetos da bohr a partir do GitHub Actions. Ela é uma camada fina que roda a [CLI do bohr](https://docs.bohr.io/pt-br/cli/install/) mais recente (`npx --yes bohr@latest action`) com os inputs abaixo. Ela entra na bohr com o **token OIDC do GitHub** da execução, então o job precisa de: ```yaml permissions: contents: read id-token: write ``` Ela tem três modos: | Modo | Input | Usado por | O que faz | | --- | --- | --- | --- | | **Deploy** (padrão) | — | Projetos que a bohr hospeda | Envia o Worker construído e os assets estáticos para a hospedagem da bohr, para o branch que recebeu o push | | **Credenciais** | `credentials: "true"` | Projetos na sua própria conta Cloudflare (no workflow que a bohr escreve) | Obtém as credenciais da Cloudflare e as variáveis de build para o `wrangler deploy`; não faz deploy de nada | | **Plano de build** | `build-plan: "true"` | Projetos migrados da bohr v1 que mantêm o workflow da v1 | Obtém o plano de build do projeto; não faz deploy de nada | Raramente você mesmo adiciona a action: a bohr a escreve no [`bohr-deploy.yml`](https://docs.bohr.io/pt-br/deploys/deploy-workflow/) dos projetos na sua conta, e os projetos migrados a rodam pelo workflow da v1. ## Inputs | Input | Padrão | Descrição | | --- | --- | --- | | `instance-url` | `https://app.bohr.io` | URL base da instância da bohr que gerencia o projeto. Precisa usar `https`. | | `working-directory` | `.` | Pasta com o `wrangler.jsonc` (ou `wrangler.json`) do projeto, relativa à raiz do repositório. Modo deploy. | | `credentials` | `false` | `"true"`: só obtém as credenciais de deploy e as variáveis de build de um projeto na conta do dono. | | `build-plan` | `false` | `"true"`: só prepara o build de um projeto migrado da bohr v1. | | `phase` | `prepare` | Com `build-plan: "true"`: o passo a rodar. Só existe `prepare`. | `credentials` e `build-plan` não podem ser `"true"` ao mesmo tempo. ## Outputs | Output | Modo | Descrição | | --- | --- | --- | | `url` | Deploy | URL onde o branch publicado é servido | | `deployment-id` | Deploy | Identificador do deployment na instância da bohr | | `cloudflare-api-token` | Credenciais | O token de API da Cloudflare para fazer o deploy (mascarado) | | `cloudflare-account-id` | Credenciais | A conta Cloudflare onde fazer o deploy (mascarado) | | `found` | Plano de build | `"true"` quando a bohr tem um plano de build para este repositório, senão `"false"` | | `node-version` | Plano de build | A versão do Node.js para o `actions/setup-node` | | `install` | Plano de build | O comando de install (vazio: nenhum) | | `build` | Plano de build | O comando de build (vazio: nenhum) | | `live` | Plano de build | `"true"` quando o endereço de produção do projeto já foi para a bohr v2 | No modo deploy, o job summary mostra a URL e quantos arquivos foram encontrados e enviados. ## Modo deploy Rode o seu build antes da action: ela faz deploy do que o build escreveu, e não instala dependências nem faz build. Cada branch que recebe push ganha deploy no seu próprio endereço; o branch de produção recebe o endereço principal do projeto. A action lê `wrangler.json` ou `wrangler.jsonc` em `working-directory`, empacota o `main` com `wrangler deploy --dry-run` (adicione `wrangler` às suas `devDependencies` para fixar a versão) e envia só os arquivos estáticos novos ou alterados. Projetos hospedados suportam assets estáticos, `vars` e secrets: veja [Configuração do wrangler](https://docs.bohr.io/pt-br/deploys/wrangler-config/#projetos-hospedados-pela-bohr). ## Modo credenciais Com `credentials: "true"` a action pede as credenciais à bohr (`POST /api/deploy/credentials` com o token OIDC), mascara todos os valores e então: - exporta as [variáveis de build](https://docs.bohr.io/pt-br/projects/variables/#variáveis-do-build) do projeto (branch de produção) para o ambiente dos steps seguintes, para que o install e o build as vejam; - define o token e a conta da Cloudflare como outputs do step, para que só o step que os mapeia (o deploy) os receba. A bohr só responde a execuções de `.github/workflows/bohr-deploy.yml` num `push` (ou `workflow_dispatch`) para o branch de produção do projeto, de um projeto na conta Cloudflare do dono. Ela entrega o token do próprio dono (o seu, ou o da sua organização), nunca o da bohr. ## Modo plano de build Para repositórios migrados da bohr v1 que mantêm o workflow (`.github/workflows/bohr.yml` rodando `bohr-io/action@main`). A action da bohr v1 chama esta duas vezes: para preparar (`build-plan: "true"`) e depois para fazer o deploy. Nada é escrito no seu repositório. Veja [Migrar da bohr v1](https://docs.bohr.io/pt-br/migrating-from-v1/what-changes/). ## Erros | Erro | Correção | | --- | --- | | `Could not get a GitHub OIDC token` | Adicione `permissions: id-token: write` ao workflow ou ao job. Workflows disparados a partir de forks nunca recebem tokens OIDC. | | `No bohr.io Cloud managed project matches this repository and branch` | Crie ou migre o projeto no painel da bohr, e faça deploy em pushes de branch (não em tags nem pull requests). | | `could not give the deploy credentials (HTTP 403)` | Modo credenciais: a mensagem diz o motivo. Só o `bohr-deploy.yml` num push para o branch de produção de um projeto na conta do dono recebe as credenciais. | | `Found wrangler.toml, but this action reads wrangler.jsonc` | Converta a configuração para `wrangler.jsonc`. | | `… is not supported` | Remova o binding; projetos hospedados suportam assets estáticos, vars e secrets. | | `The assets directory … does not exist` | Rode o build antes da action, ou corrija `assets.directory`. | | `Asset too large: …` | Arquivos com mais de 25 MiB não podem ir no deploy: remova o arquivo ou liste-o no `.assetsignore`. | --- # Exemplos > Workflows que usam a bohr-io/deploy-action@v1. Source: https://docs.bohr.io/pt-br/github-action/examples/ ## Deploy de todos os branches de um projeto que a bohr hospeda ```yaml name: Deploy on: { push: { branches: ['**'] } } permissions: { contents: read, id-token: write } jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: { node-version: 22 } - run: npm ci && npm run build # o build do próprio projeto - id: deploy uses: bohr-io/deploy-action@v1 - run: echo "Deployed to ${{ steps.deploy.outputs.url }}" ``` ## Um projeto numa subpasta ```yaml - run: npm ci && npm run build working-directory: apps/web - uses: bohr-io/deploy-action@v1 with: working-directory: apps/web ``` ## Uma instância auto-hospedada ```yaml - uses: bohr-io/deploy-action@v1 with: instance-url: https://bohr.example.com ``` ## Credenciais para o wrangler (projetos na sua própria conta) Esta é a parte do workflow que a bohr escreve para você ([workflow completo](https://docs.bohr.io/pt-br/deploys/deploy-workflow/)). O arquivo precisa ser `.github/workflows/bohr-deploy.yml`, rodando em pushes para o branch de produção: ```yaml permissions: { contents: read, id-token: write } jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 - name: bohr credentials id: bohr-credentials uses: bohr-io/deploy-action@v1 with: credentials: "true" - run: npm ci && npm run build # vê as variáveis de build - run: npx wrangler deploy env: CLOUDFLARE_API_TOKEN: ${{ steps.bohr-credentials.outputs.cloudflare-api-token }} CLOUDFLARE_ACCOUNT_ID: ${{ steps.bohr-credentials.outputs.cloudflare-account-id }} ``` ## A CLI como um step simples O mesmo deploy sem a action: ```yaml - id: bohr run: npx --yes bohr@latest deploy - run: echo "Deployed to ${{ steps.bohr.outputs.url }}" ``` Veja [Uso em CI](https://docs.bohr.io/pt-br/cli/ci/). --- # Deploy a partir de agentes de IA de programação > Como Claude Code, Cursor, Codex e outros agentes de programação fazem deploy de projetos da bohr com a CLI. Source: https://docs.bohr.io/pt-br/ai-agents/overview/ Agentes de IA de programação (Claude Code, Cursor, Codex, Windsurf, Aider, os seus próprios scripts) conseguem fazer deploy de projetos da bohr com a [CLI do bohr](https://docs.bohr.io/pt-br/cli/install/): build, upload e uma URL de homologação para mostrar a você, sem navegador e sem a sua senha. Esta seção foi escrita para você **e** para o agente. Aponte o seu agente para ela, ou entregue a ele as instruções prontas: - [Trecho para AGENTS.md / CLAUDE.md](https://docs.bohr.io/pt-br/ai-agents/agents-md/): cole no arquivo de instruções do seu repositório. - [SKILL.md](https://docs.bohr.io/pt-br/ai-agents/skill/): um arquivo de skill que o agente carrega quando precisa fazer deploy. ## Versão resumida ```sh # 1. Você: crie um token no painel (Conta › Tokens), limitado ao projeto, e entregue ao agente export BOHR_TOKEN=bohr_… # 2. O agente: encontra o projeto uma vez npx --yes bohr@latest projects --json # 3. O agente: faz deploy de uma homologação depois de cada mudança e lê "url" do JSON npx --yes bohr@latest deploy --project p3k9x0a7qd2m --branch agent/new-header --json ``` ## Como isso convive com o agente da própria bohr A bohr já tem um agente que muda o seu site a partir de um chat, com homologação e aprovação. Um agente de programação externo é para quando você trabalha no seu editor ou terminal: ele muda o código localmente e usa o `bohr deploy` para publicar homologações do trabalho dele. | | O agente da bohr | O seu agente de programação + CLI | | --- | --- | --- | | Onde roda | O sandbox na sua conta Cloudflare | A sua máquina, ou o próprio sandbox do agente | | Homologação | O branch `homolog`, aprovada no painel | Qualquer nome de branch, com `bohr deploy` | | Produção | Aprovação no painel ou no Telegram | `bohr deploy --prod` (donos), só quando você pedir | ## Continue lendo 1. [Configure um token](https://docs.bohr.io/pt-br/ai-agents/setup/): com escopo, não interativo. 2. [O ciclo de deploy](https://docs.bohr.io/pt-br/ai-agents/deploy-loop/): `--json`, códigos de saída e a etiqueta de homologação vs `--prod`. 3. [Trecho para AGENTS.md](https://docs.bohr.io/pt-br/ai-agents/agents-md/) e [SKILL.md](https://docs.bohr.io/pt-br/ai-agents/skill/). :::note[Projetos na sua própria conta da Cloudflare] O `bohr deploy` também publica projetos na sua própria conta da Cloudflare, mas só com um token de um dono do projeto (homologações incluídas), já que o wrangler faz o deploy deles com a conexão da Cloudflare do dono. Com o token de qualquer outra pessoa, ele sai com o código 5 (`own_account_not_allowed`); o agente deve então fazer commit num branch e abrir um pull request, e o merge faz o deploy pelo workflow do projeto. As homologações deles usam os bancos D1 da produção. Veja [o ciclo de deploy](https://docs.bohr.io/pt-br/ai-agents/deploy-loop/#projetos-na-sua-própria-conta-cloudflare). ::: --- # Configurar um token para um agente > Crie um token da bohr com escopo e entregue a um agente de IA sem expô-lo. Source: https://docs.bohr.io/pt-br/ai-agents/setup/ ## 1. Crie um token com escopo No painel, abra **Conta › Tokens** e preencha **Novo token**: | Campo | Recomendação | | --- | --- | | **Nome** | Algo que você vá reconhecer depois, como `claude code - shop` | | **Projetos** | **Só estes projetos**, e escolha só aqueles em que o agente trabalha. Evite **Todos os meus projetos, inclusive os que eu entrar depois**. | | **Expira** | **Em 30 dias**, **Em 90 dias** ou **Em 365 dias**. Prefira um prazo curto; crie um token novo quando ele expirar. | Clique em **Criar token** e copie o token: o painel o mostra uma única vez (*"Quem tiver o token publica como você."*). Um token age como **você**, nos projetos dos quais você é membro, limitado aos que ele lista. Ele pode fazer deploy de homologações; deploy de produção só nos projetos que são seus, e de projetos na conta Cloudflare do dono só quando eles são seus (homologações incluídas). Ele nunca carrega o papel de administrador da instância. ## 2. Entregue o token ao agente Defina o token como a variável de ambiente `BOHR_TOKEN` onde o agente roda comandos. Nunca cole o token no chat nem num arquivo do repositório. ```sh # um shell a partir do qual você inicia o agente export BOHR_TOKEN=bohr_… claude ``` - **Claude Code**: exporte no shell antes de iniciar o `claude`, ou adicione ao `env` das suas configurações de usuário (`~/.claude/settings.json`), nunca ao `.claude/settings.json` do repositório. - **Cursor, Windsurf**: defina no ambiente que o terminal do editor herda. - **Codex e agentes na nuvem**: adicione como secret do ambiente do agente. - **CI**: um secret de CI mascarado (veja [Uso em CI](https://docs.bohr.io/pt-br/cli/ci/)). Confira se funciona: ```sh npx --yes bohr@latest whoami --json ``` ## 3. Não interativo por padrão A CLI nunca faz perguntas e nunca abre o navegador quando não há terminal, quando `CI` está definida ou com `--json`. Os agentes devem sempre passar `--json`. Os agentes não devem rodar `bohr login`: ele precisa de uma pessoa para aprovar num navegador. ## Revogar **Conta › Tokens › Revogar** para o token na hora. Os deploys que ele já publicou continuam no ar. Cada token mostra quando foi **usado** pela última vez. --- # O ciclo de deploy > Como um agente de IA deve chamar a CLI, ler o JSON, reagir aos códigos de saída, e quando (não) fazer deploy de produção. Source: https://docs.bohr.io/pt-br/ai-agents/deploy-loop/ ## 1. Encontre o projeto uma vez ```sh npx --yes bohr@latest projects --json ``` Compare `repository` (`owner/name`) com o remote do GitHub do repositório e guarde o `id` do projeto. Confira: - `mode`: `managed` significa que a bohr hospeda o projeto; `byo` significa que ele roda na conta Cloudflare do dono (veja [abaixo](#projetos-na-sua-própria-conta-cloudflare)). O `bohr deploy` publica os dois. - `role`: `owner` é necessário para produção, e para qualquer deploy de um projeto `byo`. Se o repositório tiver `.bohr/project.json` (do `bohr link`), dá para omitir `--project`. ## 2. Faça deploy de uma homologação depois de cada mudança ```sh npx --yes bohr@latest deploy --project p3k9x0a7qd2m --branch agent/fix-contact-form --json ``` - Escolha um nome de branch que descreva a mudança; ele não precisa existir no git. Cada branch ganha o seu próprio endereço, então homologações de mudanças diferentes não se sobrescrevem. - A CLI roda primeiro o install e o build do `.bohr/deploy.json`. Passe `--no-build` só quando o agente já fez o build do site no mesmo ambiente. - Leia o resultado no stdout e mostre a `url` à pessoa. ```json { "ok": true, "url": "https://agent-fix-contact-form-shop-acme.bohr.io", "branch": "agent/fix-contact-form", "production": false, "...": "…" } ``` Schema completo: [Saída JSON](https://docs.bohr.io/pt-br/cli/json-output/#bohr-deploy). ## 3. Reaja ao código de saída | Saída | O agente deve | | --- | --- | | 0 | Informar a `url`. | | 1 | Ler `error.message` (e o stderr). Corrigir um erro de build e tentar de novo **uma vez**. Para `network_error`, esperar e tentar de novo uma vez. | | 2 | Corrigir o comando ou o arquivo que a mensagem cita. `no_branch`: passar `--branch`. | | 3 | **Parar** e pedir à pessoa um `BOHR_TOKEN` válido. Não rodar `bohr login`. | | 4 | Conferir de novo `projects --json`. `not_a_v2_project`: parar e avisar a pessoa; a pasta não é um projeto da bohr v2. | | 5 | **Não tentar de novo.** Explicar o motivo (`own_account_not_allowed`, `production_not_allowed`, `production_on_v1`, `worker_mismatch`, `suspended`) e fazer deploy de uma homologação quando fizer sentido. | Todos os códigos: [Códigos de saída e erros](https://docs.bohr.io/pt-br/cli/exit-codes/). ## Etiqueta de homologação vs produção - **Homologações são o padrão** e são seguras: nunca tocam a produção. Faça deploy de uma sempre que quiser que a pessoa veja uma mudança. - **Produção só com um pedido explícito** na conversa atual, como *"publica em produção"*. Uma aprovação anterior, um build que passou ou um branch com merge não é um pedido. - Antes de `--prod`, diga o que vai ser publicado. `--prod` vindo de um agente roda sem a pergunta de confirmação, então o agente é a última verificação. - Nunca faça deploy de produção para corrigir um problema em produção sem perguntar; faça primeiro o deploy de uma homologação da correção. - Não rode `bohr deploy` em loop. Um deploy por mudança relevante. ## Projetos na sua própria conta Cloudflare O `bohr deploy` faz o deploy de projetos na conta Cloudflare do dono (`mode: "byo"`) com o wrangler, usando o token da Cloudflare que o dono conectou à bohr ([detalhes](https://docs.bohr.io/pt-br/cli/deploy/#projetos-na-sua-própria-conta-da-cloudflare)). O mesmo ciclo funciona, com estas diferenças: - **Só o token de um dono** consegue fazer deploy deles, homologações incluídas. Com o de qualquer outra pessoa, a CLI sai com o código 5 e `error.code: "own_account_not_allowed"` antes de construir qualquer coisa. Aí o agente deve fazer commit da mudança num branch novo, fazer push dele, abrir um pull request para o branch de produção e deixar uma pessoa revisar e fazer o merge; o workflow do projeto faz o deploy do branch de produção. Nunca fazer push direto no branch de produção. A pessoa também pode pedir a mudança ao agente da própria bohr, no painel ou no Telegram: ela vem com uma homologação para aprovar. - Uma homologação é uma nova versão do Worker sob um alias do branch; ela nunca muda a produção. Se `url` for `null`, o Worker não tem URLs de preview (`"preview_urls": true` na configuração do wrangler dele): avise a pessoa. - **As homologações usam os bancos D1 da produção** e não aplicam migrations. Pergunte antes de fazer deploy de uma homologação que grava dados ou depende de uma mudança de schema. - `--prod` aplica as migrations do D1 e depois faz o deploy. `worker_mismatch` (código de saída 5) significa que a configuração do wrangler da pasta dá outro nome de Worker: nada recebeu deploy. - `error.code: "own_account"` só vem da CLI 4.0.0 e anteriores: rode `npx --yes bohr@latest`. --- # Trecho para AGENTS.md / CLAUDE.md > Instruções para copiar e colar que ensinam um agente de programação a fazer deploy do seu projeto com a CLI do bohr. Source: https://docs.bohr.io/pt-br/ai-agents/agents-md/ Cole esta seção no arquivo de instruções do seu repositório: `AGENTS.md` (Codex, Cursor e muitos outros), `CLAUDE.md` (Claude Code), `.cursor/rules`, ou o que o seu agente ler. Ela diz ao agente como fazer deploy de homologações, quando não fazer deploy de produção e o que fazer em cada código de saída. **Download:** [AGENTS.md](https://docs.bohr.io/pt-br/downloads/AGENTS.md) (Markdown puro). Para acrescentá-lo ao seu `AGENTS.md` pelo terminal (ele só é adicionado se o download for de fato o trecho): ```sh tmp=$(mktemp) if curl -fsSL https://docs.bohr.io/pt-br/downloads/AGENTS.md -o "$tmp" && grep -q 'npx --yes bohr@latest' "$tmp" && ! grep -qi '> AGENTS.md && cat "$tmp" >> AGENTS.md && echo "Adicionado ao AGENTS.md" else echo "O download não é o trecho da bohr: o AGENTS.md não foi alterado." >&2 fi rm -f "$tmp" ``` ````markdown ## Deploy com a bohr Este projeto faz deploy com a [bohr](https://docs.bohr.io/pt-br/). Use a CLI do bohr; nunca faça deploy com outras ferramentas. - Autenticação: a variável de ambiente `BOHR_TOKEN` (um token do painel da bohr, Conta › Tokens). Nunca imprima, registre em log, faça commit nem passe o token na linha de comando. - Sempre rode a CLI de forma não interativa com `--json`: `npx --yes bohr@latest --json`. O stdout é exatamente um objeto JSON; os logs vão para o stderr. - Encontre o projeto uma vez: `npx --yes bohr@latest projects --json`. Use o `id` do projeto cujo `repository` corresponde a este repositório. `mode: "managed"`: a bohr hospeda o projeto. `mode: "byo"`: ele roda na conta Cloudflare do dono, e só o token de um dono consegue fazer deploy dele (homologações também). - Faça deploy de uma **homologação** depois de cada mudança que você quiser mostrar: `npx --yes bohr@latest deploy --project --branch --json` Leia a `url` do JSON e entregue ao usuário. Use um nome de branch que descreva a mudança (por exemplo `agent/fix-contact-form`). - **Nunca faça deploy de produção** (`--prod`) a não ser que o usuário tenha pedido explicitamente um deploy de produção nesta conversa. Produção exige o papel de dono. - Nunca faça commit de arquivos `.env` nem de secrets. A bohr nunca publica arquivos `.git` ou `.env*`. - Códigos de saída: 0 pronto; 1 falhou (leia `error.message`, corrija o build, tente de novo uma vez); 2 uso errado (corrija o comando); 3 não entrou ou token rejeitado (pare e peça ao usuário um `BOHR_TOKEN` válido); 4 projeto não encontrado ou não é um projeto da bohr v2 (confira `projects --json`, não chute); 5 não permitido (não tente de novo; diga ao usuário: produção sem o papel de dono, um projeto na conta Cloudflare do dono sem o papel de dono, um projeto suspenso, ou uma configuração do wrangler de outro Worker). - Se `error.code` for `own_account_not_allowed`, este token não consegue fazer deploy do projeto: faça commit num branch, abra um pull request para o branch de produção e deixe uma pessoa fazer o merge. Não faça push no branch de produção você mesmo. Se for `own_account`, a CLI está desatualizada: rode `npx --yes bohr@latest`. - Em projetos com `mode: "byo"`, as homologações usam os bancos D1 da produção e não aplicam migrations: pergunte ao usuário antes de fazer deploy de uma homologação que grava dados ou precisa de uma mudança de schema. Se `url` for `null`, o Worker não tem URLs de preview (`"preview_urls": true` na configuração do wrangler dele). - As configurações de build ficam em `.bohr/deploy.json`; o servidor de desenvolvimento da homologação, em `.bohr/preview.json`. Não edite `.github/workflows/bohr-deploy.yml`: a bohr gera esse arquivo. ```` ## Como adaptar - Se você sempre faz deploy do mesmo projeto, troque o passo do `projects --json` pelo id dele, ou rode `bohr link` e faça commit do `.bohr/project.json`. - Mantenha a regra de produção, a não ser que você queira mesmo que o agente publique sem perguntar, e mantenha o token limitado ao projeto de qualquer forma. - Mantenha as regras do `own_account_not_allowed` e do D1 para projetos na sua própria conta da Cloudflare: só o token de um dono faz deploy deles, e as homologações deles usam os bancos D1 da produção ([detalhes](https://docs.bohr.io/pt-br/cli/deploy/#projetos-na-sua-própria-conta-da-cloudflare)). --- # SKILL.md para agentes > Um arquivo de skill no formato de skills do Claude Code com tudo o que um agente de IA precisa para fazer deploy de projetos da bohr. Source: https://docs.bohr.io/pt-br/ai-agents/skill/ Uma **skill** é um arquivo de instruções que o agente carrega só quando precisa. Esta segue o formato de skills do Claude Code (uma pasta com um `SKILL.md` que começa com um `name` e uma `description`); outros agentes podem lê-la como instruções comuns. **Download:** [SKILL.md](https://docs.bohr.io/pt-br/downloads/bohr-deploy/SKILL.md). ## Como instalar No Claude Code, coloque-a numa pasta `bohr-deploy` das suas skills. O comando baixa o arquivo para um arquivo temporário e só o instala se ele for de fato a skill da bohr (começa com `---` e `name: bohr-deploy`), então um download que falhou ou veio errado nunca substitui uma skill que você já tem: ```sh # para um repositório (faça commit para a sua equipe também receber); para todos os projetos # do seu computador, use dir=~/.claude/skills/bohr-deploy dir=.claude/skills/bohr-deploy tmp=$(mktemp) if curl -fsSL https://docs.bohr.io/pt-br/downloads/bohr-deploy/SKILL.md -o "$tmp" && [ "$(head -n 2 "$tmp")" = "$(printf '%s\n%s' '---' 'name: bohr-deploy')" ]; then mkdir -p "$dir" && mv "$tmp" "$dir/SKILL.md" && echo "Instalado em $dir/SKILL.md" else rm -f "$tmp"; echo "O download não é a skill da bohr: nada foi instalado." >&2 fi ``` Outros agentes: salve o arquivo em qualquer lugar e aponte para ele no seu arquivo de instruções, ou cole-o nas instruções do agente. ## O arquivo ````markdown --- name: bohr-deploy description: Faz deploy de um projeto da bohr (bohr.io) com a CLI do bohr. Use quando o usuário pedir para fazer deploy, publicar, gerar uma homologação (preview) ou colocar no ar um site que faz deploy com a bohr, quando o repositório tiver uma pasta .bohr/ (.bohr/deploy.json, .bohr/project.json), ou quando BOHR_TOKEN estiver definida. --- # Deploy de projetos da bohr A bohr (https://docs.bohr.io/pt-br/) faz deploy de repositórios do GitHub como Cloudflare Workers. A CLI `bohr` (pacote npm `bohr`, Node.js 20+) faz deploy de um projeto a partir desta máquina: homologações de qualquer branch, e produção para os donos do projeto. ## Regras 1. Use só a CLI do bohr para fazer deploy, sempre de forma não interativa e com `--json`: `npx --yes bohr@latest --json` O stdout é exatamente um objeto JSON. Logs e a saída do build vão para o stderr. 2. Autentique com a variável de ambiente `BOHR_TOKEN`. Nunca imprima, registre em log, faça commit ou dê echo no token, e nunca o coloque numa linha de comando. Se ele estiver faltando, peça ao usuário para criar um no painel da bohr (Conta › Tokens), limitado a este projeto, e defini-lo como `BOHR_TOKEN`. 3. Faça deploy de **homologações** por padrão. Faça deploy de **produção** (`--prod`) só quando o usuário tiver pedido explicitamente um deploy de produção nesta conversa. 4. Nunca faça commit de secrets nem de arquivos `.env`. Coloque os secrets no painel da bohr (Configurações › Variáveis de ambiente), não no `wrangler.jsonc`. 5. Não edite `.github/workflows/bohr-deploy.yml` (a bohr gera esse arquivo a partir do `.bohr/deploy.json`). ## Passos ### 1. Encontre o projeto (uma vez por sessão) ```sh npx --yes bohr@latest projects --json ``` Escolha o projeto cujo `repository` (`owner/name`) corresponde ao remote do GitHub deste repositório. Guarde o `id` dele. - `mode: "managed"`: a bohr hospeda o projeto; o `bohr deploy` o publica. - `mode: "byo"`: ele roda na conta Cloudflare do dono; o `bohr deploy` o publica com o wrangler, só para os donos (veja "Projetos na conta Cloudflare do dono"). - `role: "owner"` é necessário para produção, e para qualquer deploy de um projeto `byo`. Como alternativa, se o repositório tiver `.bohr/project.json`, a CLI já sabe qual é o projeto e dá para omitir `--project`. ### 2. Faça deploy de uma homologação depois de cada mudança ```sh npx --yes bohr@latest deploy --project --branch --json ``` - Use um nome de branch descritivo, por exemplo `agent/`. Ele não precisa existir no git. - A CLI roda primeiro o install e o build do `.bohr/deploy.json`. Adicione `--no-build` só se você já fez o build do site neste ambiente. - Em caso de sucesso, leia a `url` e entregue ao usuário. Também são úteis: `deploymentId`, `files`, `uploadedFiles`. Exemplo de sucesso: ```json {"ok":true,"url":"https://agent-fix-form-shop-acme.bohr.io","deploymentId":"d_…","project":{"id":"p3k9x0a7qd2m","name":"shop"},"branch":"agent/fix-form","production":false,"files":42,"bytes":1363148,"uploadedFiles":3,"uploadedBytes":20480,"modules":1} ``` ### 3. Produção (só quando pedirem) ```sh npx --yes bohr@latest deploy --project --prod --json ``` ## Como tratar o resultado Em caso de falha, o stdout é `{"ok":false,"error":{"code","message","exitCode"}}` e o processo sai com `exitCode`. Decida com base no código de saída e em `error.code`: | Saída | Significado | O que fazer | | --- | --- | --- | | 0 | Pronto | Informe a `url`. | | 1 | Falhou (build, upload, wrangler, migration do D1, rede, instância, `rate_limited`) | Leia `error.message` e o log do stderr. Corrija um erro de build e tente de novo uma vez. Para `network_error`, tente de novo uma vez depois de uma breve espera. Para `rate_limited`, pare e diga ao usuário para esperar alguns minutos. | | 2 | Uso errado (`usage`, `no_project`, `no_branch`, `invalid_deploy_config`, `invalid_link`) | Corrija o comando ou o arquivo citado na mensagem. Para `no_branch`, passe `--branch`. | | 3 | Não entrou ou token rejeitado (`not_signed_in`, `invalid_token`, `http_401`) | Pare. Peça ao usuário um `BOHR_TOKEN` válido. Não tente `bohr login` (ele precisa de uma pessoa e de um navegador). | | 4 | Não encontrado (`project_not_found`, `not_a_v2_project`, `no_address`) | Confira de novo `projects --json` e os projetos do token. `not_a_v2_project` significa que esta pasta não é um projeto da bohr v2 (talvez um repositório da bohr v1): pare e avise o usuário. | | 5 | Não permitido (`own_account_not_allowed`, `production_not_allowed`, `production_on_v1`, `worker_mismatch`, `suspended`, `http_403`, `own_account`) | Não tente de novo. Diga ao usuário o motivo. Para `production_not_allowed` ou `production_on_v1`, faça deploy de uma homologação. Para `own_account_not_allowed`, veja abaixo. `own_account` só vem de uma CLI desatualizada: rode `npx --yes bohr@latest`. | ## Projetos na conta Cloudflare do dono (`mode: "byo"`) O `bohr deploy` faz o deploy deles com o wrangler, usando o token da Cloudflare que o dono conectou à bohr. O resultado tem `"mode": "byo"`, mais `versionId`, `previewUrl`, `workerName` e `commitSha` (as contagens do upload são `null`). - Só os donos do projeto (admins da organização dele) podem fazer deploy deles, homologações incluídas. Qualquer outra pessoa recebe o código de saída 5 com `own_account_not_allowed`: não faça push no branch de produção você mesmo; faça commit da sua mudança num branch, faça push dele, abra um pull request para o branch de produção e deixe uma pessoa revisar e fazer o merge. O próprio agente da bohr do projeto (no painel da bohr ou no Telegram) também pode fazer a mudança, com uma homologação. - Uma homologação envia uma nova versão do Worker e nunca muda a produção. Se `url` for `null`, o Worker não tem URLs de preview: diga ao usuário para definir `"preview_urls": true` na configuração do wrangler dele. - As homologações usam os **bancos D1 da produção** e não aplicam migrations do D1. Pergunte ao usuário antes de fazer deploy de uma homologação que grava dados ou depende de uma mudança de schema. - `--prod` aplica as migrations do D1 e depois faz o deploy. `worker_mismatch` significa que a configuração do wrangler da pasta dá outro nome de Worker que não o do projeto: nada recebeu deploy; avise o usuário. ## Arquivos úteis - `.bohr/deploy.json`: como a produção é construída (`directory`, `node`, `packageManager`, `install`, `build`, `deploy`, `secrets`). - `.bohr/preview.json`: como roda o servidor de desenvolvimento da homologação (`install`, `command`, `port`, `env`). - `wrangler.jsonc`: o Worker. Projetos que a bohr hospeda suportam só assets estáticos, `vars` e secrets; outros bindings fazem o deploy falhar. - Arquivos estáticos com mais de 25 MiB não podem ir no deploy. Arquivos `.git` e `.env*` nunca são publicados. Docs: https://docs.bohr.io/pt-br/ai-agents/overview/ (Markdown: https://docs.bohr.io/pt-br/llms.txt) ```` --- # Organizações > Trabalhe em equipe numa organização da bohr, que espelha uma organização do GitHub. Source: https://docs.bohr.io/pt-br/organizations/overview/ Uma **organização** da bohr é uma organização do GitHub com o app do GitHub da bohr instalado. Os membros vêm do GitHub, e ela tem a própria assinatura (no bohr.io Cloud), conta da Cloudflare e configurações do agente, separadas das de cada pessoa. ## Criar uma organização Você precisa de uma organização no GitHub da qual seja **dono**. A bohr não cria organizações no GitHub: se precisar, crie uma no GitHub antes (**Criar uma organização no GitHub**). 1. Abra o menu de contexto no topo do painel e escolha **Nova organização**. 2. Clique em **Instalar o app do GitHub numa organização**. 3. No GitHub, escolha a organização e os repositórios que a bohr pode acessar, e confirme. 4. O GitHub traz você de volta para a página da organização na bohr. A bohr importa os membros da organização com o papel equivalente: os donos no GitHub viram **admins**, e os demais, **membros**. Se o App foi instalado fora da bohr por alguém que já usa a bohr, a organização também é criada. ## Configurar A página da organização mostra **Configure a organização** para os admins, com três passos (como na sua própria conta): | Passo | | | --- | --- | | **Assinatura** | Só no bohr.io Cloud: a assinatura própria da organização, paga por um admin. Os membros não precisam de uma. | | **Cloudflare** | A conta da Cloudflare onde rodam todos os projetos da organização (Workers Paid). O mesmo token que [para você](https://docs.bohr.io/pt-br/getting-started/connect-cloudflare/). | | **Agente** | O provedor e a chave que o agente usa em todos os projetos da organização. As mesmas opções que [as suas](https://docs.bohr.io/pt-br/agent/providers/), incluindo uma assinatura Claude. | Até a configuração terminar, os membros veem *"Um admin da organização ainda precisa terminar a configuração (assinatura e conta da Cloudflare) antes de criar projetos."* ## Alternar entre pessoal e organização O menu de contexto no topo do painel (**Trabalhar em**) lista **Pessoal** e cada uma das suas organizações. A lista de projetos, **Novo projeto** e as configurações seguem o contexto escolhido. - Projetos criados numa organização usam a conta da Cloudflare e o agente da organização, seja quem for que os crie. - No seu contexto pessoal, uma lista lembra das organizações cujos projetos não precisam de configuração na sua conta. ## Páginas da organização | Página | | | --- | --- | | **Projetos** | Os projetos da organização, e **Novo projeto** (um dos repositórios da organização) | | **Membros** | Membros, papéis e sincronização com o GitHub. Veja [Membros e papéis](https://docs.bohr.io/pt-br/organizations/members/). | | **Configurações** | Geral, Cloudflare, agente, assinatura e a zona de perigo. Veja [Configurações e cobrança](https://docs.bohr.io/pt-br/organizations/settings-and-billing/). | --- # Membros e papéis da organização > Como os membros da organização espelham o GitHub, os papéis deles e como mudar ou remover o acesso. Source: https://docs.bohr.io/pt-br/organizations/members/ **O GitHub é a fonte dos membros.** A bohr espelha os membros da organização no GitHub: os donos no GitHub viram **admins** na bohr, e os demais, **membros**. | Papel | Pode | | --- | --- | | **Admin** | Tudo o que o dono de um projeto pode, em todos os projetos da organização (configurações, domínios, variáveis, exclusão); as configurações, a assinatura, a conta da Cloudflare e o agente da organização; os papéis dos membros | | **Membro** | Trabalhar em todos os projetos da organização: pedir mudanças, aprovar, descartar, reverter | Os membros não precisam de assinatura, conta da Cloudflare nem chave de modelo próprias. ## Mantendo a sincronia - Pessoas adicionadas à organização no GitHub ou removidas dela entram ou saem automaticamente (o GitHub avisa a bohr). - **Sincronizar com o GitHub**, na página **Membros**, sincroniza manualmente: *"Membros sincronizados: N adicionados, N removidos, N atualizados."* - Pessoas que ainda não têm conta na bohr aparecem como **Pendente** (*"Entra quando acessar a bohr com o GitHub."*). Elas ficam ativas quando entram com essa conta do GitHub, ou quando a vinculam à conta delas na bohr. ## Mudando o acesso na bohr Os admins podem mudar coisas na bohr sem mexer no GitHub. Nesses casos, a coluna **Origem** mostra **Alterado na bohr**. - **Tornar admin** / **Tornar membro**: o papel vale até o papel dessa pessoa mudar no GitHub. - **Remover**: a pessoa perde o acesso aos projetos da organização na bohr. Ela continua na organização do GitHub, e a sincronização não traz o acesso de volta. - A organização precisa de pelo menos um admin: *"A organização precisa de pelo menos um admin. Torne outra pessoa admin primeiro."* ## Quando os membros não são importados Se o app do GitHub não tem a permissão **Members: read** na organização, só quem o instalou é adicionado, e a página diz *"Os membros não foram importados"*. Conceda a permissão no GitHub (as configurações do App na organização pedem que você a aceite) e depois clique em **Sincronizar com o GitHub**. ## Membros do projeto de fora da organização Os [convites](https://docs.bohr.io/pt-br/projects/members/) de projeto também funcionam em projetos de organizações, para pessoas de fora da organização no GitHub, como um cliente que revisa a homologação. --- # Configurações e cobrança da organização > A conta da Cloudflare, o agente e a assinatura de uma organização, e como excluí-la. Source: https://docs.bohr.io/pt-br/organizations/settings-and-billing/ **Configurações** de uma organização. Só os admins dela as mudam (*"Só os admins da organização mudam as configurações."*). ## Geral O **Nome** e a foto vêm da organização no GitHub; a página tem um link para ela no **GitHub**. ## Cloudflare Os projetos da organização rodam nesta conta da Cloudflare. **Conectar uma conta** com um token, como [para você](https://docs.bohr.io/pt-br/getting-started/connect-cloudflare/), ou **Conectar outra conta**. Uma conta não pode ser desconectada enquanto projetos da organização rodam nela. ## Agente O provedor, a chave, o modelo e o esforço do agente em todos os projetos da organização. As mesmas opções das [configurações pessoais](https://docs.bohr.io/pt-br/agent/providers/): uma chave da API da Anthropic, um provedor compatível ou uma assinatura Claude. Salvar aplica a todos os projetos prontos da organização; remover desliga o agente em todos eles (os deploys do GitHub continuam funcionando). ## Assinatura (bohr.io Cloud) Cada organização tem a **própria** assinatura, de US$20/mês, paga por um dos admins com um cliente da organização na Stripe, que nunca se mistura com a assinatura pessoal do admin. Os membros não precisam de assinatura. Os admins assinam pela configuração da organização e a gerenciam (cartão, faturas, cancelamento) em **Gerenciar na Stripe**. Veja [Assinatura](https://docs.bohr.io/pt-br/billing/subscription/). ## Quando o app do GitHub é desinstalado Se alguém desinstala o App da bohr da organização no GitHub, a página diz *"O app do GitHub foi desinstalado"*: os projetos continuam no ar, mas não dá para criar novos nem sincronizar os membros. Clique em **Instalar o app de novo** para resolver. ## Zona de perigo: excluir a organização **Excluir organização** remove da bohr os projetos dela e tudo o que a bohr criou para eles. Digite o slug da organização para confirmar. - Os projetos da organização são excluídos (agentes, homologações, bots e rotas da bohr). - A assinatura da organização é cancelada, e as contas da Cloudflare e o agente são desconectados. - O app da bohr é desinstalado da organização no GitHub. **Os repositórios não são alterados.** - Os sites publicados na conta da Cloudflare da organização **continuam no ar**, a menos que você marque **Também apagar os sites publicados na conta da Cloudflare da organização**. --- # Sua conta e conexões > Perfil, idioma, formas de entrar e como desconectar o GitHub, o Telegram, a Cloudflare e o agente. Source: https://docs.bohr.io/pt-br/account/connections/ **Conta** (barra lateral) reúne o seu perfil e tudo o que está conectado à sua conta da bohr. ## Perfil e idioma - **Perfil**: o seu **Nome** e **E-mail**. - **Idioma**: o **Idioma da interface** (Português, English, Español). A escolha fica salva naquele navegador. - **Sair da conta** encerra a sessão neste navegador. ## Contas conectadas ### Formas de entrar Como você entra na bohr: **GitHub**, **E-mail** e **Telegram**. Sua conta precisa de pelo menos uma. - **Conectar login do GitHub** vincula uma conta do GitHub. - **Adicionar e-mail**: digite o endereço, clique em **Enviar código**, digite o código de 6 dígitos e clique em **Adicionar e-mail**. *"Este e-mail já pertence a outra conta da bohr."* quer dizer que ele já está em uso. - **Vincular o Telegram** (quando a instância tem um bot da plataforma): abre o bot; toque em **Iniciar**. A partir daí, os bots dos projetos reconhecem você. - **Remover** tira uma forma de entrar. A última não pode ser removida: *"Esta é a única forma de entrar na sua conta. Adicione outra antes de removê-la."* ### App do GitHub As contas do GitHub em que o app da bohr está instalado, com quantos projetos usam cada uma. **Desconectar** desinstala o app daquela conta, e a bohr deixa de acessar os repositórios dela. Os projetos que ainda usam a conta precisam ser excluídos antes; os repositórios não são alterados. ### Cloudflare As contas da Cloudflare em que os seus projetos são publicados. **Desconectar** apaga o token de API que a bohr guardava para aquela conta; os sites publicados nela continuam no ar. Os projetos que ainda usam a conta precisam ser excluídos antes. Apague também o próprio token no painel da Cloudflare (**My Profile → API Tokens**). ### Telegram **Desconectar** faz o bot da bohr deixar de reconhecer você. Os bots dos projetos continuam no Telegram. ### Agente O seu **Provedor** do modelo, o **Modelo** (ou *Padrão da bohr*) e o fim da sua **Chave**. **Configurar** abre [Provedores de modelo](https://docs.bohr.io/pt-br/agent/providers/). **Desconectar** apaga a chave do provedor e desliga o agente em todos os seus projetos; eles continuam publicando o que chega ao GitHub. ## Também nesta página - **Assinatura**: se a sua assinatura do bohr.io Cloud está ativa, e **Ver a assinatura**. Veja [Assinatura](https://docs.bohr.io/pt-br/billing/subscription/). - **Agente**: **Configurar o agente**. - **Tokens e a CLI**: **Gerenciar tokens**. Veja [Tokens](https://docs.bohr.io/pt-br/account/tokens/). - **Zona de perigo**: [excluir a sua conta](https://docs.bohr.io/pt-br/account/delete-account/). --- # Tokens > Crie, limite e revogue tokens para a CLI da bohr, scripts e agentes de IA. Source: https://docs.bohr.io/pt-br/account/tokens/ Um token deixa um script ou um agente de IA usar a bohr por você, com a [CLI da bohr](https://docs.bohr.io/pt-br/cli/install/): listar os seus projetos e publicar homologações (produção também, nos projetos que são seus; projetos na conta Cloudflare do dono, só quando são seus). Entregue o token na variável de ambiente `BOHR_TOKEN`. Gerencie os tokens em **Conta › Tokens** (**Gerenciar tokens**). ## Criar um token Em **Novo token**: | Campo | | | --- | --- | | **Nome** | Um que você reconheça, por exemplo "agente de deploy" ou "CI da loja". | | **Projetos** | **Todos os meus projetos, inclusive os que eu entrar depois**, ou **Só estes projetos** (escolha pelo menos um). | | **Expira** | **Em 30 dias**, **Em 90 dias**, **Em 365 dias** ou **Nunca**. | Clique em **Criar token**. O painel mostra o token **uma única vez**, com o jeito de usar: ```sh BOHR_TOKEN=bohr_… npx bohr deploy --json ``` Copie agora e guarde em lugar seguro: a bohr não mostra o token de novo, e quem o tiver pode publicar como você. A bohr guarda só um hash dele. ## O que um token pode fazer - Ele age como **você**, nos projetos de que você é membro (os projetos de uma organização, por meio da organização), limitado aos projetos que ele lista. - Homologações em qualquer um desses projetos; produção só nos projetos que são seus (ou cuja organização você administra). - Ele nunca carrega o papel de administrador da instância, mesmo que você o tenha. - Você pode ter até 50 tokens. ## Seus tokens **Seus tokens** lista cada token com os projetos dele (**Todos os seus projetos** ou **Projetos: …**), quando foi **Criado**, quando foi **usado** pela última vez (ou *nunca usado*) e quando expira (ou *não expira*). Tokens vencidos mostram **Expirado**. Cada computador em que você rodou `bohr login` tem um token próprio, marcado como **CLI** e com o nome "CLI on <computador>". O `bohr logout` revoga esse token. ## Revogar Clique em **Revogar** e confirme: scripts, agentes e computadores que usam o token param de funcionar na hora. Os deploys já publicados continuam no ar. --- # Excluir sua conta > Remova a sua conta da bohr e tudo o que a bohr criou para ela. Source: https://docs.bohr.io/pt-br/account/delete-account/ A **Zona de perigo**, no fim de **Conta**, exclui a sua conta. Não dá para desfazer. 1. Clique em **Excluir conta**. 2. Leia o que sai e o que fica. 3. Opcional: marque **Também apagar os sites publicados na minha conta Cloudflare**. 4. Digite `EXCLUIR` para confirmar (`DELETE` em inglês). ## O que sai - Todos os seus projetos: os Workers dos agentes e a hospedagem da bohr. - O app do GitHub é desinstalado das suas contas. - As conexões com a Cloudflare são removidas. - O vínculo com o Telegram é desfeito. - As configurações do agente são apagadas. - A assinatura do bohr.io Cloud é cancelada. ## O que fica - **Os repositórios no GitHub nunca são alterados.** - **Os bots dos projetos continuam no Telegram.** Apague-os no BotFather se quiser. - **Os sites publicados na sua conta da Cloudflare continuam no ar**, a menos que você tenha marcado a opção, que remove os Workers de produção dos sites nas contas da Cloudflare conectadas. ## Suas organizações - Uma organização em que você é o **único membro ativo** é excluída junto com a sua conta. - Numa organização com outros membros, os projetos que você criou, as conexões com a Cloudflare que você fez e a assinatura que você paga passam para outro membro ativo (um admin, quando houver). - Se você for o **último admin** de uma organização com outros membros, a bohr recusa: *"You are the last admin of … Make another member an admin first, or delete the organization."* Numa instância self-hosted, o único administrador não pode excluir a própria conta enquanto existirem outros usuários (*"You are the only admin. Make someone else an admin first."*). Quando algo não pôde ser removido, a página de entrada mostra *"Algumas coisas ficaram para trás e precisam ser removidas à mão"* com a lista. --- # Assinatura > A assinatura do bohr.io Cloud, o que ela inclui e como gerenciá-la. Source: https://docs.bohr.io/pt-br/billing/subscription/ **O bohr.io Cloud custa US$20 por mês** por conta pessoal ou organização. A bohr roda e mantém a instância para você (o painel, o bot do Telegram, o cofre de credenciais), e os seus projetos rodam na sua própria conta da Cloudflare. A cobrança é feita pela Stripe. Instâncias self-hosted não têm assinatura: *"Esta instância não cobra assinatura."* ## O que está incluído - A instância da bohr em [app.bohr.io](https://app.bohr.io), com todos os recursos: o agente, as homologações, as aprovações, as versões, os membros, as organizações, as variáveis, a proteção por senha, os domínios, a CLI e a GitHub Action. - O bot da plataforma no Telegram e a entrada por e-mail. ## O que não está incluído A infraestrutura é paga direto aos provedores: - **Cloudflare**: o plano Workers Paid (US$5/mês) na conta em que os seus projetos rodam, o tempo de container enquanto o agente trabalha e o que os seus sites consomem. - **O seu provedor do modelo**: os tokens do agente, ou a sua assinatura Claude. ## Assinar - Em **Primeiros passos**, na etapa **Assinatura**: clique em **Assinar**, pague na Stripe e volte. O painel confirma o pagamento (*"Pagamento recebido. Estamos confirmando a assinatura com a Stripe…"*). Se ela ainda não aparecer como ativa, aguarde um pouco e clique em **Verificar de novo**. - Ou em **Conta › Assinatura › Ver a assinatura › Assinar o bohr.io Cloud**. - Uma organização assina durante a configuração dela, com o pagamento feito por um dos admins. Veja [Configurações e cobrança da organização](https://docs.bohr.io/pt-br/organizations/settings-and-billing/#assinatura-bohrio-cloud). Criar projetos no bohr.io Cloud exige uma assinatura ativa. Códigos promocionais são aceitos no checkout. ## Gerenciar **Assinatura** (a partir de **Conta**) mostra a **Situação**, o **Plano** e a **Próxima cobrança** (ou **Válida até**, depois de cancelada). **Gerenciar na Stripe** abre o portal da Stripe para o cartão, as faturas e o cancelamento. | Situação | Significado | | --- | --- | | **Ativa** | Paga e em dia | | **Em período de teste** | Num período de teste | | **Pagamento atrasado** | Um pagamento falhou; os projetos continuam funcionando enquanto a Stripe tenta de novo | | **Cancelada**, **Expirada**, **Não paga**, **Pagamento incompleto**, **Pausada** | Não ativa: você não pode criar projetos | | **Vinda da versão anterior, em verificação** | Uma assinatura trazida da bohr v1 | ## Clientes da bohr v1 Clientes que pagavam pela bohr v1 mantêm **o preço do plano deles** (*Preço da versão anterior da bohr*). Os projetos deles ficam hospedados pela bohr até que eles os movam. Veja [Migrar da bohr v1](https://docs.bohr.io/pt-br/migrating-from-v1/overview/). --- # Visão geral da auto-hospedagem > Rode a sua própria instância da bohr na sua conta da Cloudflare, e quanto isso custa. Source: https://docs.bohr.io/pt-br/self-hosting/overview/ A bohr é open source (MIT). Uma **instância auto-hospedada** é o mesmo software do bohr.io Cloud, rodando na sua conta da Cloudflare: um Worker com a API, o onboarding (web e Telegram), o cofre de credenciais e o painel web, mais um banco de dados D1. Os projetos não rodam na instância. Cada um roda na conta da Cloudflare do seu dono, que a instância prepara com o token da API do dono. Instale uma instância para você, para a sua equipe ou para os seus clientes; ela tem usuários e projetos ilimitados e todos os recursos. ## O que cada pessoa precisa | Quem | Precisa de | | --- | --- | | Quem hospeda a instância | Uma conta da Cloudflare com Workers, D1 e Workflows (o plano gratuito basta para começar) e uma conta do GitHub para ser dona do app do GitHub da instância | | Cada usuário | Uma conta da Cloudflare no Workers Paid (o sandbox do agente é um Container), uma conta do GitHub e um provedor de modelo. O Telegram é opcional. | ## Custos | Conta | Paga por | | --- | --- | | A da instância | Workers, D1 e Workflows. Uma instância pequena cabe no plano gratuito. O Workers Paid (US$5/mês) só é necessário para o [container de login](https://docs.bohr.io/pt-br/self-hosting/optional-features/#um-container-de-login-dedicado) opcional. | | A Cloudflare de cada usuário | Workers Paid (US$5/mês), o sandbox enquanto o agente trabalha (um container `standard-1` custa centavos por hora e dorme quando ocioso) e o que o projeto usa em produção | | O provedor de modelo de cada usuário | Os tokens do agente. Todo pedido tem um orçamento (US$5 por padrão, definido por projeto). | ## Passos 1. [Faça o deploy da instância](https://docs.bohr.io/pt-br/self-hosting/deploy-instance/) com o botão Deploy to Cloudflare ou com o wrangler. 2. [Crie o app do GitHub dela](https://docs.bohr.io/pt-br/self-hosting/github-app/) em `/setup`. 3. Opcional: [o bot da plataforma, o login por e-mail e o container de login](https://docs.bohr.io/pt-br/self-hosting/optional-features/). 4. Entre: a primeira pessoa vira o [administrador](https://docs.bohr.io/pt-br/self-hosting/administration/). 5. Os usuários passam pelo [Primeiros passos](https://docs.bohr.io/pt-br/getting-started/sign-in/) como no bohr.io Cloud, sem o passo da assinatura. ## Confiança A instância guarda os tokens da Cloudflare dos usuários e a chave privada do app do GitHub dela, criptografados com uma chave mestra que fica com você. Os usuários precisam confiar em quem hospeda a instância. Todo uso de uma credencial guardada fica registrado no log de auditoria da instância. Veja [Modelo de segurança](https://docs.bohr.io/pt-br/reference/security/). --- # Fazer o deploy da instância > Instale uma instância da bohr com o botão Deploy to Cloudflare ou com o wrangler. Source: https://docs.bohr.io/pt-br/self-hosting/deploy-instance/ ## Com o botão Deploy to Cloudflare [![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/bohr-io/bohr) A Cloudflare copia o repositório para a sua conta do GitHub, cria o banco de dados D1 e pede dois secrets: | Secret | Valor | | --- | --- | | `ADMIN_TOKEN` | Uma string aleatória de pelo menos 32 caracteres (`openssl rand -hex 32`). Protege o `/setup` e a API de administração. | | `ENCRYPTION_KEY` | 32 bytes aleatórios em base64 (`openssl rand -base64 32`). A chave mestra do cofre. **Guarde uma cópia**: sem ela, os tokens da Cloudflare e as chaves do app do GitHub guardados não podem ser lidos. | Deixe o `APP_URL` vazio, a menos que você já saiba o endereço final da instância. ## Com o wrangler ```sh git clone https://github.com/bohr-io/bohr && cd bohr pnpm install npx wrangler login npx wrangler deploy npx wrangler secret put ADMIN_TOKEN # openssl rand -hex 32 npx wrangler secret put ENCRYPTION_KEY # openssl rand -base64 32 ``` Você precisa do Node.js 22 e do pnpm 10. O `wrangler deploy` roda o build definido no `wrangler.jsonc` (ele empacota o Worker de cada projeto dentro da instância e faz o build do painel web), cria o banco de dados D1 no primeiro deploy e publica o Worker, chamado `bohr`. A própria instância aplica as migrations do banco de dados na primeira requisição. Para aplicá-las manualmente: ```sh npx wrangler d1 migrations apply DB --remote ``` ## O endereço A instância responde em `https://bohr..workers.dev`, ou num domínio próprio que você adicionar ao Worker. **O endereço que você usa para abrir o `/setup` vira a URL da instância** (a menos que o `APP_URL` esteja definido), e ele entra nas URLs de callback do app do GitHub: use o seu domínio final desde o começo. Próximo passo: [Criar o app do GitHub](https://docs.bohr.io/pt-br/self-hosting/github-app/). ## Conferir ```sh curl https:///health ``` Abrir a instância antes do `/setup` mostra *"Esta instância ainda não foi configurada"* na página de login, com um link para a configuração. --- # O app do GitHub da instância > Crie o app do GitHub que a sua instância usa, e as permissões que ele pede. Source: https://docs.bohr.io/pt-br/self-hosting/github-app/ Toda instância tem o próprio app do GitHub, criado a partir de um manifest em `/setup`. A bohr o usa para fazer o login das pessoas com o GitHub, ler repositórios, fazer push do trabalho do agente, abrir e fazer merge de pull requests, e escrever o workflow de deploy. ## Criar o App 1. Abra `https:///setup`. 2. Preencha: - **Admin token**: o secret `ADMIN_TOKEN`. - **App name**: até 34 caracteres, único no GitHub (padrão `bohr `). - **GitHub organization (optional)**: para criar o App como propriedade de uma organização em vez da sua conta. - **Other people can install it**: deixe marcado se outros usuários vão trazer os próprios repositórios. 3. Clique em **Create the GitHub App**. O GitHub mostra as permissões; confirme. O GitHub volta para a instância, que guarda as credenciais do App no cofre. Depois disso, o `/setup` mostra o App e um link para instalá-lo. Para usar outro App mais tarde, apague a configuração `github_app` no banco de dados da instância e abra o `/setup` de novo. ## Permissões | Permissão | Por quê | | --- | --- | | Contents: write | O agente faz push no branch `homolog`; as aprovações fazem merge para a produção | | Pull requests: write | As aprovações abrem pull requests e fazem merge deles; os rollbacks abrem pull requests de revert | | Workflows: write | O Worker do projeto escreve o workflow de deploy (o token do próprio sandbox nunca recebe essa permissão) | | Secrets: write | Variáveis do build dos projetos que a bohr hospeda, e a remoção de secrets do Actions que versões antigas escreveram. O token da Cloudflare dos projetos em conta própria nunca é guardado no GitHub. | | Actions: read | Avisa quando o deploy de produção termina; a página Builds | | Metadata: read | Exigida pelo GitHub | | Organization › Members: read | As organizações na bohr espelham os membros da organização no GitHub | | Administration: write | Cria repositórios a partir de modelos (novos projetos a partir de um modelo, só com a autorização do próprio usuário) | Eventos: | Evento | Por quê | | --- | --- | | **Organization** | Membros adicionados a uma organização do GitHub ou removidos dela: os membros da organização na bohr acompanham | | **Push**, **Pull request** | Assinados desde a primeira versão; a bohr confirma o recebimento e não faz nada com eles hoje (os deploys rodam pelo workflow do repositório) | Os eventos **Installation** chegam a todo App sem precisar de assinatura: a bohr registra cada instalação e liga a instalação de uma organização do GitHub à organização dela na bohr. O webhook vai para `https:///api/github/webhook`; numa instância local (`http://localhost`), o webhook fica desligado. ## Apps criados por versões antigas - **Organizações** precisam da permissão de organização **Members** (somente leitura) e do evento **Organization**. Adicione-os nas configurações do App no GitHub (*Permissions & events*); depois, cada organização do GitHub aceita a nova permissão. Até isso acontecer, a bohr só adiciona quem instalou o App, e o painel pede a permissão. - **Modelos** precisam da permissão de repositório **Administration** (leitura e escrita). Cada conta que instalou o App a aceita uma vez. Até lá, o GitHub se recusa a criar o repositório, e o painel avisa. ## Usar um App existente Em vez do `/setup`, uma instância pode ler o App a partir de secrets: `GITHUB_APP_ID`, `GITHUB_APP_SLUG`, `GITHUB_APP_PRIVATE_KEY`, `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET` e `GITHUB_WEBHOOK_SECRET`. Veja [Configuração](https://docs.bohr.io/pt-br/self-hosting/configuration/). --- # Referência de configuração > Os secrets, as variáveis e os bindings que uma instância auto-hospedada da bohr lê. Source: https://docs.bohr.io/pt-br/self-hosting/configuration/ Uma instância auto-hospedada é configurada pelo `wrangler.jsonc` da raiz do repositório e por secrets do Worker (`npx wrangler secret put `). Para desenvolvimento local, coloque os secrets em `.dev.vars` (o git o ignora; o `.dev.vars.example` lista todos). ## Secrets | Secret | Obrigatório | Descrição | | --- | --- | --- | | `ADMIN_TOKEN` | Sim | Protege o `/setup` e a API de administração. Pelo menos 32 caracteres aleatórios: `openssl rand -hex 32`. | | `ENCRYPTION_KEY` | Sim | A chave mestra do cofre: 32 bytes aleatórios em base64 (`openssl rand -base64 32`). Aceita várias chaves durante a [rotação](https://docs.bohr.io/pt-br/self-hosting/updates-and-backups/#rotacionar-a-chave-mestra): `k2:,k1:`, a atual primeiro. Guarde uma cópia. | | `TELEGRAM_BOT_TOKEN` | Não | O [bot da plataforma](https://docs.bohr.io/pt-br/self-hosting/optional-features/#o-bot-da-plataforma), para o onboarding pelo Telegram e para vincular contas do Telegram. | | `GITHUB_APP_ID`, `GITHUB_APP_SLUG`, `GITHUB_APP_PRIVATE_KEY`, `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `GITHUB_WEBHOOK_SECRET` | Não | Um app do GitHub existente, em vez de criar um em `/setup`. | ## Variáveis (`vars`) | Variável | Padrão | Descrição | | --- | --- | --- | | `APP_URL` | vazio | A URL pública da instância. Deixe vazio para usar o endereço com que você abre o `/setup`. | | `OIDC_AUDIENCE` | `bohr.io` | A audience que a instância espera nos tokens OIDC do GitHub vindos dos workflows de deploy. Mantenha `bohr.io`: a action de deploy pede essa audience. | | `BOHR_TELEMETRY` | não definida | `off` (ou `0`, `false`) mantém a [telemetria](https://docs.bohr.io/pt-br/self-hosting/telemetry/) desligada, diga o painel o que disser. | | `EMAIL_FROM` | `bohr >` | O remetente dos códigos de login, por exemplo `bohr `. Só com o binding `EMAIL`. | | `RUNTIME_IMAGE` | `ghcr.io/bohr-io/agent:` | A [imagem do agente](https://docs.bohr.io/pt-br/self-hosting/optional-features/#sua-própria-imagem-do-agente) copiada para cada conta que roda projetos. Também pode ser um secret. | ## Bindings | Binding | Tipo | Descrição | | --- | --- | --- | | `DB` | D1 | O banco de dados da instância (`bohr`). Criado pelo wrangler no primeiro deploy; migrations em `apps/instance/migrations`. | | `PROVISION` | Workflow (`bohr-provision`) | Prepara o runtime de cada projeto na conta do dono. | | `ASSETS` | Static assets | O painel web, com build em `apps/web/dist`. | | `EMAIL` | Send email | Opcional: [login com um código por e-mail](https://docs.bohr.io/pt-br/self-hosting/optional-features/#login-com-um-código-por-e-mail). | | `CLAUDE_LOGIN` | Durable Object + container | Opcional: o [container de login dedicado](https://docs.bohr.io/pt-br/self-hosting/optional-features/#um-container-de-login-dedicado). | ## Cron `17 * * * *` (de hora em hora): limpeza (sessões de deploy vencidas e códigos de uso único) e, quando ligado, o ping diário de telemetria. ## Rotas que o Worker responde primeiro `/api/*`, `/auth/*`, `/setup`, `/setup/*`, `/.well-known/*` e `/health`. Todo o resto é o painel web (uma single-page app). :::note O bohr.io Cloud faz o deploy do `apps/instance/wrangler.jsonc`, com a hospedagem dos projetos migrados da v1 e a cobrança ligadas. As instâncias auto-hospedadas fazem o deploy do `wrangler.jsonc` da raiz, que deixa essas partes desligadas; você não precisa de nenhuma das configurações delas. ::: --- # Recursos opcionais > O bot da plataforma no Telegram, o login por e-mail, o container de login dedicado e a sua própria imagem do agente. Source: https://docs.bohr.io/pt-br/self-hosting/optional-features/ ## O bot da plataforma Os usuários podem fazer o onboarding pela web. Um **bot da plataforma** também permite fazê-lo pelo Telegram (`/new`, `/status`, `/retry`), vincular a conta do Telegram à conta na bohr e criar o bot de cada projeto com um toque. 1. Crie um bot com o [@BotFather](https://t.me/BotFather). Nas configurações dele, permita que ele **gerencie outros bots** (managed bots da Bot API): é isso que deixa ele criar o bot de cada projeto. Sem isso, os usuários colam um token do BotFather. 2. Guarde o token dele: ```sh npx wrangler secret put TELEGRAM_BOT_TOKEN ``` 3. Aponte o bot para a instância: ```sh curl -X POST https:///api/admin/platform-bot \ -H "Authorization: Bearer " ``` Sem um bot da plataforma, **Vincular o Telegram** diz *"Esta instância não tem um bot do Telegram configurado."*; os bots dos projetos continuam funcionando com tokens do BotFather. ## Login com um código por e-mail Os usuários podem entrar com o GitHub, ou com um código de uso único enviado pelo [Cloudflare Email Service](https://developers.cloudflare.com/email-service/). 1. Ative o Email Sending para um domínio seu: ```sh npx wrangler email sending enable mail.example.com ``` 2. No `wrangler.jsonc`, descomente o binding `send_email` e defina o `EMAIL_FROM`: ```jsonc "send_email": [{ "name": "EMAIL", "allowed_sender_addresses": ["login@mail.example.com"] }], "vars": { "EMAIL_FROM": "bohr " } ``` 3. Faça o deploy de novo. Sem o binding, a página de login só oferece o GitHub. ## Um container de login dedicado Conectar uma [assinatura Claude](https://docs.bohr.io/pt-br/agent/providers/#assinatura-claude-promax) roda o `claude setup-token` da CLI oficial. Sem mais nada, ele roda no container de um dos projetos do dono: o dono precisa de um projeto com o agente pronto, e um container dormindo precisa iniciar antes. Um container dedicado pequeno, ligado à instância, elimina as duas coisas: a conexão funciona antes de existir qualquer projeto e inicia em segundos. Ele não recebe nenhum secret; o token que ele devolve vai para a instância, nunca para o navegador. Cada usuário ou organização que faz login ganha o próprio container, que para 10 minutos depois do último uso. Ele precisa do Workers Paid na conta da instância e da imagem no registry dessa conta: 1. Crie um token da API com **Containers: Edit** na conta da instância e copie a imagem (por padrão, a versão em `runtime/claude-login/package.json`; passe outra imagem como argumento): ```sh CLOUDFLARE_API_TOKEN= CLOUDFLARE_ACCOUNT_ID= node apps/instance/scripts/copy-login-image.mjs ``` 2. No `wrangler.jsonc`, descomente `durable_objects`, `migrations` e `containers` em *"Optional: a small dedicated container"*, com o ID da sua conta na imagem (o script mostra a linha), e faça o deploy de novo. Copie a nova imagem e atualize a tag dela quando atualizar a bohr. ## Sua própria imagem do agente O sandbox de cada projeto roda a imagem gerada a partir de `runtime/agent`. No primeiro projeto de uma conta, a instância copia a imagem publicada (`ghcr.io/bohr-io/agent:`) para o registry da Cloudflare dessa conta. Para usar o seu próprio build: ```sh pnpm --filter @bohr/agent build docker build --platform linux/amd64 -f runtime/agent/Dockerfile -t ghcr.io//bohr-agent: . docker push ghcr.io//bohr-agent: npx wrangler secret put RUNTIME_IMAGE # ghcr.io//bohr-agent: ``` A imagem precisa ser pública (recomendamos o GitHub Container Registry ou o Google Artifact Registry; o Docker Hub limita pulls anônimos). Os Cloudflare Containers rodam imagens `linux/amd64`. --- # Administração > Os administradores da instância, a área de Administração do painel e a API de administração. Source: https://docs.bohr.io/pt-br/self-hosting/administration/ ## Administradores A **primeira pessoa que entra** numa instância nova vira a administradora dela. Os administradores: - veem a área **Administração** no painel; - têm acesso de dono a todos os projetos e organizações (o projeto mostra *"Você está vendo este projeto como administrador"*), e as mudanças deles ficam registradas como de administrador no log de auditoria; - atualizam os runtimes dos projetos e escolhem se a instância envia [telemetria](https://docs.bohr.io/pt-br/self-hosting/telemetry/). Os tokens da CLI nunca carregam o papel de administrador. ## A área de Administração | Página | | | --- | --- | | **Visão geral** | Usuários, projetos e assinaturas ativas, e **Runtimes**: **Atualizar runtimes** leva o Worker de cada projeto à versão desta instância | | **Usuários** | Busca por nome, e-mail ou login. A página de um usuário lista os projetos e as organizações dele, **Tornar admin** / **Remover admin** e a exclusão da conta | | **Projetos** | Busca por nome, repositório ou dono; status, hospedagem e runtime de cada um | | **Organizações** | Busca por nome ou login no GitHub; membros, projetos e assinatura | | **Telemetria** | A chave de opt-in e exatamente o que seria enviado | A instância precisa de pelo menos um administrador: *"A instância precisa de pelo menos um admin."* ## A API de administração Chamadas com `Authorization: Bearer `: ```sh # Torna alguém administrador (ou "user" para remover); identifique a pessoa por email, githubLogin ou userId curl -X POST https:///api/admin/users/role \ -H "Authorization: Bearer " -H "Content-Type: application/json" \ -d '{"email":"you@example.com","role":"admin"}' # Leva o runtime de todos os projetos à versão desta instância curl -X POST https:///api/admin/runtimes/update -H "Authorization: Bearer " # Aponta o bot da plataforma para a instância (depois de definir o TELEGRAM_BOT_TOKEN) curl -X POST https:///api/admin/platform-bot -H "Authorization: Bearer " # Recriptografa todas as credenciais guardadas com a chave mestra atual (depois de uma rotação de chave) curl -X POST https:///api/admin/vault/rewrap -H "Authorization: Bearer " ``` Mantenha o `ADMIN_TOKEN` em segredo: ele abre o `/setup` e estas chamadas. --- # Atualizações e backups > Atualize a sua instância e os runtimes dos projetos, faça backup do banco de dados e rotacione a chave mestra. Source: https://docs.bohr.io/pt-br/self-hosting/updates-and-backups/ ## Atualizar a instância Traga as mudanças do upstream para a sua cópia do repositório e faça o deploy de novo: ```sh git pull upstream main pnpm install npx wrangler deploy ``` Se você usou o botão Deploy to Cloudflare, faça push das mudanças no branch de que o Workers Builds faz deploy. As novas migrations do banco de dados rodam na primeira requisição depois do deploy. ## Atualizar os runtimes dos projetos O Worker de cada projeto (o agente, o bot e a homologação) roda a versão com que foi criado. Depois de atualizar a instância, leve todos para a nova versão: - **Administração › Visão geral › Atualizar runtimes**, ou - a API de administração: ```sh curl -X POST https:///api/admin/runtimes/update -H "Authorization: Bearer " ``` Enquanto um runtime é atualizado, a versão anterior continua atendendo; uma atualização que falha o deixa rodando como estava. Se você usa o [container de login dedicado](https://docs.bohr.io/pt-br/self-hosting/optional-features/#um-container-de-login-dedicado), copie a nova imagem dele também. ## Backup O que guardar com segurança: | O quê | Onde | Como | | --- | --- | --- | | `ENCRYPTION_KEY` | Um secret do Worker | Guarde uma cópia fora da Cloudflare (num gerenciador de senhas). Sem ela, os tokens da Cloudflare, as chaves do app do GitHub e as chaves do agente guardados não podem ser lidos. | | `ADMIN_TOKEN` | Um secret do Worker | Guarde uma cópia; você também pode substituí-lo com `wrangler secret put`. | | O banco de dados da instância | D1 `bohr` | `npx wrangler d1 export bohr --remote --output bohr-backup.sql`. O Time Travel do D1 também pode restaurá-lo para um momento recente. | O banco de dados da instância guarda usuários, sessões, projetos, organizações, conexões (criptografadas) e configurações. Os membros, o chat e as publicações de cada projeto ficam no Durable Object do projeto, na conta da Cloudflare do dono; o código fica no GitHub. ## Rotacionar a chave mestra O `ENCRYPTION_KEY` aceita várias chaves, a atual primeiro: `k2:,k1:`. Valores novos são criptografados com a `k2`; os antigos continuam abrindo com a `k1`. Para passar tudo para a `k2` e depois descartar a `k1`: ```sh npx wrangler secret put ENCRYPTION_KEY # k2:,k1: curl -X POST https:///api/admin/vault/rewrap -H "Authorization: Bearer " npx wrangler secret put ENCRYPTION_KEY # k2: ``` --- # Telemetria > A telemetria anônima e opcional das instâncias auto-hospedadas, o que ela envia e como mantê-la desligada. Source: https://docs.bohr.io/pt-br/self-hosting/telemetry/ As instâncias auto-hospedadas podem enviar telemetria anônima de uso. Ela vem **desligada por padrão**: um administrador da instância a liga em **Administração › Telemetria**, que mostra exatamente o que é enviado. ## O que é enviado ```json { "instanceId": "3f1c2a9e-8b7d-4c1e-9a2f-6d5e4b3a2c1d", "version": "2.0.0", "projects": 12 } ``` - `instanceId`: um ID aleatório criado para isso; ele não identifica nada além da instância. - `version`: a versão da instância. - `projects`: quantos projetos ela tem. Nada mais: nenhum nome, e-mail, URL, repositório ou dado derivado de IP é guardado. ## Quando e para onde Uma vez por dia, a partir do cron de hora em hora da instância, como um `POST` para `https://app.bohr.io/api/telemetry`. O primeiro ping sai assim que você liga, então **Último envio** mostra que funcionou. ## Por quê Para saber quantas instâncias e versões existem por aí, e assim a bohr saber com o que precisa manter compatibilidade. ## Desligar - Desligue **Enviar telemetria anônima** em **Administração › Telemetria**, ou - defina a variável `BOHR_TELEMETRY=off` no `wrangler.jsonc` e faça o deploy. Ela mantém a telemetria desligada, diga o painel o que disser; o painel então mostra *"A telemetria está desligada na configuração desta instância (BOHR_TELEMETRY=off)"*. O bohr.io Cloud nunca envia telemetria; ele só recebe esses pings. --- # Projetos da bohr v1 na bohr v2 > O que aconteceu com os projetos da bohr v1, e o que você pode fazer agora. Source: https://docs.bohr.io/pt-br/migrating-from-v1/overview/ A bohr v2 substitui a bohr v1. Os projetos dos clientes pagantes da bohr v1 foram movidos para a bohr v2 por nós; você não precisou fazer nada. ## O que aconteceu com o seu projeto - **Ele roda na bohr v2**, hospedado pela bohr na conta da Cloudflare dela, como era na v1. No painel, a hospedagem dele mostra **Hospedado pela bohr**. - **Mesmos endereços, sem mudanças de DNS.** Os seus domínios próprios e os seus endereços `bohr.io` (`-.bohr.io`) continuam funcionando. - **O seu repositório mantém o workflow.** O workflow da bohr v1 (`.github/workflows/bohr.yml`) continua rodando a cada push, e agora faz deploy na bohr v2. A bohr não escreveu nada no seu repositório: nenhum workflow novo, nenhum arquivo, nenhum secret do Actions. - **Mesmo preço.** O seu plano mantém o preço que você pagava na v1. - **As suas configurações vieram junto**: variáveis de ambiente (como [variáveis do build](https://docs.bohr.io/pt-br/projects/variables/#variáveis-do-build) e [variáveis do site](https://docs.bohr.io/pt-br/projects/variables/#variáveis-do-site)), proteção por senha e domínios. Entre em [app.bohr.io](https://app.bohr.io) com a mesma conta do GitHub para ver os seus projetos. ## O que você pode fazer agora | | | | --- | --- | | **Deixar como está** | Faça push como antes; cada branch continua ganhando o próprio endereço de homologação. Veja [O que muda](https://docs.bohr.io/pt-br/migrating-from-v1/what-changes/). | | **Ativar o agente** | Mude o site conversando, com homologações e aprovações. No projeto, clique em **Ativar o agente** (precisa de uma assinatura ativa e de um [provedor de modelo](https://docs.bohr.io/pt-br/agent/providers/)). | | **Mover para a sua própria conta da Cloudflare** | Onde rodam os projetos da bohr v2. Veja [Mover para a sua conta da Cloudflare](https://docs.bohr.io/pt-br/migrating-from-v1/move-to-your-cloudflare/). | | **Fazer deploy pelo terminal ou por um agente de IA** | O `bohr deploy` publica projetos que a bohr hospeda. Veja [a CLI](https://docs.bohr.io/pt-br/cli/deploy/). | Dúvidas: [Discord](https://discord.com/invite/p3hhfGg2Uy) ou [contact@bohr.io](mailto:contact@bohr.io). Veja também as [Perguntas frequentes](https://docs.bohr.io/pt-br/migrating-from-v1/faq/). --- # O que muda para um projeto da v1 > Como um projeto migrado faz build, deploy e é servido enquanto a bohr o hospeda. Source: https://docs.bohr.io/pt-br/migrating-from-v1/what-changes/ ## Os deploys continuam funcionando O workflow da v1 do seu repositório roda o `bohr-io/action` a cada push, como antes. Essa action agora pergunta à bohr v2 como fazer o build do projeto (o **plano de build** dele: a versão do Node.js, os comandos de install e de build e os arquivos gerados de que a bohr v2 precisa), faz o build e o deploy com o [`bohr-io/deploy-action`](https://docs.bohr.io/pt-br/github-action/reference/#modo-plano-de-build). O build plan fica na bohr, não no seu repositório. - **Cada branch que recebe push** ganha deploy no próprio endereço: `--.bohr.io`. O branch de produção fica com `-.bohr.io` e os seus domínios próprios. - As **variáveis do build** são entregues ao build quando ele roda; gerencie-as em **Configurações › Variáveis de ambiente**. Pull requests nunca as recebem. - **Os arquivos estáticos são publicados como a v1 publicava**: os arquivos que a v1 deixava de fora (como `node_modules/`, `.github/`, `package.json`, lockfiles e arquivos `.env`) continuam de fora, e arquivos de 24 MiB ou mais são pulados com um aviso, em vez de fazer o deploy falhar. ## O que a hospedagem suporta Os projetos que a bohr hospeda são Workers com static assets na conta da bohr: - Static assets, `vars` e secrets ([variáveis do site](https://docs.bohr.io/pt-br/projects/variables/)). Outros bindings (D1, KV, R2, Durable Objects…) e cron triggers não estão disponíveis enquanto a bohr hospeda o projeto; [mova-o](https://docs.bohr.io/pt-br/migrating-from-v1/move-to-your-cloudflare/) para usá-los. - A [proteção por senha](https://docs.bohr.io/pt-br/projects/password-protection/) é aplicada pela borda da bohr. - Os domínios continuam como eram na v1. Para mudá-los, mova o projeto para a sua conta. ## O painel - **Configurações › Hospedagem** mostra **Hospedado pela bohr** e a mudança. - **Configurações › Domínios** lista os seus domínios como **No ar** ou **Pendente** (*Pendente* enquanto a bohr v1 ainda serve um endereço). - **Builds** mostra as execuções do seu workflow. - Sem o agente, o projeto mostra **Só deploys**. **Ativar o agente** adiciona o agente, a homologação e as aprovações; o agente então também roda na conta da bohr, até você mover o projeto. ## A CLI A CLI da bohr v2 é a `bohr@2`. O seu workflow da v1 não precisa dela. Localmente: - `bohr deploy` publica uma homologação do branch atual; `bohr deploy --prod` publica a produção (só donos). Veja [bohr deploy](https://docs.bohr.io/pt-br/cli/deploy/). - Enquanto a bohr v1 ainda serve o seu endereço de produção, os deploys de produção vêm do seu workflow (`production_on_v1`); as homologações funcionam. - Os comandos da v1 (`bohr dev`) e as opções da v1 (`--no-install`, `--show-install`, `--show-build`) não existem mais. - Num repositório que ainda roda só na bohr v1, a CLI repassa o comando para a CLI da bohr v1, que faz o deploy como sempre fez. --- # Mover para a sua conta da Cloudflare > Mova um projeto que a bohr hospeda para a sua própria conta da Cloudflare, com os secrets e os domínios dele. Source: https://docs.bohr.io/pt-br/migrating-from-v1/move-to-your-cloudflare/ Os projetos da bohr v2 rodam na conta da Cloudflare do dono. Um projeto migrado da v1 pode ir para lá quando você quiser: você ganha todos os recursos da Cloudflare (D1, KV, R2, Durable Objects, cron triggers…) e controle total dos seus domínios. ## Antes de começar - Uma conta da Cloudflare no **Workers Paid**, conectada à bohr (ou conecte uma durante a mudança). Veja [Conectar a Cloudflare](https://docs.bohr.io/pt-br/getting-started/connect-cloudflare/). - Para cada domínio próprio que deve ir sem ficar fora do ar, a **zona dele nessa conta da Cloudflare** (nameservers apontando para a Cloudflare). - Só o dono do projeto (ou um admin da organização dele) pode movê-lo. :::caution[Ainda não é automático para todos os projetos] A mudança automática funciona para repositórios cujo workflow de deploy foi gerado pela migração. Repositórios que ainda rodam o workflow da bohr v1 (`bohr.yml` com `bohr-io/action`) ainda não podem ser movidos automaticamente: o painel diz *"Não foi possível preparar a mudança automaticamente."* Veja [abaixo](#quando-a-mudança-não-pode-ser-preparada-automaticamente). ::: ## Como funciona 1. A bohr abre um pull request no seu repositório que muda o deploy para a sua conta da Cloudflare. 2. Depois do merge, o GitHub Actions publica o site na sua conta, e a bohr copia os secrets e move os seus domínios. 3. Os endereços bohr.io passam a redirecionar para o novo endereço do site. O deploy pega o token da Cloudflare na bohr na hora da execução, nunca no repositório. ## Passo a passo 1. Abra **Configurações › Hospedagem** do projeto. 2. Em **Conta da Cloudflare de destino**, escolha uma conta, ou **Conectar outra conta**. 3. Clique em **Preparar a mudança** e confirme. A bohr abre um pull request (branch `bohr/move-to-cloudflare`) que troca o workflow de deploy por um `wrangler deploy` para a sua conta, no branch de produção, e escreve as suas variáveis de produção comuns (não secretas) no `wrangler.jsonc`. O site só muda depois do merge. 4. Revise e faça o merge do pull request no GitHub (**Abrir #N no GitHub**). 5. Espere o deploy do GitHub Actions terminar. 6. Volte e clique em **Concluir a mudança**. **Concluir a mudança** confere o merge e o novo Worker, depois copia os secrets para ele, liga os seus domínios próprios cujas zonas estão na sua conta e aponta os endereços bohr.io para o novo lugar. Se aparecer *"Ainda não dá para concluir"*, confira se o pull request foi mergeado e se o deploy terminou, e tente de novo. ## Os endereços depois da mudança | Situação | Significado | | --- | --- | | **Na sua conta** | O domínio agora aponta para o Worker na sua conta | | **Redireciona** | Os endereços bohr.io redirecionam (301) para o novo endereço do site | | **Pendente** | A zona do domínio ainda não está na sua conta. Adicione-a, aponte os nameservers para a Cloudflare e clique em **Concluir a mudança** de novo. Até lá, o domínio continua mostrando a última versão publicada pela bohr. | | **Desativado** | Os endereços de homologação dos branches não recebem mais deploy: na sua conta, as homologações vêm do agente | Quando não há nada pendente: *"Pronto! O projeto agora roda na sua conta da Cloudflare."* A partir daí, ele é um projeto comum da bohr v2: [domínios](https://docs.bohr.io/pt-br/projects/domains/), [variáveis](https://docs.bohr.io/pt-br/projects/variables/) e o [workflow de deploy](https://docs.bohr.io/pt-br/deploys/deploy-workflow/) funcionam como em qualquer projeto na sua conta. Se o agente estava ligado, ele continua funcionando: o sandbox fica onde foi criado e, daqui em diante, faz deploy na sua conta. ## Quando a mudança não pode ser preparada automaticamente Alguns repositórios não podem ser movidos automaticamente, por exemplo quando o workflow de deploy não é o que a migração gerou, ou quando o repositório ainda roda o workflow da bohr v1 com um build plan. O painel então diz *"Não foi possível preparar a mudança automaticamente."* Fale com a gente no [Discord](https://discord.com/invite/p3hhfGg2Uy) ou em [contact@bohr.io](mailto:contact@bohr.io): ajudamos você a mudar a etapa de deploy manualmente. --- # Perguntas frequentes sobre a migração > Dúvidas comuns dos clientes da bohr v1. Source: https://docs.bohr.io/pt-br/migrating-from-v1/faq/ ### Preciso fazer alguma coisa? Não. O seu projeto foi movido para a bohr v2 por nós e continua fazendo deploy a partir do workflow do seu repositório. Movê-lo para a sua própria conta da Cloudflare e ativar o agente são opcionais. ### O meu preço mudou? Não. Os clientes que pagavam pela bohr v1 mantêm o preço do plano. A página da assinatura mostra *Preço da versão anterior da bohr*. ### Os meus domínios ou o DNS mudaram? Não. Os seus domínios próprios e endereços `bohr.io` continuam funcionando, sem mudanças de DNS. Se você [mover o projeto](https://docs.bohr.io/pt-br/migrating-from-v1/move-to-your-cloudflare/), cada domínio vai junto quando a zona dele estiver na sua conta da Cloudflare. ### A bohr mudou o meu repositório? Não. A migração não escreveu nada no seu repositório: nenhum workflow, nenhum arquivo, nenhum secret. A mudança para a sua própria conta, se você iniciá-la, abre um pull request que você revisa e faz o merge. ### O meu workflow ainda diz `bohr-io/action@main`. Está certo? Sim. Essa action agora faz o build e o deploy do seu projeto na bohr v2. Deixe como está enquanto a bohr hospeda o projeto. ### Onde estão as minhas variáveis de ambiente? Em **Configurações › Variáveis de ambiente**: variáveis do build para o build do GitHub Actions, e variáveis do site para o site em execução. Os valores secretos ficam ocultos. ### As homologações por branch ainda funcionam? Sim, enquanto a bohr hospeda o projeto: cada branch que recebe push ganha `--.bohr.io`. Depois da mudança para a sua conta, as homologações passam a vir do agente (o branch `homolog`). ### Posso usar KV, D1, R2 ou cron triggers? Não enquanto a bohr hospeda o projeto: os projetos hospedados suportam static assets, `vars` e secrets. Mova o projeto para a sua conta da Cloudflare para usar qualquer binding da Cloudflare. ### O `npx bohr deploy` parou de funcionar no meu workflow da v1 ou no meu terminal. A CLI da bohr v2 não faz deploy de projetos da bohr v1 nem aceita opções da v1. O seu workflow da v1 não precisa dela: ele faz deploy pelo `bohr-io/action`. Localmente, use o `bohr deploy` da bohr v2 ([documentação](https://docs.bohr.io/pt-br/cli/deploy/)). ### Um arquivo maior que 24 MiB sumiu do meu site. A bohr v1 nunca publicou arquivos de 24 MiB ou mais, e os projetos migrados mantêm essa regra. O limite da própria Cloudflare é de 25 MiB por arquivo. Sirva arquivos grandes a partir de um armazenamento como o R2. ### Com quem eu falo? [Discord](https://discord.com/invite/p3hhfGg2Uy) ou [contact@bohr.io](mailto:contact@bohr.io). --- # Glossário > As palavras que a bohr usa, em inglês e no painel em português. Source: https://docs.bohr.io/pt-br/reference/glossary/ | Termo | Em inglês | Significado | | --- | --- | --- | | **Instância** | Instance | O plano de controle da bohr: o painel, a API e o cofre de credenciais. O bohr.io Cloud é uma; você pode [hospedar a sua](https://docs.bohr.io/pt-br/self-hosting/overview/). | | **Projeto** | Project | Um repositório do GitHub, o site de produção dele e o agente dele. | | **Worker do projeto** | Project Worker | O Worker que a bohr cria na conta da Cloudflare do dono para cada projeto: a fila de pedidos, os membros, o chat, o bot do Telegram e o sandbox do agente. Não é o seu site. | | **Sandbox** | Sandbox | O Cloudflare Container onde o agente trabalha numa cópia do repositório e roda a homologação. Ele dorme quando está ocioso. | | **Agente** | Agent | A IA que muda o seu código a partir de uma conversa. | | **Pedido** | Request | Uma coisa que um membro pediu ao agente. Os pedidos rodam um de cada vez. | | **Homologação** | Preview | O site rodando a partir do branch `homolog`, com mudanças esperando uma decisão. | | **`homolog`** | `homolog` | O branch em que o agente faz commit. | | **Versão** | Version | Cada conjunto de mudanças que o agente enviou para a homologação (versão 1, 2…), e cada publicação em **Versões**. | | **Aprovar e publicar** | Approve and publish | Fazer o merge da homologação no branch de produção, o que faz o deploy da produção. | | **Descartar** | Discard | Voltar a homologação para a produção, descartando as mudanças dela. | | **Publicação** | Release | Uma aprovação ou um rollback mergeado, com deploy feito pelo GitHub Actions. | | **Reverter** | Rollback | Uma publicação que reverte a anterior. | | **Branch de produção** | Production branch | O branch de que a produção faz deploy, geralmente `main`. | | **Dono** | Owner | Gerencia as configurações, as chaves e os acessos de um projeto. Numa organização, os admins dela. | | **Membro** | Member | Pede mudanças e aprova publicações. | | **Organização** | Organization | Uma organização do GitHub com o app da bohr instalado; os membros dela espelham os do GitHub. | | **Provedor do modelo** | Model provider | De onde vem o modelo do agente: Anthropic, um endpoint compatível ou uma assinatura Claude. | | **Variáveis do site** | Site variables | Valores que o Worker de produção lê em tempo de execução. | | **Variáveis do build** | Build variables | Valores que o build do GitHub Actions lê, guardados criptografados na bohr. | | **Hospedado pela bohr** | Hosted by bohr | Um projeto migrado da bohr v1, ainda na conta da Cloudflare da bohr (`mode: managed`). | | **Sua conta da Cloudflare** | Own account | Um projeto na conta da Cloudflare do dono (`mode: byo`). | | **Plano de build** | Build plan | Como a bohr v2 faz o build de um projeto migrado que mantém o workflow da v1. | | **Token** | Token | Uma credencial `bohr_…` para a CLI, scripts e agentes de IA. | | **Workflow de deploy** | Deploy workflow | `.github/workflows/bohr-deploy.yml`, escrito pela bohr a partir do `.bohr/deploy.json`. | | **Bot da plataforma** | Platform bot | O bot do Telegram da própria instância, para o onboarding e para vincular contas. Cada projeto tem o próprio **bot do projeto**. | --- # Solução de problemas > Erros comuns, com as mensagens exatas que a bohr mostra, e como resolvê-los. Source: https://docs.bohr.io/pt-br/reference/troubleshooting/ ## Login | Mensagem | Solução | | --- | --- | | *Esta instância ainda não foi configurada* | Auto-hospedagem: o administrador precisa concluir o `/setup` ([app do GitHub](https://docs.bohr.io/pt-br/self-hosting/github-app/)). | | *Muitas tentativas. Aguarde alguns minutos e tente de novo.* | Códigos por e-mail demais ou códigos errados demais. Espere uns 15 minutos. | | *O código venceu ou foi digitado errado vezes demais. Peça um novo código.* | Os códigos valem 10 minutos e permitem 5 tentativas. | | *Este e-mail já pertence a outra conta da bohr.* | Entre com essa outra conta, ou use outro endereço. | ## Conectando a Cloudflare | Mensagem | Solução | | --- | --- | | *Isso não parece um token da API da Cloudflare.* | Copie o token inteiro, sem espaços. | | *Cloudflare did not accept this token.* / *This token is …* | O token é inválido, venceu ou está desativado. Crie outro. | | *O token não tem todas as permissões* (Containers: Edit…) | Edite o token e adicione o que estiver listado. **Containers: Edit** também exige que a conta esteja no **Workers Paid**. Veja [Conectar a Cloudflare](https://docs.bohr.io/pt-br/getting-started/connect-cloudflare/). | | *This token cannot see any Cloudflare account.* | Dê ao token acesso à sua conta (Account Resources). | | *Paste the Cloudflare token again.* | Você levou mais de 15 minutos para escolher uma conta. Cole o token de novo. | | *O token da Cloudflare não pode criar bancos de dados D1.* | Projetos criados a partir de um modelo precisam de **D1: Edit**. Edite o token e tente de novo. | ## Configuração do projeto | Mensagem | Solução | | --- | --- | | *This Cloudflare account has no workers.dev subdomain yet. Open Workers & Pages in the Cloudflare dashboard once to create it, then try again.* | Faça isso e depois use a opção de tentar de novo na página do projeto. | | *… is already a bohr project.* | Um repositório só pode ser um projeto. Procure-o em **Projetos** (ou numa organização). | | *The GitHub App cannot reach that repository.* | [Dê ao app acesso](https://docs.bohr.io/pt-br/getting-started/install-github-app/#dar-acesso-a-mais-repositórios) ao repositório. | | *Para criar projetos no bohr.io Cloud, você precisa de uma assinatura ativa.* | [Assine](https://docs.bohr.io/pt-br/billing/subscription/), ou peça a um admin da organização para assinar. | | *The Cloudflare account already has a Worker named … Choose another project name.* | Projetos criados a partir de um modelo: escolha outro nome. | | *GitHub is taking too long to copy the template.* | O repositório foi criado; espere um minuto e crie o projeto a partir dele como repositório. | | *Falha na configuração* com outro motivo | Confira as permissões do token e se a conta está no Workers Paid, e tente de novo. | ## O agente | Mensagem | Solução | | --- | --- | | *O agente está desligado porque ainda não tem um provedor.* | O dono (ou o admin da organização) define um [provedor de modelo](https://docs.bohr.io/pt-br/agent/providers/). | | *That does not look like an Anthropic API key (sk-ant-…).* | As chaves da Anthropic começam com `sk-ant-`. Um token `sk-ant-oat01-` é um token de assinatura Claude: escolha **Assinatura Claude**. | | *The provider did not accept this key.* / *Could not reach …* | Confira a chave e a **URL base** de um provedor compatível (sem `/v1/messages`). | | *o orçamento do pedido (US$…) acabou antes de o trabalho terminar* | Aumente o **Orçamento por pedido** em **Configurações › Agente**, ou divida o pedido. | | *o ambiente do agente reiniciou no meio do pedido* | Acontece durante atualizações da bohr. Mande o pedido de novo; uma preparação do repositório interrompida recomeça sozinha uma vez. | | *Você já tem 5 pedidos na fila.* | Espere, ou cancele um com `/cancelar`. | | *A mensagem é longa demais.* | Os pedidos têm limite de 20.000 caracteres. Divida-o. | ## A homologação | Mensagem | Solução | | --- | --- | | *A homologação ainda não está configurada: o agente prepara isso ao importar o repositório.* | Espere a preparação do repositório, ou clique em **Preparar o repositório** no chat. | | *A homologação não conseguiu iniciar. Peça ao agente para verificar o arquivo .bohr/preview.json.* | Abra **Status e log da homologação** para ver o erro e peça ao agente para corrigi-lo. Veja [.bohr/preview.json](https://docs.bohr.io/pt-br/deploys/preview-json/). | | *A homologação está iniciando. Esta página recarrega sozinha.* | O sandbox estava dormindo e está instalando as dependências. Pode levar alguns minutos. | | *A homologação está rodando, mas o servidor dela não respondeu.* | O servidor de desenvolvimento precisa escutar em `0.0.0.0` na porta configurada e aceitar qualquer header `Host`. | ## Deploys | Mensagem | Solução | | --- | --- | | *O deploy de produção falhou. Veja os detalhes: …* | Abra a execução em [Builds](https://docs.bohr.io/pt-br/projects/builds/) e peça ao agente para corrigir o erro. A produção mantém a versão anterior. | | *O arquivo .bohr/deploy.json tem um problema (…), então o deploy de produção não foi atualizado.* | Peça ao agente para corrigi-lo, ou corrija manualmente ([referência](https://docs.bohr.io/pt-br/deploys/deploy-json/)). | | `Deploy credentials are only given to .github/workflows/bohr-deploy.yml on .` | Só esse workflow, num push para o branch de produção, recebe credenciais. | | `Could not get a GitHub OIDC token` | O workflow precisa de `permissions: id-token: write`. | | *A proteção não vale para este site* | O projeto usa um comando `deploy` próprio; veja [Proteção por senha](https://docs.bohr.io/pt-br/projects/password-protection/). | ## CLI | Mensagem | Solução | | --- | --- | | `Not signed in to … Run "bohr login", or set BOHR_TOKEN…` | Faça login, ou defina um token ([Autenticação](https://docs.bohr.io/pt-br/cli/authentication/)). | | `… The token expired or was revoked…` | Crie um novo token, ou rode `bohr login` de novo. | | `… runs in its owner's Cloudflare account, and deploys from the CLI only reach projects bohr hosts for now.` | Uma CLI desatualizada (4.0.0 ou anterior): rode `npx bohr@latest` ([detalhes](https://docs.bohr.io/pt-br/cli/deploy/#quais-projetos)). | | `… runs in its owner's Cloudflare account: only its owners (admins of its organization) can deploy it from the CLI…` | Só os donos fazem deploy desses projetos pela CLI. Faça push num branch, ou peça a um dono ([detalhes](https://docs.bohr.io/pt-br/cli/deploy/#quem-pode-fazer-deploy)). | | `wrangler printed no preview address: turn on preview URLs for the Worker…` | Defina `"preview_urls": true` na configuração do wrangler do Worker ([detalhes](https://docs.bohr.io/pt-br/cli/deploy/#homologações)). | | `This folder's wrangler config deploys the Worker "…", but …'s site is "…"` | Rode na pasta do Worker do projeto, ou corrija o `name` na configuração do wrangler. | | `This repository is not a bohr v2 project: …` | Rode na pasta do projeto, vincule-a com `bohr link` ou adicione uma configuração do wrangler. Repositórios da bohr v1 nunca são alterados. | | `Which project? … has no GitHub remote (origin).` | Passe `--project ` ou rode `bohr link`. | | `Which branch? HEAD is detached: pass --branch .` | Passe `--branch`. | | `Asset too large: …` | A Cloudflare aceita arquivos de até 25 MiB: remova o arquivo ou liste-o no `.assetsignore`. | | `Found wrangler.toml, but this action reads wrangler.jsonc.` | Converta a configuração para `wrangler.jsonc`. | Todos os códigos da CLI: [Códigos de saída e erros](https://docs.bohr.io/pt-br/cli/exit-codes/). ## Domínios e variáveis | Mensagem | Solução | | --- | --- | | *O site ainda não foi publicado* / `The site's Worker (…) is not deployed yet.` | Domínios e variáveis do site precisam do Worker do site: publique uma vez. | | `No zone in your Cloudflare account covers … Add the domain to Cloudflare first.` | Adicione a zona do domínio à conta em que o projeto roda. | | *… é um nome que a bohr ou o GitHub já usam.* | Nomes que começam com `GITHUB_`, `CLOUDFLARE_`, `BOHR_`, e `CI`, são reservados. | | `… is already set in the site's wrangler config: change it there.` | Remova-a de `vars` no `wrangler.jsonc`, ou mude-a lá. | Ainda com problemas? [Discord](https://discord.com/invite/p3hhfGg2Uy) ou [contact@bohr.io](mailto:contact@bohr.io). --- # Limites > Todos os limites de tamanho, tempo e quantidade da bohr, num só lugar. Source: https://docs.bohr.io/pt-br/reference/limits/ ## O agente | Limite | Valor | | --- | --- | | Orçamento por pedido | US$5 por padrão; definido pelo dono (de 0,10 a 1000, no painel ou no Telegram) | | Máximo de turnos por pedido | 200 por padrão; de 1 a 1000 | | Tempo de execução por pedido | 2 horas | | Tamanho do pedido | 20.000 caracteres | | Pedidos esperando | 5 por membro; um roda de cada vez por projeto | | Perguntas do agente | Até 8 opções | | Início da homologação | O servidor de desenvolvimento precisa aceitar conexões em até 3 minutos; o `install`, em até 15 minutos | | Porta reservada | 4840 (o servidor de controle do agente) | ## Deploys | Limite | Valor | | --- | --- | | Tamanho de arquivo estático | 25 MiB por arquivo (Cloudflare). Projetos migrados da v1 pulam arquivos de 24 MiB ou mais. | | `_redirects`, `_headers` | 256 KiB cada (projetos que a bohr hospeda) | | Workflow de deploy | 30 minutos por execução; uma execução de cada vez por repositório | | Comandos do `.bohr/deploy.json` | Uma linha, até 500 caracteres, sem `${{ }}` | | `secrets` do `.bohr/deploy.json` | Até 50 nomes | | Comandos do `.bohr/preview.json` | Até 1000 caracteres | | Sessões de deploy (CLI e action) | Vencem depois de 2 horas | | Branches de homologação que um token cria | 20 por projeto hospedado pela bohr, contando as homologações que ele já tem; um branch que já tem homologação continua recebendo deploy | | Projetos por repositório | Um | ## Contas e acesso | Limite | Valor | | --- | --- | | Sessão no painel | 30 dias | | Código de login por e-mail | 6 dígitos, válido por 10 minutos, 5 tentativas | | Código do `bohr login` | Válido por 10 minutos | | Código de convite de projeto | Uso único, válido por 24 horas | | Tokens por usuário | 50 | | Validade do token | 30, 90 ou 365 dias, ou nunca | | Comando de orçamento no Telegram | De 0,10 a 1000 (US$) | ## Projetos que a bohr hospeda Só static assets, `vars` (strings) e secrets; nenhum outro binding e nenhum cron trigger. Veja [Configuração do wrangler](https://docs.bohr.io/pt-br/deploys/wrangler-config/#projetos-hospedados-pela-bohr). --- # Modelo de segurança > O que a bohr pode acessar, como as credenciais são guardadas e por que o agente não consegue publicar nem vazar as suas chaves. Source: https://docs.bohr.io/pt-br/reference/security/ ## O que a bohr pode acessar | Acesso | Dado por | Usado para | | --- | --- | --- | | Os repositórios que você seleciona | O app do GitHub da bohr ([permissões](https://docs.bohr.io/pt-br/getting-started/install-github-app/#o-que-o-app-pode-fazer)) | O branch do agente, pull requests, merges, o workflow de deploy, os logs de build | | A sua conta da Cloudflare | O token da API que você cria ([permissões](https://docs.bohr.io/pt-br/getting-started/connect-cloudflare/#criar-o-token)) | Criar e atualizar os Workers, o sandbox e a homologação de cada projeto; o seu deploy de produção; domínios, variáveis e proteção | | O seu provedor de modelo | A sua chave da API ou o token da sua assinatura Claude | Os pedidos do agente | ## Como as credenciais são guardadas | Credencial | Guardada | Observações | | --- | --- | --- | | Token da API da Cloudflare | No cofre da instância, com envelope encryption (AES-256-GCM) | Todo uso fica registrado no log de auditoria da instância. Entregue ao seu deploy de produção na hora da execução (e ao `bohr deploy` de um dono), nunca guardado no GitHub. | | Chave privada do app do GitHub | No cofre da instância | Usada para tokens de instalação de curta duração, restritos a um repositório | | Chave do modelo ou token Claude | Criptografados na instância, e como secret de cada Worker do projeto | O sandbox só tem um placeholder | | Variáveis do build | Criptografadas na instância | Presas ao projeto, ao branch e ao nome delas | | Variáveis do site | Secrets do seu Worker de produção | A bohr guarda os valores comuns só para mostrá-los | | Senhas do site | Só hashes PBKDF2-SHA256 | — | | Tokens da CLI e da API (`bohr_…`) | Só o hash SHA-256 deles | O token em si fica no seu computador ou em `BOHR_TOKEN` | | Códigos de convite | Com hash | Uso único, 24 horas | ## O sandbox do agente O sandbox é um Cloudflare Container na conta do dono do projeto. Ele **nunca guarda uma credencial**: - O agente vê placeholders. Um gateway no Worker do projeto adiciona a chave real do modelo, só nos endpoints de mensagens do provedor e só enquanto um pedido roda, não enquanto a homologação roda entre pedidos. - O tráfego do Git recebe um token de curta duração para aquele único repositório, com **contents: write** e nada mais. Os pushes só são aceitos enquanto um pedido roda, e só para o `homolog`. - Sem a permissão de workflows, o GitHub recusa qualquer push que mude `.github/workflows`, então o código no sandbox não consegue adicionar um workflow que rodaria com os secrets do repositório. - Requisições que carregam credenciais não seguem redirecionamentos, então um redirecionamento não consegue levar uma chave para outro lugar. - Uma dependência maliciosa instalada no sandbox pode usar a rede, mas não consegue ler as chaves. A única exceção: conectar uma assinatura Claude roda o `claude setup-token` num container, onde o novo token existe até o login terminar. Instâncias com o container de login dedicado o rodam ali, onde nenhum código de projeto roda. ## Aprovações - A produção só muda por meio de um pull request aprovado e mergeado. O merge indica o commit revisado: mudanças enviadas depois de uma revisão não podem ser publicadas por aquela aprovação. - O link do diff em cada decisão mostra exatamente o commit que a aprovação publica. - A homologação é pública, mas não listada (um nome `workers.dev` impossível de adivinhar, `noindex`), e nunca chega à porta de controle do sandbox. ## Credenciais de deploy Os projetos na sua própria conta fazem deploy pelo GitHub Actions com `wrangler deploy`, e **nenhum token da Cloudflare fica no repositório**. A primeira etapa da bohr no workflow pede um token OIDC do GitHub (audience `bohr.io`) e pede as credenciais à instância. A instância verifica o token (emissor, audience, validade, assinatura), encontra o projeto pelo id do repositório e só responde quando: - a execução é do `.github/workflows/bohr-deploy.yml` no branch de produção, disparada por `push` ou `workflow_dispatch` (nada de pull request, outro branch ou outro workflow); - o projeto roda na conta da Cloudflare do dono, com uma conexão do dono (a do usuário, ou a da organização). Toda resposta é auditada (repositório, ref, id da execução; nunca o token). Toda recusa é um HTTP 403 com o motivo. O código que roda no workflow de produção só vem de merges aprovados ou de pessoas com permissão de escrita no branch de produção. ## Tokens Um token `bohr_…` age como o usuário dele, só nos projetos que lista, e nunca com o papel de administrador da instância. Sessões de deploy abertas com um token só podem ser concluídas com o mesmo token. Para o [`bohr deploy`](https://docs.bohr.io/pt-br/cli/deploy/#projetos-na-sua-própria-conta-da-cloudflare) de um projeto na conta Cloudflare do dono, um token também pode obter o token da API da Cloudflare e o id dessa conta, de que o wrangler precisa. A instância só responde quando: - o token alcança o projeto e o usuário dele é dono do projeto (num projeto de organização: admin da organização); - o projeto roda na conta da Cloudflare do dono, com uma conexão do dono. Nunca para projetos que a bohr hospeda, e nunca o token da conta da própria bohr. Toda entrega fica registrada no log de auditoria (usuário, token, projeto), é respondida com `Cache-Control: no-store` e tem limite de 30 por usuário e projeto em 10 minutos (HTTP 429 acima disso). A CLI coloca o token da Cloudflare só no ambiente do wrangler: nunca numa linha de comando, num log ou em disco. ## O que a bohr deixa na sua conta da Cloudflare Toda chamada à API envia `User-Agent: bohr/ (+https://bohr.io)`; os Workers da bohr levam as tags `bohr` e `bohr-project:`; os deploys de produção, e as versões que o `bohr deploy` envia, levam a mensagem `bohr` e a tag `bohr-` (`bohr-local` para uma árvore de trabalho com mudanças não commitadas). ## Relatar uma vulnerabilidade Mande um e-mail para [contact@bohr.io](mailto:contact@bohr.io). Por favor, não abra issues públicas para problemas de segurança. Respondemos em até 3 dias úteis. --- # Histórico de mudanças > O que mudou na bohr, versão por versão, a partir da bohr v2. Source: https://docs.bohr.io/pt-br/changelog/ ## CLI 4.1.0 - O `bohr deploy` faz deploy de projetos na sua própria conta da Cloudflare, para os donos deles (admins da organização): homologações como versões do Worker com um alias de preview por branch, produção com as migrations do D1 primeiro, as duas com o wrangler e as variáveis do build guardadas na bohr. Os membros recebem o código de saída 5 (`own_account_not_allowed`). Veja [Projetos na sua própria conta da Cloudflare](https://docs.bohr.io/pt-br/cli/deploy/#projetos-na-sua-própria-conta-da-cloudflare). - O resultado `--json` do `bohr deploy` tem `mode` (`managed` ou `byo`); os deploys na sua própria conta acrescentam `versionId`, `previewUrl`, `workerName` e `commitSha`. - `own_account` (código de saída 5) agora só vem da CLI 4.0.0 e anteriores: atualize com `npx bohr@latest`. ## 2.0.0 bohr v2: a bohr reescrita como uma plataforma de deploy open source e auto-hospedada, operada por um agente de IA. ### O agente - Um agente de IA muda o seu site por conversa, no painel web ou em um bot do Telegram por projeto. - Toda mudança vai primeiro para a homologação (branch `homolog`); **Aprovar e publicar** faz o merge para a produção, **Descartar** joga fora, e a reversão desfaz a última publicação. - Provedores de modelo: uma chave da API da Anthropic, qualquer endpoint compatível com a Messages API da Anthropic, ou uma assinatura Claude Pro/Max. - Orçamento e máximo de turnos por pedido, modelo e idioma por projeto. ### Projetos - Os projetos rodam na conta da Cloudflare do dono, com deploy feito por um workflow do GitHub Actions que a bohr escreve a partir do `.bohr/deploy.json`, com credenciais entregues na hora da execução via GitHub OIDC. - Novos projetos a partir de seis modelos (Lista de espera, Agendamentos, Link na bio, Formulários e pesquisas, Cardápio digital, Links curtos), com um banco de dados D1. - Variáveis do site e do build, proteção por senha com Basic Auth, domínios próprios, builds e versões no painel. - Membros com códigos de convite de uso único; organizações que espelham organizações do GitHub, com assinatura, conta da Cloudflare e agente próprios. ### Ferramentas de deploy - A CLI `bohr` 4.0.0 (`npx bohr`; as versões 2.x e 3.x no npm são de um pacote de 2016 sem relação, que usava o nome): `login`, `logout`, `whoami`, `projects`, `link`, `open` e `deploy`, com saída `--json` e códigos de saída estáveis para scripts e agentes de IA. - Tokens em **Conta › Tokens**, restritos a projetos e com validade. - `bohr-io/deploy-action@v1` roda a CLI no GitHub Actions. ### Rodando a bohr - Auto-hospedagem com o botão Deploy to Cloudflare, telemetria anônima opcional. - bohr.io Cloud em app.bohr.io por US$20/mês por conta ou organização. - Os projetos da bohr v1 continuam fazendo deploy pelo workflow deles, hospedados pela bohr até que os donos os movam para a própria conta da Cloudflare.