Pular para o conteúdo principal

Brabo API (0.1.0)

Baixar a especificação OpenAPI:Baixar

A API do Brabo. Todo endpoint devolve JSON, exceto os quatro explicitamente documentados com outro content-type (os dois de SSE, o de métricas, e o callback OAuth, que redireciona).

Autenticação

O access token é um JWT EdDSA de 15 minutos, apresentado em Authorization: Bearer <token>. A chave pública mora em GET /.well-known/jwks.json.

O refresh não é JWT: é um token opaco que mora num cookie httpOnly (brabo_refresh, Path=/auth, SameSite=Strict) e nunca aparece em corpo de resposta nenhum. POST /auth/refresh e POST /auth/logout leem o cookie e exigem que o cabeçalho X-CSRF-Token bata com o cookie brabo_csrf.

A rotação é obrigatória. Cada refresh consome o token apresentado e emite outro. Reapresentar um já consumido é assinatura de roubo e revoga a família INTEIRA — inclusive a sessão legítima. Um cliente que dispara dois refreshes concorrentes derruba a si mesmo; use uma única chamada em voo.

As rotas /internal/* são a superfície api ↔ engine e ficam fora do JWT: exigem o cabeçalho X-Brabo-Service-Token com o segredo compartilhado. Token de usuário não abre nenhuma delas.

Erros

Formato padrão do NestJS: { "statusCode": number, "message": string | string[], "error": string }.

código quando
400 corpo inválido — o ValidationPipe roda com whitelist e forbidNonWhitelisted, então campo desconhecido também reprova
401 sem token, token expirado ou credencial inválida
403 autenticado mas sem o papel que o RBAC exige, ou service token errado
404 o recurso não existe ou é invisível para quem chama
409 conflito de estado — transição de sessão inválida, recurso já existe
429 rate limit ou bloqueio progressivo

As rotas de auth respondem de forma deliberadamente indistinguível entre e-mail inexistente, senha errada e conta bloqueada: mesmo corpo, mesmo status, mesmo tempo. É isso que fecha a enumeração de contas, e não é defeito de diagnóstico.

Rate limit

Janela deslizante no Postgres: 300 requisições por usuário e 600 por IP a cada 60s, configurável. Rota @Public() e rota de serviço são isentas — o que protege /auth/* é o bloqueio progressivo, não o rate limit.

autenticação

Chaves públicas de verificação do access token

Uma chave em operação normal; duas durante uma rotação de AUTH_JWT_SECRET.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "keys": [
    ]
}

Autentica e emite o par access + refresh

E-mail inexistente, senha errada e conta bloqueada devolvem exatamente a mesma resposta 401 — mesmo corpo, mesmo status.

Request Body schema: application/json
required
email
required
string
senha
required
string

Respostas

Exemplos de requisição

Content type
application/json
{
  • "email": "fulano@brabo.dev",
  • "senha": "correct horse battery staple"
}

Exemplos de resposta

Content type
application/json
{
  • "accessToken": "string",
  • "expiresIn": 900,
  • "locale": "pt-BR"
}

Revoga a família do refresh apresentado

Sempre 204, mesmo para token desconhecido — responder 401 aqui seria um oráculo de validade de token.

Respostas

Recebe o callback OAuth do login social

Sucesso vai para WEB_ORIGIN/ já com os cookies da sessão gravados; falha vai para WEB_ORIGIN/login?oauth_error=1, sem detalhar o motivo.

path Parameters
provider
required
string
Valores: "github" "gitlab"
query Parameters
code
required
string
state
required
string

Respostas

Redireciona para o provider OAuth do login social

O state vai assinado por HMAC com propósito PRÓPRIO — nunca o do fluxo de conexão de git ao projeto (ver ADR 0084).

path Parameters
provider
required
string
Valores: "github" "gitlab"

Respostas

Rotaciona o refresh e emite um par novo

O refresh apresentado é consumido. Reapresentar um token já rotacionado revoga a família INTEIRA e grava um evento de segurança — mesmo quando a causa foi um duplo envio do cliente.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "accessToken": "string",
  • "expiresIn": 900,
  • "locale": "pt-BR"
}

Cria uma conta e envia o e-mail de verificação

Responde 202 tanto para endereço novo quanto para um já cadastrado — a resposta não revela se a conta existe. No segundo caso nada é criado e o dono do endereço recebe um aviso.

Request Body schema: application/json
required
email
required
string

O e-mail da conta.

senha
required
string >= 12 characters

Senha. Mínimo de 12 caracteres; sem exigência de maiúscula, dígito ou símbolo.

nome
string

Respostas

Exemplos de requisição

Content type
application/json
{
  • "email": "fulano@brabo.dev",
  • "senha": "correct horse battery staple",
  • "nome": "Fulano de Tal"
}

Exemplos de resposta

Content type
application/json
{
  • "message": "If the address is available, we've sent an email."
}

Pede o link de redefinição de senha

Responde 202 tanto para endereço conhecido quanto desconhecido. É também o caminho de quem foi importado do Keycloak e ainda não definiu senha.

Request Body schema: application/json
required
email
required
string

Respostas

Exemplos de requisição

Content type
application/json
{
  • "email": "fulano@brabo.dev"
}

Exemplos de resposta

Content type
application/json
{
  • "message": "If the address is available, we've sent an email."
}

Define a senha nova a partir do token

Revoga TODAS as sessões do usuário. Não emite tokens: quem redefine a senha é mandado ao login, para que comprometer o e-mail não equivalha a tomar a conta num passo só.

Request Body schema: application/json
required
token
required
string

Token de uso único recebido por e-mail.

novaSenha
required
string >= 12 characters

Respostas

Exemplos de requisição

Content type
application/json
{
  • "token": "string",
  • "novaSenha": "another pretty long passphrase"
}

Confirma o e-mail com o token de uso único

Request Body schema: application/json
required
token
required
string

Token de uso único recebido por e-mail.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "token": "string"
}

gates

O registro de gates ativos

Índice declarativo dos gates do fluxo (ADR 0054). A tela deriva daqui quais etapas existem e quem julga cada uma, em vez de repetir a lista no código — que era como ela envelhecia sem ninguém notar.

Authorizations:
bearer

Respostas

Exemplos de resposta

Content type
application/json
{
  • "version": 1,
  • "gates": [
    ]
}

Retoma um ciclo de gate estacionado

Ciclo de gate parado há mais de 2 h é estacionado em vez de reiniciado sozinho (ADR 0207). Este é o gesto humano que o retoma.

Authorizations:
bearer
path Parameters
projectId
required
string
taskId
required
string
gate
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

git

Recebe o retorno OAuth e redireciona para a web

Pública porque quem chega é o NAVEGADOR do usuário vindo do provider, sem sessão da api. Não é irrestrita: o state é verificado por HMAC e sem um válido a chamada é recusada. Nunca responde JSON — sempre redireciona, porque um corpo de erro cru numa navegação do navegador seria uma experiência péssima.

path Parameters
provider
required
string
Valores: "github" "gitlab"
query Parameters
code
required
string
state
required
string

Respostas

Anota cada linha de um arquivo com o commit que a tocou

Base para a pendência declarada do blame (FASE 26b) — a interface que anota o editor linha a linha ainda não existe. truncated avisa quando o arquivo passou do teto de linhas anotadas.

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
path
required
string

Caminho do arquivo a anotar.

ref
string

Branch, tag ou sha. Ausente usa a branch padrão do repositório.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ref": "dev",
  • "path": "apps/api/src/main.ts",
  • "lines": [
    ],
  • "truncated": false
}

Lista branches com ahead/behind e a PR aberta associada

Base para o dropdown rico (FASE 26b) — hoje o seletor de ref é um campo de texto simples. ahead/behind são relativos à branch PADRÃO do repositório; null quando o provider não consegue calcular (degradação honesta, não erro). NÃO é listBranches (que o bootstrap do Gitflow usa) — é operação própria, porque enriquecer custa uma chamada a mais ao provider POR BRANCH.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "items": [
    ],
  • "truncated": false
}

Devolve o conteúdo de um arquivo

UTF-8, cortado no teto de bytes com truncated: true quando passa dele. Caminho que escapa da pasta do projeto é recusado com 400 pela checagem central da RN-095 — nunca com 404, que convidaria a sondar.

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
path
required
string

Caminho do arquivo.

ref
string

Branch, tag ou sha.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ref": "dev",
  • "path": "apps/api/src/main.ts",
  • "content": "import { NestFactory } from '@nestjs/core';\n",
  • "truncated": false,
  • "bytes": 1284
}

Lista as PRs/MRs do repositório

Base para a lista navegável (FASE 26b) — hoje o diff só é alcançável por um id conhecido (ex.: vindo de Aprovações); esta rota resolve como chegar ao id sem ter de sabê-lo de cor. truncated avisa quando a lista passou do teto por chamada.

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
state
string
Valores: "open" "merged" "closed"

Ausente lista todos os estados.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "items": [
    ],
  • "truncated": false
}

Devolve o diff de uma PR, normalizado entre providers

patch nulo distingue o caso em que o provider não entregou o texto (binário, ou patch grande demais) do caso em que o texto voltou vazio. Juntar os dois faria a tela dizer que um binário alterado não mudou. O campo truncated avisa quando a lista de arquivos passou do teto.

Authorizations:
bearer
path Parameters
projectId
required
string
pullRequestId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "pullRequestId": "pr-1",
  • "files": [
    ],
  • "truncated": false
}

Lista UM nível da árvore do repositório

Não recursiva, por desenho do contrato: a aba navega sob demanda, e pedir a árvore inteira de um repositório grande é exatamente o amplificador de tráfego que esta fase proíbe. truncated avisa quando o nível passou do teto de entradas.

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
ref
string

Branch, tag ou sha. Ausente usa a branch padrão do repositório.

path
string

Diretório a listar. Ausente ou vazio é a raiz.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ref": "dev",
  • "path": "apps/api",
  • "entries": [
    ],
  • "truncated": false
}

Inicia o OAuth com o provider de git

Não redireciona: devolve a URL para o cliente decidir quando mandar o navegador. O state vai assinado por HMAC, e é isso que impede o callback de ser forjado.

Authorizations:
bearer
path Parameters
projectId
required
string
provider
required
string
Valores: "github" "gitlab"

Respostas

Exemplos de resposta

Cria o repositório e roda o bootstrap do Gitflow

SÍNCRONA: a resposta só volta depois que o bootstrap inteiro (branches permanentes, proteções, templates) rodou — não há worker nem fila por trás. É IDEMPOTENTE E RETOMÁVEL, então chamá-la de novo depois de uma falha retoma do passo que falhou. Acompanhe o progresso e leia o motivo da falha por GET /projects/:id/git/bootstrap.

Authorizations:
bearer
path Parameters
projectId
required
string
provider
required
string
Valores: "local" "github" "gitlab"
Request Body schema: application/json
required
name
required
string

Nome do repositório no provider.

visibility
required
string
Valores: "public" "private"
namespace
string

Organização ou grupo. Quando omitido, o repositório é criado na conta pessoal de quem registrou a credencial.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "name": "checkout",
  • "visibility": "private",
  • "namespace": "acme"
}

Exemplos de resposta

Content type
application/json
{
  • "repository": {
    },
  • "bootstrap": {
    }
}

Adota um repositório existente, sem criar nada

Valida o acesso com getRepo e produz um PLANO (dry-run) do que o bootstrap faria — branches faltando, proteções faltando, arquivos. NADA é executado no repositório: decida depois por plan/approve ou plan/skip. Readotar o mesmo repositório converge (regenera o plano sem duplicar linha).

Authorizations:
bearer
path Parameters
projectId
required
string
provider
required
string
Valores: "local" "github" "gitlab"
Request Body schema: application/json
required
externalId
required
string

O identificador do repositório NO PROVIDER: owner/repo no github, namespace/path no gitlab, o caminho absoluto do repositório bare no local. Nada é criado — o repositório já tem de existir e a credencial registrada tem de alcançá-lo.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "externalId": "acme/checkout"
}

Exemplos de resposta

Content type
application/json
{
  • "repository": {
    },
  • "plan": {
    },
  • "alreadyAdopted": false
}

Devolve o estado do bootstrap do Gitflow

Em que passo está, se falhou e onde, e quantas tentativas houve. O detalhe passo a passo vem dos eventos bootstrap.step_* da sessão dedicada.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "status": "provisioning",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "failedStep": null,
  • "lastError": null,
  • "attempts": 1
}

Reconhece a falha de proteção de branch e segue adiante

protect_branches falha em repositório privado no plano gratuito, e o assistente avisa disso ANTES. Sem esta saída o único botão era "Tentar de novo", que sempre falha pelo mesmo motivo — e provision_failed faz o painel redirecionar o projeto de volta para a página de provisionamento, deixando-o inalcançável para sempre. Só falha em PROTEGER pode ser reconhecida: é o último passo e o único cuja falha deixa um repositório utilizável. A trava de merge do produto (RN-006) não depende da proteção do provider e continua valendo.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "status": "provisioned"
}

Devolve o plano de bootstrap e o que se decidiu sobre ele

decision: null com plano presente é o estado em que NADA roda — aguardando aprovação ou adoção como está (RN-045).

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "plan": {
    },
  • "decision": null,
  • "decidedAt": null,
  • "decidedBy": null
}

Aprova o plano INTEIRO e roda o bootstrap

A aprovação é tudo ou nada: aprovar passos soltos quebraria a cascata dev←main, qa←dev, rc←qa. O que roda é o plano RE-DERIVADO na hora da execução — igual ou menor que o mostrado, nunca maior.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
planGeneratedAt
required
string <date-time>

O generatedAt do plano que você VIU. Trava otimista: se o plano foi regenerado desde então (readoção, ou o repositório mudou), a decisão é recusada com 409 em vez de aplicar um sim dado sobre outra coisa.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "planGeneratedAt": "2026-08-01T23:45:00.000Z"
}

Exemplos de resposta

Content type
application/json
{
  • "repository": {
    },
  • "bootstrap": {
    }
}

Adota o repositório COMO ESTÁ, dispensando o bootstrap

Grava a decisão e não toca o repositório. O plano fica guardado como evidência do que deliberadamente não foi aplicado, e o cursor do bootstrap NÃO é mexido — nenhum passo rodou.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
planGeneratedAt
required
string <date-time>

O generatedAt do plano que você VIU. Trava otimista: se o plano foi regenerado desde então (readoção, ou o repositório mudou), a decisão é recusada com 409 em vez de aplicar um sim dado sobre outra coisa.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "planGeneratedAt": "2026-08-01T23:45:00.000Z"
}

Exemplos de resposta

Content type
application/json
{
  • "repository": {
    },
  • "bootstrap": {
    }
}

Devolve o repositório provisionado do projeto

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000REPOSITORIO000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "provider": "github",
  • "externalId": "904837261",
  • "defaultBranch": "main",
  • "visibility": "private",
  • "origin": "created",
  • "provisionedBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-23T10:00:00.000Z",
  • "updatedAt": "2026-07-23T10:00:00.000Z"
}

infraestrutura

Readiness — o processo consegue de fato servir tráfego

Executa um select 1. Revela só se o banco responde; nem topologia nem versão. Pública porque quem chama é o kubelet, que não carrega token.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "service": "api",
  • "status": "ok",
  • "timestamp": "2026-07-27T15:40:00.000Z",
  • "details": { }
}

Liveness — o processo ainda atende requisições

NÃO toca o banco, de propósito. Se tocasse, um Postgres lento reiniciaria TODAS as réplicas de uma vez e transformaria degradação em queda total. O pod sai do balanceador pelo /health.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "service": "api",
  • "status": "ok",
  • "timestamp": "2026-07-27T15:40:00.000Z",
  • "details": { }
}

Expõe métricas no formato de exposição do Prometheus

Não é JSON: é text/plain no formato de exposição. Pública por necessidade (o scraper não carrega token) e restrita por REDE — o Ingress de produção bloqueia este caminho na borda e a NetworkPolicy só libera o namespace de monitoramento.

Respostas

Exemplos de resposta

Content type
text/plain
# HELP oban_queue_depth Oban queue depth
# TYPE oban_queue_depth gauge
oban_queue_depth{queue="default",state="available"} 0

Baixa o binário standalone do runner local pra plataforma pedida

Proxy de GitHub Releases — platform aceita só linux-x64, linux-arm64, darwin-arm64. Sem autenticação: o binário não é segredo. Os bytes são conferidos contra o checksums.txt da mesma Release antes de qualquer coisa ser respondida (ADR 0149, RN-525); a rota NÃO verifica a assinatura do manifesto — isso é integridade, não procedência, e quem verifica assinatura é o install.sh.

Respostas

interno

Cria a PRIMEIRA conta de uma instalação, já verificada

Para o instalador de uma linha, que roda onde nenhum transporte de e-mail está configurado: o .env gerado não traz variável de e-mail, MAIL_TRANSPORT cai em log, e o cadastro normal espera um e-mail que nunca chega. A conta nasce verificada porque quem roda o instalador já provou algo MAIS FORTE que controlar uma caixa de e-mail — controla a máquina, o .env e o daemon do Docker. O cadastro normal não muda. Recusa com 409 quando a instalação tem QUALQUER usuário: a condição é sobre a instalação, não sobre este e-mail, então a restauração de uma migração silencia o passo pelo mesmo teste. A senha nunca é gerada aqui e nunca é guardada em lugar nenhum senão como hash argon2id; o workspace pessoal (RN-410) nasce na mesma transação.

Authorizations:
service-token
Request Body schema: application/json
required
email
required
string

O e-mail do owner, digitado no TTY. Normalizado antes de qualquer gravação; é o que o instalador grava no marcador dele, já que e-mail identifica e não é segredo.

senha
required
string

Lida sem eco e confirmada pelo instalador. Usada e descartada — nunca gravada no .env, no marcador nem em log, e nunca gerada por código nenhum: não há caminho em que uma conta nasça com senha escolhida pelo script. O mínimo é a política do DOMÍNIO, o mesmo código que o cadastro usa; o tamanho máximo aqui é proteção do argon2id, não política.

nome
string

Nome de exibição. Omitido: o nome do workspace pessoal cai na parte local do e-mail (RN-410) — nada é inventado.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "email": "voce@exemplo.dev",
  • "senha": "uma frase longa e minha",
  • "nome": "Fulana de Tal"
}

Exemplos de resposta

Content type
application/json
{
  • "userId": "01JC4Z0000USUARIO0000000001",
  • "email": "voce@exemplo.dev",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001"
}

Lê o registro declarativo de gates

O registro DESCREVE, não executa: nenhum gate passa a ser aplicado por causa dele, e mudar um campo aqui não muda comportamento nenhum. Cada gate diz onde mora a prova de que passou (evidencia), porque nem toda prova está no event log.

Authorizations:
service-token

Respostas

Exemplos de resposta

Content type
application/json
{
  • "version": 1,
  • "gates": [
    ]
}

Publica uma versão de prompt template, idempotente por hash

Se já existe uma versão com o MESMO hash para o mesmo name, nenhuma versão nova é criada — a existente é devolvida (o acerto de idempotência não muda o status HTTP: sempre 201, por simplicidade — o corpo é idêntico ao que teria sido criado).

Authorizations:
service-token
Request Body schema: application/json
required
name
required
string
version
required
string
body
required
string
hash
required
string

Respostas

Exemplos de requisição

Content type
application/json
{
  • "name": "dev-agent-kickoff",
  • "version": "3",
  • "body": "You are the dev agent for the {{modulo}} module...",
  • "hash": "sha256:9f2c..."
}

Exemplos de resposta

Content type
application/json
{
  • "name": "dev-agent-kickoff",
  • "version": "3",
  • "body": "You are the dev agent for the {{modulo}} module...",
  • "hash": "sha256:9f2c...",
  • "active": true
}

Busca um prompt template pelo nome

Uma version específica busca por igualdade; omitida, busca a versão active mais recente. 404 se o template (ou a versão pedida) não existe.

Authorizations:
service-token
path Parameters
name
required
string
query Parameters
version
string
Exemplo: version=3

Respostas

Exemplos de resposta

Content type
application/json
{
  • "name": "dev-agent-kickoff",
  • "version": "3",
  • "body": "You are the dev agent for the {{modulo}} module...",
  • "hash": "sha256:9f2c..."
}

Registra a chave de dispositivo de MÁQUINA de uma instalação nova

Para o instalador de uma linha, logo depois de criar a primeira conta: o agente local precisa de uma credencial, e a única que existia era presa a um PROJETO — numa instalação que ainda não tem nenhum. O par é gerado NA MÁQUINA e só a metade pública chega aqui; grave o id devolvido na JWK privada como kid (RN-475), que é o único vínculo entre o arquivo em disco e a metade pública no servidor. Não há userId no corpo DE PROPÓSITO: o dono é o ÚNICO usuário da instalação, resolvido pela api, então ter o service token nunca significa escolher de quem é a credencial cunhada. Registrar SUBSTITUI: as chaves de máquina ativas do dono são revogadas na mesma transação, então uma máquina reinstalada funciona e mil chaves de máquina não podem existir. Chaves de projeto (ADR 0118) nunca são tocadas.

Authorizations:
service-token
Request Body schema: application/json
required
name
required
string

Um nome para um humano reconhecer esta MÁQUINA depois, na lista de chaves de dispositivo de todo projeto que ela atende. Não é único. O instalador sugere o hostname; nada aqui é derivado dele pela api.

publicKeyJwk
required
string

A JWK PÚBLICA Ed25519 (RFC 8037), serializada como JSON. O par é gerado na máquina e a metade privada nunca viaja — JWK trazendo d é recusada com 400 dizendo isso, nunca guardada.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "name": "servidor-de-casa",
  • "publicKeyJwk": "{\"kty\":\"OKP\",\"crv\":\"Ed25519\",\"x\":\"…\"}"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000CHAVE000000000001",
  • "userId": "01JC4Z0000USUARIO0000000001",
  • "name": "servidor-de-casa",
  • "createdAt": "2026-09-12T12:00:00.000Z",
  • "replacedKeyIds": [ ]
}

Sincroniza o catálogo de modelos de todos os providers

Nunca falha por causa de um provider: cada um responde por si no relatório, com o motivo de ter sido pulado e a origem da falha quando houve. Provider que não respondeu é PULADO, não marcado indisponível.

Authorizations:
service-token

Respostas

Exemplos de resposta

Content type
application/json
{
  • "porProvider": [
    ]
}

O backlog do projeto em árvore, para o PO ler o que já foi escrito

A MESMA árvore épico → história → tarefa da aba Backlog, pelo mesmo caso de uso (três leituras por projeto, nunca N+1). É com ela que o PO vê um épico órfão e uma história sem tarefa em vez de recriar o que já existe (RN-164).

Authorizations:
service-token
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

As regras de negócio do projeto, com cobertura, para o PO ler

Todo artifact.business_rule das sessões do projeto — não só o da sessão corrente, que era o teto do contexto de kickoff do PO — com a description inteira e quais histórias já citam cada regra. uncoveredCount é a pendência: regra que nenhuma história cobre (RN-164). Projeto sem regra nenhuma responde 200 com lista vazia: "nenhuma regra capturada ainda" não é erro.

Authorizations:
service-token
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "rules": [
    ],
  • "uncoveredCount": 2
}

Executa um comando de terminal DENTRO do container real do projeto (RN-492)

Chamada só pelo engine, quando Engine.Actions.TerminalExecutor decidiu que o comando cabe dentro do container real (execution_mode: container com uma linha running REGISTRADA). Faz proxy para ContainerBrokerPort.exec (ADR 0130/0134) — a última das cinco operações do broker a ganhar chamador real. sucesso: false na resposta — nunca um erro lançado — é a forma NORMAL de broker que recusou ou é inalcançável: o container pode ter morrido ou sido removido por fora entre a linha running registrada e esta chamada (RN-486, registrado e observado nunca se fundem), e isso é falha do comando, não erro de transporte.

Authorizations:
service-token
path Parameters
projectId
required
string
Request Body schema: application/json
required
comando
required
string

O comando de shell, interpretado por sh -c DENTRO do container — a mesma convenção da ação de terminal rodada fora de um.

cwd
string

Diretório de trabalho DENTRO do container. Já traduzido do caminho do host pelo engine (RN-492) — este DTO não repete essa tradução. Omitido roda em /work, a raiz do projeto. O broker revalida que está dentro de /work e recusa (DiretorioForaDoEscopoError) caso contrário.

timeoutMs
number

Timeout em milissegundos. Omitido usa o padrão do broker.

object

AT-612: run in the task QA instance instead of the work container. Set by the engine from the gate context, never by the model.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "comando": "npm test",
  • "cwd": "/work/.worktrees/dev-api",
  • "timeoutMs": 300000,
  • "alvo": {
    }
}

Exemplos de resposta

Content type
application/json
{
  • "sucesso": true,
  • "exitCode": 0,
  • "output": "ok\n",
  • "timedOut": false,
  • "motivo": "o broker de container não respondeu em http://broker:8090: timeout"
}

O que o broker precisa para compor ele mesmo a spec do container

Identidade do projeto, modo de execução e a decisão de imagem vigente do Arquiteto. O broker revalida tudo antes de entregar qualquer coisa ao daemon — ler daqui não é o mesmo que confiar, e a recusa nomeia o campo. Nenhum caminho ABSOLUTO é devolvido: a origem do bind é resolvida pelo daemon contra o sistema de arquivos do HOST, e um caminho de dentro do container da api montaria em silêncio uma pasta vazia. O que viaja é localizacao (RN-503) — qual das duas raízes do broker usar, mais o segmento relativo que a raiz não cobre.

Authorizations:
service-token
path Parameters
projectId
required
string
query Parameters
papel
string
Valor: "qa"
task
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "projectId": "f52be111-0000-4000-8000-000000000000",
  • "projectSlug": "exp002",
  • "workspaceId": "aaaaaaaa-0000-4000-8000-000000000000",
  • "workspaceDirName": "exp002-f52be111",
  • "executionMode": "container",
  • "localizacao": {
    },
  • "usuarioDaPasta": {
    },
  • "imagem": {
    },
  • "imagemVersao": 3,
  • "comandoDoApp": "string",
  • "ports": [
    ],
  • "dns": [
    ],
  • "extraHosts": [
    ],
  • "qa": {
    }
}

O remoto de trabalho do projeto, para fetch e push

Devolve a origem limpa (sem credencial embutida) e, para provider remoto, o token do DONO do workspace (RN-058) decifrado na hora. Quem consome injeta o token por invocação e NUNCA o grava em arquivo — .git/config fica dentro da pasta onde a RN-075 concede ao dev agent leitura auto-aprovada.

Authorizations:
service-token
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{}

O agente local relata o desfecho de uma rodada de espelho (RN-517)

Chamada só pelo engine, depois que o runner empurra mirror_sync_result pelo canal — o MESMO caminho do workspace_confirm (runner → canal → engine → api), nunca um segundo mecanismo: o engine relata, não grava a tabela. Isto é TELEMETRIA, não evento de domínio: nunca session_events (rodada de espelho não tem sessão e session_id é NOT NULL, o mesmo raciocínio que fez de rag_searches uma tabela) e nunca proposed_action (a escrita do espelho é configuração que o usuário declarou, não agente pedindo para agir). ok é o que decide o desfecho — nunca a presença de uma contagem ou de uma mensagem: rodada que copiou 0 arquivos é normal e não pode ser indistinguível de uma que nunca rodou. Gravar nunca derruba o que mede: a cópia já está feita quando isto é chamado, e o engine só registra em log uma recusa aqui. Projeto cujo destino foi limpo nesse meio-tempo AINDA grava — a rodada aconteceu, e o erro dela costuma ser o que explica o que deu errado.

Authorizations:
service-token
path Parameters
projectId
required
string
Request Body schema: application/json
required
ok
required
boolean

O desfecho REAL da cópia, relatado pelo agente local depois de terminar — nunca um "ok" otimista antes de a rodada acabar.

destination
string

O destino que a rodada de fato resolveu (sucesso) ou tentou usar (falha), na máquina do USUÁRIO. CONGELADO na linha: mostrar o destino atual do projeto ao lado da cópia de ontem seria a tela afirmando sobre uma pasta que aquela rodada nunca tocou. Omitido quando a falha é sobre o próprio destino.

filesCopied
number

Arquivos regulares copiados nesta rodada. 0 é um número, não uma ausência — "sincronizou e não copiou nada" é um estado próprio (RN-088).

filesSkipped
number

Entradas que o git listou e não são arquivos regulares — um repositório aninhado (o worktree de um dev agent é um), um symlink, ou um arquivo que sumiu entre a listagem e a cópia.

filesRefused
number

Alvos que a guarda por arquivo recusou (um symlink escapando do destino). Contados, nunca engolidos.

error
string

A mensagem de falha NOMEADA. Guardada cortada quando muito longa, dizendo que foi cortada. Nunca apaga a última sincronização bem-sucedida — qual linha é a CORRENTE se decide comparando os dois carimbos.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "ok": true,
  • "destination": "/home/you/mirrors/store",
  • "filesCopied": 412,
  • "filesSkipped": 3,
  • "filesRefused": 0,
  • "error": "o espelho não conseguiu listar o trabalho com o git: not a git repository"
}

Exemplos de resposta

Content type
application/json
{
  • "recorded": true,
  • "status": "synced"
}

Os contratos entre módulos, para um dev agent ler (RN-684)

Uma entrada por módulo do module_map VIGENTE: o que ele consome (dependeDe, o dependsOn do mapa) e o que expõe (expoe, do artifact.module_contracts vigente do Arquiteto, ou null quando nenhum foi declarado). É o que um dev agent lê em vez de abrir o worktree de outro módulo (ADR 0200). Projeto sem contrato responde 200 com status: sem_contratos.

Authorizations:
service-token
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "status": "sem_contratos",
  • "version": 2,
  • "modulos": [
    ],
  • "contratosForaDoMapa": [ ]
}

O funil de entrega do projeto e métricas DORA parciais, para o PO ler

O MESMO relatório do script analise:funil (ADR 0089) — funil sessão → commit → PR → merge, lead time real e frequência de deploy real — pelas mesmas funções puras e a mesma consulta (apps/api/src/application/services/funil-metrics.ts), para que os dois nunca divirjam sobre o mesmo fato. Fecha docs/fluxo.yml (papel po, entrada metricas-de-produto, antes status: lacuna) (RN-407).

Authorizations:
service-token
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "project": {
    },
  • "totalActionsConsidered": 18,
  • "funnel": {
    },
  • "leadTimes": {
    },
  • "deploymentFrequency": [
    ]
}

Removes the QA instance of a task (RN-936)

Automatic, no proposal: it only reaches what carries the QA label (the broker guarantees it). Idempotent.

Authorizations:
service-token
path Parameters
projectId
required
string
taskId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "sucesso": true,
  • "status": "provisioning",
  • "chave": "a1b2c3d4",
  • "motivo": "string"
}

Brings up the ephemeral QA instance of a task (RN-935)

Records the row, then asks the broker. sucesso: false is the NORMAL shape of a refused broker. At most ONE active instance per project: another task active -> 409 instancia_de_qa_ocupada. runner projects -> 409 qa_nao_suporta_runner.

Authorizations:
service-token
path Parameters
projectId
required
string
taskId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "sucesso": true,
  • "status": "provisioning",
  • "chave": "a1b2c3d4",
  • "motivo": "string"
}

O runner confirma o caminho de um projeto "runner" (RN-423)

Chamada só pelo engine, depois que um runner conecta e manda workspace_confirm pelo canal. O runner é a FONTE DE VERDADE do caminho — a api sobrescreve workspacePath com o que ele relatou, depois de revalidá-lo lexicamente (raiz de sistema/sobreposição com o Brabo seguem proibidas mesmo vindo do runner). Idempotente: reconectar com o MESMO caminho não grava nada de novo.

Authorizations:
service-token
path Parameters
projectId
required
string
Request Body schema: application/json
required
path
required
string

Caminho absoluto confirmado pelo runner NO HOST — a fonte de verdade (RN-423). Revalidado LEXICAMENTE aqui antes de gravar; inválido é 400, nunca gravado.

sessionId
string <uuid>

A sessão mais recente do projeto (ProjectSession.latest_id/1), resolvida do lado do engine. null/omitida quando o projeto ainda não tem sessão nenhuma — o projeto é atualizado assim mesmo, só o evento de auditoria é pulado (lacuna aceita, RN-423).

actorId
string <uuid>

Quem pediu o ticket do runner (dono do socket que confirmou) — vira o ator do evento project.workspace_verified. Omitido: o evento (se houver sessão) nasce sem ator identificado.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "path": "/home/you/projects/store",
  • "sessionId": "01JC4Z0000SESSAO00000000001",
  • "actorId": "01JC4Z0000USUARIO0000000001"
}

Exemplos de resposta

Content type
application/json
{
  • "verified": true,
  • "workspacePath": "/home/you/projects/store",
  • "changed": true
}

Removes QA instances whose gate is no longer in flight (RN-937)

The engine sends the task ids it still has in flight; every other active or failed instance is removed. Shared services and the QA network have no broker operation yet (declared gap).

Authorizations:
service-token
Request Body schema: application/json
required
taskIdsEmVoo
required
Lista de strings

Task ids that still have a gate in flight; every other active instance is removed.

projectId
string <uuid>

Limit the sweep to one project.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "taskIdsEmVoo": [
    ],
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8"
}

Exemplos de resposta

Content type
application/json
{
  • "removidas": [
    ],
  • "falhas": [
    ]
}

O voto do agente sobre um chunk recuperado (RN-480)

Mesmo caso de uso da rota humana — nenhum segundo caminho de julgamento. searchId/chunkId desconhecido é um 400 que o engine transforma em tool-result de erro para o modelo corrigir (RN-061), nunca um crash.

Authorizations:
service-token
Request Body schema: application/json
required
projectId
required
string <uuid>
searchId
required
string <uuid>
chunkId
required
string <uuid>
verdict
required
string
Valores: "util" "irrelevante"
agent
required
string

Slug do agente — quem vota.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
  • "chunkId": "90e1f3df-a8a1-438e-8dd5-10e45398d051",
  • "verdict": "util",
  • "agent": "qa"
}

Exemplos de resposta

Content type
application/json
{
  • "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
  • "chunkId": "90e1f3df-a8a1-438e-8dd5-10e45398d051",
  • "verdict": "util",
  • "rank": 0
}

Busca híbrida sobre o índice RAG do projeto, para a ferramenta do engine

Mesmo motor de POST /projects/:projectId/rag/search (rota humana), projetado no formato que a ferramenta rag_search do engine espera.

Authorizations:
service-token
Request Body schema: application/json
required
projectId
required
string <uuid>
query
required
string
topK
number
sessionId
string <uuid>

A sessão em que o agente está rodando. Ausente quer dizer que quem chamou não tinha sessão — a linha de telemetria é gravada assim mesmo (RN-479), só a narração rag.search na timeline é pulada. Nunca inventada pela api: sessão que ela não recebeu é sessão que não existiu.

agent
string

Slug do agente, gravado como ator da telemetria (actor_kind: agent). Ausente cai no ator system em vez de inventar um usuário.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "query": "how the parallelism cap is decided",
  • "topK": 5,
  • "sessionId": "f6567dd8-e069-418e-8893-7d22fcf12459",
  • "agent": "dev-lead"
}

Exemplos de resposta

Content type
application/json
{
  • "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
  • "hits": [
    ],
  • "degraded": true
}

Propõe uma ação com efeito externo em nome de um agente

A ÚNICA porta pela qual um agente toca git, terminal ou gasto. permissions.json decide na criação, e deny vence qualquer autonomia concedida ao agente.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
actionType
required
string
Valores: "terminal" "git_commit" "git_push" "pr_open" "spend" "git_repo_create" "git_branch_create" "git_branch_protect" "write_file" "open_adr_pr" "git_merge" "open_infra_pr" "instruction_patch" "parallelize" "raise_max_parallel" "propose_execution_plan" "assess_implementability" "container_start" "container_stop" "container_remove" "container_recreate" "container_start_via_runner" "qa_environment_start"
required
object

Sempre um agente nesta rota.

required
object

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "actionType": "terminal",
  • "actor": {
    },
  • "payload": {
    }
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z"
}

Monta o contexto de uma rodada da Anamnese

Tudo numa chamada só, espelhando o contexto do Psicólogo. Os membros já vêm SEM quem optou por não ser perfilado, e as decisões do usuário dentro da janela vêm por aqui porque não estão no event log. O engine lê os eventos em si direto do Postgres — carregá-los por HTTP seria mais caro sem ser mais correto.

Authorizations:
service-token
query Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "competencyCatalog": [
    ],
  • "members": [
    ],
  • "queuedHypotheses": [
    ],
  • "currentProfiles": [
    ],
  • "instructions": [
    ],
  • "decisions": [
    ],
  • "windowFrom": "2026-07-27T12:00:00.000Z"
}

Fecha a janela da Anamnese de uma rodada que não emitiu perfil

Grava uma rodada da Anamnese com zero perfis para que a próxima comece em windowTo — sem isso, a janela nunca avançava e todo tick pagava uma rodada nova sobre o mesmo material.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
windowFrom
required
string <date-time>
windowTo
required
string <date-time>
eventCount
required
number

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "windowFrom": "2026-07-27T12:00:00.000Z",
  • "windowTo": "2026-07-27T12:15:00.000Z",
  • "eventCount": 12
}

Exemplos de resposta

Content type
application/json
{
  • "runId": "01JC4Z0000RODADA00000000001",
  • "profiles": [
    ]
}

Gera uma versão nova do diagrama C4 (Context + Container)

O artefato É o evento artifact.c4_diagram: imutável, versionado e com autor, ao lado de artifact.module_map. Exige um module_map vigente — sem ele não há nível Container para desenhar (400).

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
systemName
required
string

Nome do sistema/projeto, para o rótulo do diagrama.

systemDescription
string
Lista de objects (C4AtorInternalDto)

Atores externos do nível Context (Simon Brown). Os containers do nível Container NÃO entram aqui: vêm do module_map vigente do projeto.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "systemName": "Brabo",
  • "systemDescription": "Agent-orchestrated engineering platform.",
  • "actors": [
    ]
}

Exemplos de resposta

Content type
application/json
{
  • "diagrama": {
    },
  • "version": 1
}

Registra o desfecho de uma delegação de área

completed (com o veredito), failed (com a origem) ou dispensed (com a justificativa) — o lead nunca chama esta rota com desfecho pela metade: toda delegação já nasce aqui resolvida.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
area
required
string

A área que delegou — "qa" (Fase 8b) ou "infra" (Fase 8c). Texto, não enum.

taskId
string <uuid>

A tarefa de backlog por trás da delegação, quando existe. QA (Fase 8b) sempre a manda; Infra (Fase 8c) nunca — a delegação é sobre a SESSÃO, não uma tarefa.

leadAgent
required
string
subagent
required
string
status
required
string
Valores: "completed" "failed" "dispensed"
parecerArtifactId
string

Id do session_event artifact.qa_verdict do VEREDITO desta subespecialidade — obrigatório quando status é "completed".

failureOrigin
string
Valores: "infra" "modelo" "codigo" "politica"

A ORIGEM da falha (ADR 0020/0038), nunca por eliminação — obrigatória quando status é "failed".

failureReason
string
justification
string

Por que o lead escolheu NÃO delegar — obrigatório quando status é "dispensed". Nunca em branco: dispensar é uma decisão registrada, não silêncio (CLAUDE.md, Fase 8b item 2).

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "area": "qa",
  • "taskId": "01JC4Z0000TASK00000000001",
  • "leadAgent": "qa-lead",
  • "subagent": "qa-automacao",
  • "status": "completed",
  • "parecerArtifactId": "evt_01jc4z0000parecer000000001",
  • "failureOrigin": "infra",
  • "failureReason": "iteration limit reached without emit_perf_seguranca_verdict",
  • "justification": "story with no relevant performance NFR"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000DELEGACAO00000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z0000SESSAO000000000001",
  • "taskId": "01JC4Z0000TAREFA00000000001",
  • "area": "qa",
  • "leadAgent": "qa-lead",
  • "subagent": "qa-automacao",
  • "status": "completed",
  • "parecerArtifactId": "evt_01jc4z0000parecer000000001",
  • "failureOrigin": null,
  • "failureReason": null,
  • "justification": null,
  • "createdAt": "2026-07-30T12:00:00.000Z"
}

Monta o contexto completo de uma tarefa para o dev agent

Uma chamada só com tudo de que o prompt precisa: a história inteira, as regras de negócio resolvidas e os ADRs aplicáveis. module restringe os ADRs ao módulo daquele dev; ADR sem módulo declarado é TRANSVERSAL e sempre entra. Omitir module traz a coleção inteira, que é o que os gates de QA e SecOps querem ao reusar este mesmo contexto.

Authorizations:
service-token
query Parameters
projectId
required
string
taskId
required
string
module
string
Exemplo: module=api

Respostas

Exemplos de resposta

Content type
application/json
{
  • "task": {
    },
  • "story": {
    },
  • "businessRules": [
    ],
  • "adrs": [
    ],
  • "siblingTasks": [
    ],
  • "moduleOpenTasks": [
    ],
  • "moduleOpenTasksTotal": 0,
  • "moduleContract": {
    },
  • "primeiraDoModulo": true,
  • "decisoes": [
    ],
  • "decisoesDoProjeto": [
    ]
}

Cria um épico do backlog

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
title
required
string
description
string

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "title": "Shopping cart",
  • "description": "Everything the buyer does before paying."
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Shopping cart",
  • "description": "Everything the buyer does before paying.",
  • "createdAt": "2026-07-25T08:30:00.000Z",
  • "updatedAt": "2026-07-25T08:30:00.000Z"
}

Pagina o event log da sessão para o engine

Usada para REIDRATAR o histórico de um agente conversacional e para ler os artefatos de que o kickoff dele precisa. A rota humana equivalente é protegida por RBAC; esta, pelo service token. latest=true devolve a CAUDA (ainda em seq crescente) e ignora afterSeq; types restringe a página a esses tipos de evento. A página tem teto de 200 em qualquer caso (ADR 0060).

Authorizations:
service-token
path Parameters
sessionId
required
string
query Parameters
projectId
required
string
afterSeq
string
Exemplo: afterSeq=40
limit
string
Exemplo: limit=200
latest
string
Exemplo: latest=true

Busca a cauda do log; ignora afterSeq.

types
string
Exemplo: types=artifact.product_brief,artifact.business_rule

Tipos de evento separados por vírgula (no máximo 20). Só eventos desses tipos contam para limit.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "items": [
    ],
  • "nextCursor": 41
}

Acrescenta um evento ao log da sessão, em nome de um agente

Mesmo caso de uso e mesma atribuição atômica de seq da rota humana. As hipóteses do Psicólogo NÃO passam por aqui: têm rota própria, com validação de evidência.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
type
required
string

Ver docs/reference/events.md.

actorKind
required
string
Valores: "user" "agent" "system"
actorId
required
string

Slug do agente que o emitiu.

required
object

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "type": "agent.tool_call",
  • "actorKind": "agent",
  • "actorId": "dev-api",
  • "payload": {
    }
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRB",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 41,
  • "type": "chat.message",
  • "actor": {
    },
  • "payload": {
    },
  • "createdAt": "2026-07-27T14:30:58.512Z"
}

Registra o veredito de QA ou SecOps sobre a PR de uma tarefa

O nextAction da resposta é o que o engine obedece: correct volta ao dev, run_secops avança o gate, done libera para o usuário, await_user estaciona o ciclo até a pergunta aberta ser respondida (RN-860, sem contar correção), e blocked significa que o teto de correções acabou. O MERGE nunca é automático — done só quer dizer que é a vez do humano.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
taskId
required
string <uuid>
gate
required
string
Valores: "qa" "secops"
veredito
required
string
Valores: "approved" "changes_requested" "needs_user_decision"

needs_user_decision (só QA, RN-860): o ciclo espera a resposta do usuário a uma pergunta aberta — não conta como correção.

resumo
required
string
itens
required
Lista de strings

O que precisa mudar, item a item.

pergunta
string

Com needs_user_decision: a pergunta aberta nova (até 500 caracteres).

sugestao
string

Com needs_user_decision: a sugestão do agente.

openQuestionId
string <uuid>

Com needs_user_decision: uma pergunta aberta EXISTENTE em vez de uma nova.

maxCorrections
number

Teto de idas e voltas antes de a tarefa virar blocked. Omitido usa o padrão do domínio.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "taskId": "01JC4Z0000TAREFA00000000001",
  • "gate": "qa",
  • "veredito": "changes_requested",
  • "resumo": "Missing tests for the insufficient-stock path.",
  • "itens": [
    ],
  • "pergunta": "Should a nonexistent code answer 404?",
  • "sugestao": "404 with a plain message.",
  • "openQuestionId": "4c8aa973-c398-4859-8f2e-3fe00dc96a12",
  • "maxCorrections": 3
}

Exemplos de resposta

Content type
application/json
{
  • "nextAction": "run_secops",
  • "task": {
    },
  • "openQuestionId": "4c8aa973-c398-4859-8f2e-3fe00dc96a12"
}

Oferece um handoff de um agente para outro

Nasce offered. Quem aceita é uma PESSOA, pela rota humana — agente não ativa agente. Duas exceções. A oferta Criativo→PO que leva o product_brief pedido por um clique em "Estou pronto — a necessidade está validada" é aceita em nome de quem clicou, com essa pessoa como ator e implicito no payload (RN-658, ADR 0185). O handoff do PO ao Arquiteto é aceito pelo SISTEMA quando o backlog está coberto (ao menos uma regra de negócio, nenhuma sem história) e o repositório é local sem credencial de git no projeto (RN-660, ADR 0186); aceiteAutomatico diz se aconteceu e, se não, por quê. Em qualquer dos casos a resposta então traz status: accepted.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
fromAgent
required
string
toAgent
required
string
artifactId
string

ULID do session_event do artefato que motivou o handoff.

seAusente
boolean

Só se ninguém o pegou ainda (ADR 0182, RN-636): com uma oferta pendente ao alvo em QUALQUER sessão do projeto, devolve-a (desfecho: ja_oferecido) em vez de substituí-la. O AppSec o manda.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "fromAgent": "criativo",
  • "toAgent": "po",
  • "artifactId": "01JC4Z8QK3M7YV2N5T9B0PXHRB",
  • "seAusente": true
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000HANDOFF00000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "fromAgent": "criativo",
  • "toAgent": "po",
  • "artifactId": "01JC4Z0000ARTEFATO000000001",
  • "status": "offered",
  • "createdAt": "2026-07-24T10:00:00.000Z",
  • "updatedAt": "2026-07-24T10:05:00.000Z",
  • "desfecho": "criado",
  • "aceiteAutomatico": {
    }
}

Registra uma rodada de análise e suas hipóteses

Cada hipótese precisa citar eventos que EXISTEM nesta sessão — evidência inventada é recusada com 400, e é isso que separa uma hipótese de uma opinião. A rodada anterior da sessão passa a superada.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
tier
required
string
Valores: "leve" "pesada"

As duas faixas usam modelos de fato diferentes; o custo diverge.

triggeredBy
required
string
Valores: "auto" "manual"
eventCount
required
number

Tamanho do log analisado.

cause
string
Valores: "normal" "timeout" "kill" "crash" "node_shutdown" "unknown"

Causa CLASSIFICADA pelo engine. É ela, não o status terminal, que decide se terminationAnalysis é obrigatório. Opcional para não quebrar um engine mais antigo durante um deploy gradual.

required
Lista de objects (HypothesisDraftDto)

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "tier": "leve",
  • "triggeredBy": "auto",
  • "eventCount": 128,
  • "cause": "timeout",
  • "hypotheses": [
    ]
}

Exemplos de resposta

Content type
application/json
{
  • "analysisId": "01JC4Z0000ANALISE0000000001",
  • "hypotheses": [
    ]
}

Devolve os arquivos de uma PR de infra para os gates lerem

O conteúdo vem do próprio payload da proposed_action: artefato de infra nunca toca worktree, como os ADRs.

Authorizations:
service-token
path Parameters
prActionId
required
string
query Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "title": "api's production Dockerfile",
  • "files": [
    ]
}

Monta o contexto inicial do InfraAgent

O module_map vigente mais os ADRs de infraestrutura relevantes, mais o roteamento de módulos do Arquiteto (ADR 0131) — as candidatas entre as quais o Infra Lead elege ao propor container_start.

Authorizations:
service-token
query Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "moduleMap": {
    },
  • "adrs": [
    ],
  • "gitProvider": "github",
  • "moduleRouting": {
    },
  • "projectImage": {
    }
}

Registra o veredito de QA ou SecOps sobre uma PR de infra

Mesmo pipeline e mesma máquina de estados das PRs de dev.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
prActionId
required
string <uuid>

A ação open_infra_pr (uma proposed_action) que abriu a PR.

gate
required
string
Valores: "qa" "secops"
veredito
required
string
Valores: "approved" "changes_requested"
resumo
required
string
itens
required
Lista de strings
maxCorrections
number

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "prActionId": "01JC4Z8QK3M7YV2N5T9B0PXHRD",
  • "gate": "secops",
  • "veredito": "approved",
  • "resumo": "Non-root image with no secret in ARG.",
  • "itens": [ ],
  • "maxCorrections": 3
}

Exemplos de resposta

Content type
application/json
{
  • "nextAction": "done",
  • "artifact": {
    }
}

Propõe um patch no arquivo de instruções de um agente

Vira proposed_action, não escrita direta: mudar o comportamento de um agente é efeito externo e passa pelo mesmo pipeline de aprovação de todo o resto. Isso fecha o laço hipótese → patch.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agent
required
string
proposedContent
required
string

O arquivo INTEIRO como ficaria, não um diff.

rationale
required
string
hypothesisId
string <uuid>

A hipótese que motivou o patch. É isso que fecha o laço da Anamnese.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agent": "dev-api",
  • "proposedContent": "# dev-api\n\nAlways run the suite before opening the PR.",
  • "rationale": "The task was reopened three times for lack of a criterion.",
  • "hypothesisId": "01JC4Z0000HIPOTESE000000001"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z"
}

Executa um turno de LLM medido, com suporte a ferramentas

O metering é OBRIGATÓRIO: todo turno grava token_usage, e é isso que dá sentido ao orçamento. Não grava evento nenhum — quem narra o event log é o engine. Falha de provider volta em error com 200, porque a contabilidade em usage continua valendo: o turno gastou mesmo falhando.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agentId
string

Atribui o custo a este agente no painel do time.

required
Lista de objects

Histórico já montado pelo ContextManager do engine.

Lista de objects

Ferramentas oferecidas ao modelo; parameters é JSON Schema.

catalogoCompleto
boolean

Pede o catálogo INTEIRO de ferramentas: o roteador de ferramentas do Jev (ADR 0179) é pulado nesta chamada. O engine o liga quando repete um passo cujo menu restrito fez o modelo responder sem chamar ferramenta.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agentId": "dev-api",
  • "messages": [
    ],
  • "tools": [
    ],
  • "catalogoCompleto": true
}

Exemplos de resposta

Content type
application/json
{
  • "message": {
    },
  • "usage": {
    },
  • "error": null,
  • "errorCode": null,
  • "modelName": "llama3.2:3b",
  • "truncated": true,
  • "toolRouting": {
    }
}

Executa um turno de LLM com a resposta em streaming

Mesma semântica de llm-turn, entregue quadro a quadro. O quadro done traz o usage — sem ele o turno sairia sem contabilidade.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agentId
string
required
Lista de objects
Lista de objects
catalogoCompleto
boolean

Pede o catálogo INTEIRO de ferramentas: o roteador de ferramentas do Jev (ADR 0179) é pulado nesta chamada. O engine o liga quando repete um passo cujo menu restrito fez o modelo responder sem chamar ferramenta.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agentId": "criativo",
  • "messages": [
    ],
  • "tools": [
    ],
  • "catalogoCompleto": true
}

Propõe subir o teto de paralelismo de uma área

Recusa propor teto igual ou menor que o atual: a Anamnese roda periodicamente e repropria a mesma coisa a cada rodada, enchendo de ruído uma fila que o usuário precisa ler.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
area
required
string

A área cujo teto subiria.

proposto
required
number >= 1

O teto proposto. Tem de ser MAIOR que o atual — propor o mesmo ou menos vira ruído numa fila que o usuário precisa ler, e a Anamnese roda periodicamente.

rationale
required
string

Ancorado em DECISÕES OBSERVADAS, não numa impressão.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "area": "dev",
  • "proposto": 4,
  • "rationale": "You authorized the same request four times in this window, and none was denied."
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z"
}

Declara uma versão nova dos contratos entre módulos

O artefato É o evento artifact.module_contracts: imutável, versionado e com autor, ao lado de artifact.module_map. Cada chamada leva a lista INTEIRA e substitui a versão anterior. O que um módulo consome não se escreve aqui: é o dependsOn do module_map vigente.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
required
Lista de objects (ContratoDeModuloInternalDto)

A lista INTEIRA de contratos: cada chamada é uma versão nova que substitui a anterior. O que um módulo CONSOME não está aqui — é derivado do dependsOn do module_map vigente na leitura.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "contratos": [
    ]
}

Exemplos de resposta

Content type
application/json
{
  • "contratos": [
    ],
  • "version": 1
}

Publica uma versão nova do module_map

O histórico é imutável: cada publicação é uma versão a mais, e a vigente é a de maior version. CICLO de dependência entre módulos faz o mapa ser RECUSADO com 400 — o grafo precisa ser acíclico.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
required
Lista de objects

Grafo de módulos. Um CICLO faz o mapa ser recusado com 400 — a validação é de domínio. Cada módulo pode declarar resources (cpus, memoryMb, pidsLimit — os três ou nenhum); declaração parcial, valor acima do teto do container ou SOMA dos módulos acima dele também é 400 (RN-683).

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "modules": [
    ]
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000MODULEMAP00000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "modules": [
    ],
  • "version": 3,
  • "createdAt": "2026-07-24T16:00:00.000Z"
}

Roteia cada módulo do module_map vigente para uma imagem candidata

O artefato É o evento artifact.module_routing: imutável, versionado e com autor, ao lado de artifact.module_map/artifact.project_image/artifact.c4_diagram. Cada item é validado com a mesma régua de choose_project_image (tag/digest explícito, latest recusado, rationale não trivial); nome de módulo fora do module_map vigente, lista vazia ou módulo repetido são recusados com 400.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
required
Lista de objects (RoteamentoDeModuloInternalDto)

Um item por módulo do module_map vigente. A imagem candidata é o Arquiteto propondo, não decidindo — a Infra elege entre as candidatas num passo posterior.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "roteamento": [
    ]
}

Exemplos de resposta

Content type
application/json
{
  • "roteamento": [
    ],
  • "version": 1
}

A sessão tem trabalho pendente que impede fechá-la?

Consultada pelo SessionServer do engine no timeout de heartbeat. pending: true faz o timeout ser reagendado em vez de fechar, e o motivo vai para o log do engine — sessão que não fecha sem dizer por quê é indiagnosticável.

Authorizations:
service-token
path Parameters
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "pending": true,
  • "motivo": "handoff po → arquiteto aguardando aceite",
  • "aguardandoUsuarioDesde": "2026-09-18T12:00:00.000Z"
}

Registra os perfis de proficiência derivados na rodada

Competência fora do catálogo é RECUSADA, e evidência que cita evento de outro projeto também — as duas validações existem porque o modelo erra as duas coisas.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
windowFrom
required
string <date-time>
windowTo
required
string <date-time>
eventCount
required
number
required
Lista de objects (ProficiencyDraftDto)

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "windowFrom": "2026-07-27T12:00:00.000Z",
  • "windowTo": "2026-07-27T12:15:00.000Z",
  • "eventCount": 240,
  • "profiles": [
    ]
}

Exemplos de resposta

Content type
application/json
{
  • "runId": "01JC4Z0000RODADA00000000001",
  • "profiles": [
    ]
}

Define a imagem de container do projeto

O artefato É o evento artifact.project_image: imutável, versionado e com autor. Revisar é emitir versão nova, nunca sobrescrever. Enquanto não houver uma, o container do projeto não sobe e a aba Código responde 409.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
image
required
string

Referência OCI com TAG ou digest explícito. latest é RECUSADO com 400 — a regra é de domínio.

rationale
required
string

Por que esta imagem. Mínimo de 10 caracteres.

network
string
Padrão: "none"
Valores: "none" "egress"

A postura de rede do container. none é o padrão, e é o que torna "lá dentro, o agente é livre" uma frase segura.

object

Teto de recursos. Acima do máximo, a decisão é RECUSADA, nunca rebaixada em silêncio.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "image": "node:22-bookworm-slim",
  • "rationale": "The module_map is TypeScript on Node 22; the slim variant has the runtime and nothing else.",
  • "network": "none",
  • "resources": {
    }
}

Exemplos de resposta

Content type
application/json
{
  • "decisao": {
    },
  • "version": 1,
  • "containerDePe": {
    }
}

Monta o contexto de uma rodada do Psicólogo

alreadyAnalyzed é o que dá IDEMPOTÊNCIA ao caminho automático: com true o worker encerra cedo sem gastar token. As hipóteses anteriores vêm junto para a rodada não se repetir.

Authorizations:
service-token
path Parameters
sessionId
required
string
query Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "alreadyAnalyzed": false,
  • "sessionStatus": "closed_abnormally",
  • "terminationReason": "heartbeat_timeout",
  • "businessRules": [
    ],
  • "priorHypotheses": [
    ]
}

Avisa quando uma regra de negócio recém-escrita parece com uma existente

Vetoriza o título e os títulos das regras do projeto (as 100 mais recentes) com o modelo de embedding do RAG e avisa com cosseno ≥ o limiar. Nunca recusa. Sem provider de embedding a checagem é PULADA com o motivo, narrado também no event log. O gasto de embedding é medido como linha própria de token_usage (ator system/duplicata-semantica).

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
kind
required
string
Valor: "business_rule"
title
required
string

Título da regra RECÉM-acrescentada. Regras com o mesmo título normalizado (a RN-080 faz dela a nova) ficam fora da comparação.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "kind": "business_rule",
  • "title": "Greeting with the caller name"
}

Exemplos de resposta

Content type
application/json
{
  • "status": "warned",
  • "similarTo": {
    },
  • "closest": {
    },
  • "similarity": 0.83,
  • "threshold": 0.8,
  • "compared": 12,
  • "total": 12,
  • "reason": "provider \"ollama\" did not answer",
  • "message": "string"
}

Cria uma história com requisitos funcionais/não funcionais, DoD, DoR e regras cobertas

businessRuleIds é o que alimenta a cobertura regra→história. Cada id tem de referenciar um evento artifact.business_rule que EXISTE — a validação recusa id inventado. A resposta traz também semanticDuplicate (RN-681): um AVISO por embedding contra as histórias do projeto, nunca uma recusa.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
epicId
required
string <uuid>
title
required
string
description
string
rf
Lista de strings
rnf
Lista de strings
dod
Lista de strings
dor
Lista de strings
businessRuleIds
Lista de strings

Cada id precisa referenciar um evento artifact.business_rule que EXISTE — id inventado é recusado.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "businessRuleIds": [
    ]
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z",
  • "semanticDuplicate": {
    }
}

Arquiva uma história em rascunho

A história e suas tarefas saem do backlog, da cobertura, do plano e do claim; a linha fica e backlog.story_archived a registra, com o PO como ator (RN-727).

Authorizations:
service-token
path Parameters
storyId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
reason
string

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "reason": "Duplicate of \"Register a user\"."
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z"
}

Completa uma história em rascunho existente em vez de recriá-la

businessRuleIds é SOMADO às regras já ligadas; listas não vazias substituem as atuais e listas omitidas ficam. Depois de gravar, a história é promovida pelo MESMO critério da criação de história (ready no modo auto, proposedReady no manual) (RN-720).

Authorizations:
service-token
path Parameters
sessionId
required
string
storyId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
description
string
rf
Lista de strings
rnf
Lista de strings
dod
Lista de strings
dor
Lista de strings
businessRuleIds
Lista de strings

SOMADO às regras que a história já cita (completar nunca desliga uma regra); cada id novo tem de referenciar um artifact.business_rule existente.

questionId
string <uuid>

RN-859 (ADR 0214): uma pergunta aberta que o usuário JÁ respondeu — só então uma história ready (sem tarefa em execução) pode ser corrigida.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "description": "As a buyer, I want to pay by card.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "businessRuleIds": [
    ],
  • "questionId": "ffa0420e-f70b-4e5b-99a0-434bff860467"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z"
}

Corrige o título e/ou a descrição de uma história em rascunho

Só história draft sem tarefa em execução; grava backlog.story_updated com o PO como ator (RN-727). Uma ready também, quando questionId cita uma pergunta aberta que o usuário já respondeu (RN-859).

Authorizations:
service-token
path Parameters
storyId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
title
string
description
string
questionId
string <uuid>

RN-859 (ADR 0214): uma pergunta aberta que o usuário JÁ respondeu — só então uma história ready (sem tarefa em execução) pode ser corrigida.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "title": "Register a user",
  • "description": "As a visitor, I want to sign up.",
  • "questionId": "ffa0420e-f70b-4e5b-99a0-434bff860467"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z"
}

Associa uma história aos módulos que ela toca

Esta é a validação cruzada: módulo que não existe no mapa vigente vira pendência de arquitetura em vez de passar despercebido.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
storyId
required
string <uuid>
moduleIds
required
Lista de strings

Nomes do module_map vigente. Módulo que não existe vira pendência de arquitetura.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "moduleIds": [
    ]
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z"
}

Cria uma tarefa dentro de uma história

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
storyId
required
string <uuid>
title
required
string
description
string

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "title": "Endpoint POST /cart/items",
  • "description": "Accepts SKU and quantity; validates stock."
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000TAREFA00000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "title": "POST /cart/items endpoint",
  • "description": "Accepts SKU and quantity; validates stock.",
  • "status": "in_progress",
  • "assignedTo": "dev-api",
  • "blocked": false,
  • "blockedReason": null,
  • "blockedOrigin": null,
  • "gateStatus": null,
  • "gateCorrectionCount": 0,
  • "module": "api",
  • "createdAt": "2026-07-25T10:00:00.000Z",
  • "updatedAt": "2026-07-25T12:30:00.000Z"
}

Marca a tarefa como bloqueada, com o motivo

Não há desbloqueio automático: quem desbloqueia é uma pessoa, pela rota humana. É isso que impede um agente de girar indefinidamente.

Authorizations:
service-token
path Parameters
sessionId
required
string
taskId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agentId
required
string
reason
required
string
diagnosis
required
string

Diagnóstico em texto livre — um detalhe humano do que aconteceu, não a origem estruturada da falha.

origin
string
Valores: "infra" "modelo" "codigo" "politica"

A ORIGEM da falha: infra, modelo, codigo ou politica. Nunca por eliminação — é a lição do ADR 0020, levada um nível acima pelo QA Lead no ADR 0038. Opcional: nem todo ponto de chamada sabe a origem.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agentId": "dev-api",
  • "reason": "Gate correction cap reached.",
  • "diagnosis": "Correction cycle exhausted without exit 0.",
  • "origin": "infra"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000TAREFA00000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "title": "POST /cart/items endpoint",
  • "description": "Accepts SKU and quantity; validates stock.",
  • "status": "in_progress",
  • "assignedTo": "dev-api",
  • "blocked": false,
  • "blockedReason": null,
  • "blockedOrigin": null,
  • "gateStatus": null,
  • "gateCorrectionCount": 0,
  • "module": "api",
  • "createdAt": "2026-07-25T10:00:00.000Z",
  • "updatedAt": "2026-07-25T12:30:00.000Z"
}

Abre o pipeline de gates da tarefa, começando por QA

Chamada quando a PR do dev agent está pronta para revisão.

Authorizations:
service-token
path Parameters
sessionId
required
string
taskId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agentId
required
string

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agentId": "dev-api"
}

Exemplos de resposta

Content type
application/json
{
  • "gateStatus": "awaiting_qa"
}

Move o estado da tarefa conforme o trabalho avança

Authorizations:
service-token
path Parameters
sessionId
required
string
taskId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agentId
required
string

Só o agente que reivindicou a tarefa pode movê-la.

status
required
string
Valores: "todo" "in_progress" "in_review" "done"

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agentId": "dev-api",
  • "status": "in_review"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000TAREFA00000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "title": "POST /cart/items endpoint",
  • "description": "Accepts SKU and quantity; validates stock.",
  • "status": "in_progress",
  • "assignedTo": "dev-api",
  • "blocked": false,
  • "blockedReason": null,
  • "blockedOrigin": null,
  • "gateStatus": null,
  • "gateCorrectionCount": 0,
  • "module": "api",
  • "createdAt": "2026-07-25T10:00:00.000Z",
  • "updatedAt": "2026-07-25T12:30:00.000Z"
}

Desbloqueia uma tarefa depois de uma falha transitória de rede/provider

Chamada pelo job de retentativa do engine (até 3 vezes, depois de 1, 3 e 10 min). Mesmo caso de uso do desbloqueio humano, com ator system; tarefa que não está mais bloqueada fica intocada.

Authorizations:
service-token
path Parameters
sessionId
required
string
taskId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
agentId
required
string

O dev agent cuja falha transitória agendou a retentativa.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "agentId": "dev-api"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000TAREFA00000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "title": "POST /cart/items endpoint",
  • "description": "Accepts SKU and quantity; validates stock.",
  • "status": "in_progress",
  • "assignedTo": "dev-api",
  • "blocked": false,
  • "blockedReason": null,
  • "blockedOrigin": null,
  • "gateStatus": null,
  • "gateCorrectionCount": 0,
  • "module": "api",
  • "createdAt": "2026-07-25T10:00:00.000Z",
  • "updatedAt": "2026-07-25T12:30:00.000Z"
}

Reivindica atomicamente a próxima tarefa reivindicável do módulo

ATÔMICA por desenho: com vários dev agents no mesmo módulo, dois claims concorrentes não podem devolver a mesma tarefa. Sem tarefa disponível, devolve vazio em vez de erro.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
module
required
string

Só tarefas deste módulo entram no sorteio.

agentId
required
string

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "module": "api",
  • "agentId": "dev-api"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000TAREFA00000000001",
  • "storyId": "01JC4Z0000HISTORIA000000001",
  • "title": "POST /cart/items endpoint",
  • "description": "Accepts SKU and quantity; validates stock.",
  • "status": "in_progress",
  • "assignedTo": "dev-api",
  • "blocked": false,
  • "blockedReason": null,
  • "blockedOrigin": null,
  • "gateStatus": null,
  • "gateCorrectionCount": 0,
  • "module": "api",
  • "createdAt": "2026-07-25T10:00:00.000Z",
  • "updatedAt": "2026-07-25T12:30:00.000Z"
}

Lista as tarefas em andamento do projeto seguradas por um dev agent

Não bloqueadas e fora dos gates de PR; vazio a menos que a sessão seja de execução. Usada pelo engine ao parar uma execução, para bloquear as que nenhum dev agent vivo segura.

Authorizations:
service-token
path Parameters
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Relata que o processo da sessão terminou no engine

Só chegam aqui os encerramentos que a api NÃO causou — crash, kill, heartbeat_timeout, desligamento defensivo. Uma parada planejada pela própria api não passa por aqui: o engine já soube dela pela outbox, e relatá-la de volta seria eco.

Authorizations:
service-token
path Parameters
sessionId
required
string
Request Body schema: application/json
required
projectId
required
string <uuid>
to
required
string
Valores: "closing" "closed" "closed_abnormally"

closing NÃO é terminal: quer dizer "estou liberando esta sessão". Se outra réplica a adota, ela continua viva; se ninguém a adota antes do timeout, o drain manda closed_abnormally. created e active ficam de fora porque entrar neles é decisão da api, nunca do engine relatando um encerramento.

reason
string

A ORIGEM do encerramento, não um diagnóstico por eliminação.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "to": "closed_abnormally",
  • "reason": "heartbeat_timeout"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

llm

Lista o que cada provider de LLM sabe fazer, independente do modelo

A camada de PROVIDER das capabilities (ADR 0041) para os nove providers, lida das mesmas instâncias que servem as chamadas. Uma capability só é true quando provada contra a API real. A tela lê routingPreference daqui antes de oferecer preferência de roteamento num binding (ADR 0166).

Authorizations:
bearer

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Resolve qual modelo um agente usa, e de onde veio

Cascata agente → área → projeto → workspace, SEM sessão: é a configuração do agente no projeto, não a de uma conversa específica. origin: "agent" quer dizer que este agente DIVERGIU do padrão da área; qualquer outra origem quer dizer que ele herda.

Authorizations:
bearer
path Parameters
projectId
required
string
agentSlug
required
string
Exemplo: dev-api

Respostas

Exemplos de resposta

Content type
application/json
{
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "origin": "project",
  • "routingPreference": null,
  • "skipped": [
    ],
  • "herdadoDoLead": "secops"
}

Fixa o modelo de um agente NESTE projeto

Vale para toda sessão deste projeto que não tem binding próprio, e só para elas — antes do ADR 0064 o binding era global e alcançava outros projetos também. É assim que se dá um modelo barato ao Psicólogo e um caro ao Arquiteto no mesmo projeto, e também é como um agente DIVERGE do padrão da área.

Authorizations:
bearer
path Parameters
projectId
required
string
agentSlug
required
string
Exemplo: dev-api
Request Body schema: application/json
required
modelId
required
string <uuid>

Modelo a fixar neste escopo. Tem de existir em GET /models.

routingPreference
string or null
Valores: "price" "throughput" "latency"

Como um HUB escolhe o upstream que serve o modelo (ADR 0166, RN-583). AUSENTE mantém o valor gravado quando o provider do modelo novo o aceita, e o limpa caso contrário; null o limpa; valor para modelo cujo provider não declara a capability routingPreference (GET /llm/provider-capabilities) é recusado com 422. Viaja JUNTO com este binding: nunca cascateia sozinho.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "modelId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "routingPreference": "throughput"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

Faz o agente voltar a herdar o modelo da área

APAGA o binding do agente — não copia o modelo da área para ele. Copiar pareceria igual na tela e não é: viraria uma cópia, e a próxima mudança da área deixaria este agente para trás em silêncio. 404 quando ele já herda.

Authorizations:
bearer
path Parameters
projectId
required
string
agentSlug
required
string
Exemplo: dev-api

Respostas

Quebra o gasto do projeto por agente, nos últimos 30 dias

Janela DESLIZANTE de 30 dias, não o mês civil corrente: é o rótulo que a tela mostra, e com mês civil a estimativa despencaria no dia 1º por virar a página, não por mudança de uso. Só conta actor_kind = agent (RN-038). Agente que nunca rodou não aparece na lista — a tela mostra um traço para ele, o que é diferente de zero.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Resolve qual é o modelo padrão de uma área, e de onde veio

O padrão que o lead e os subagentes da área compartilham. origin: "area" quer dizer que alguém o escolheu para esta área; qualquer outra origem quer dizer que a própria área herda do projeto ou do workspace.

Authorizations:
bearer
path Parameters
projectId
required
string
areaKey
required
string
Exemplo: qa

Respostas

Exemplos de resposta

Content type
application/json
{
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "origin": "project",
  • "routingPreference": null,
  • "skipped": [
    ],
  • "herdadoDoLead": "secops"
}

Define o modelo padrão de uma área

Vale para o lead e para todo subagente da área que não tem binding próprio (RN-102). Exige maintainer porque alcança a área inteira de uma vez, e escolher modelo é decidir gasto — o mesmo motivo do teto de paralelismo.

Authorizations:
bearer
path Parameters
projectId
required
string
areaKey
required
string
Exemplo: qa
Request Body schema: application/json
required
modelId
required
string <uuid>

Modelo a fixar neste escopo. Tem de existir em GET /models.

routingPreference
string or null
Valores: "price" "throughput" "latency"

Como um HUB escolhe o upstream que serve o modelo (ADR 0166, RN-583). AUSENTE mantém o valor gravado quando o provider do modelo novo o aceita, e o limpa caso contrário; null o limpa; valor para modelo cujo provider não declara a capability routingPreference (GET /llm/provider-capabilities) é recusado com 422. Viaja JUNTO com este binding: nunca cascateia sozinho.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "modelId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "routingPreference": "throughput"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

Faz a área voltar a herdar o modelo do projeto

A área deixa de ter padrão próprio e passa a herdar do projeto (ou do workspace). Agentes que divergiram continuam divergindo: o binding deles é outro, e apagar este não pode decidir por eles.

Authorizations:
bearer
path Parameters
projectId
required
string
areaKey
required
string
Exemplo: qa

Respostas

Lê o orçamento do projeto e quanto já foi gasto

Valores em micro-USD. Exige maintainer — é informação de custo.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000ORCAMENTO000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": null,
  • "limitMicros": 50000000,
  • "spentMicros": 12400000,
  • "policy": "block",
  • "lastThresholdNotified": 70,
  • "createdAt": "2026-07-12T08:00:00.000Z",
  • "updatedAt": "2026-07-27T15:00:00.000Z"
}

Define o teto de gasto do projeto

O limite entra em DÓLARES e é convertido para micro-USD. Com policy=block a chamada que estouraria o teto é RECUSADA, não só registrada.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
limitUsd
required
number >= 0

Teto em DÓLARES — o único lugar do contrato que fala em dólares, porque é o que uma pessoa digita. A api o converte para micro-USD, e as respostas voltam em micro-USD.

policy
required
string
Valores: "block" "allow"

block recusa a chamada que estouraria o teto; allow a deixa passar e só avisa.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "limitUsd": 50,
  • "policy": "block"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000ORCAMENTO000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": null,
  • "limitMicros": 50000000,
  • "spentMicros": 12400000,
  • "policy": "block",
  • "lastThresholdNotified": 70,
  • "createdAt": "2026-07-12T08:00:00.000Z",
  • "updatedAt": "2026-07-27T15:00:00.000Z"
}

Lê o binding de modelo do projeto

O binding CRU deste escopo — null se o projeto só herda do workspace.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

Define o modelo do projeto

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
modelId
required
string <uuid>

Modelo a fixar neste escopo. Tem de existir em GET /models.

routingPreference
string or null
Valores: "price" "throughput" "latency"

Como um HUB escolhe o upstream que serve o modelo (ADR 0166, RN-583). AUSENTE mantém o valor gravado quando o provider do modelo novo o aceita, e o limpa caso contrário; null o limpa; valor para modelo cujo provider não declara a capability routingPreference (GET /llm/provider-capabilities) é recusado com 422. Viaja JUNTO com este binding: nunca cascateia sozinho.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "modelId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "routingPreference": "throughput"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

Resolve o modelo de vários agentes e áreas numa leitura só

Forma em lote de GET .../agent-bindings/:agentSlug e GET .../area-bindings/:areaKey: cada chave pedida recebe EXATAMENTE o valor que a rota de chave única dela responde (mesma cascata, mesmas origens, null quando nenhum nível tem modelo). Existe para a aba Configurações ler 20 bindings resolvidos com uma requisição em vez de 20 — o rate limit é por USUÁRIO. As chaves são separadas por vírgula, deduplicadas, e chave malformada ou mais de 64 chaves no total é 400, nunca descartada em silêncio.

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
agents
string
Exemplo: agents=criativo,po,dev-lead

Slugs de agente separados por vírgula.

areas
string
Exemplo: areas=dev,qa,infra

Chaves de área separadas por vírgula.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "agents": [
    ],
  • "areas": [
    ]
}

Lista os modelos ativos NO WORKSPACE do projeto

A categoria local são os do Ollama, que não gastam dinheiro; cloud são os de API paga. Modelo que o workspace não ativou não aparece aqui, mas fica nos custos históricos — para vê-lo use a rota do catálogo. A lista é a do workspace DONO do projeto: o mesmo modelo pode estar ligado num workspace e desligado no vizinho (ADR 0049).

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "local": {
    },
  • "cloud": {
    }
}

Lê o orçamento da sessão e o gasto acumulado

É isto que alimenta o medidor de tokens ao vivo da tela de sessão.

Authorizations:
bearer
path Parameters
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000ORCAMENTO000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": null,
  • "limitMicros": 50000000,
  • "spentMicros": 12400000,
  • "policy": "block",
  • "lastThresholdNotified": 70,
  • "createdAt": "2026-07-12T08:00:00.000Z",
  • "updatedAt": "2026-07-27T15:00:00.000Z"
}

Define o teto de gasto da sessão

Mesma conversão de dólar para micro-USD do orçamento do projeto.

Authorizations:
bearer
path Parameters
sessionId
required
string
Request Body schema: application/json
required
limitUsd
required
number >= 0

Teto em DÓLARES — o único lugar do contrato que fala em dólares, porque é o que uma pessoa digita. A api o converte para micro-USD, e as respostas voltam em micro-USD.

policy
required
string
Valores: "block" "allow"

block recusa a chamada que estouraria o teto; allow a deixa passar e só avisa.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "limitUsd": 50,
  • "policy": "block"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000ORCAMENTO000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": null,
  • "limitMicros": 50000000,
  • "spentMicros": 12400000,
  • "policy": "block",
  • "lastThresholdNotified": 70,
  • "createdAt": "2026-07-12T08:00:00.000Z",
  • "updatedAt": "2026-07-27T15:00:00.000Z"
}

Conversa com o modelo da sessão, com a resposta em streaming

Server-Sent Events. Quadros delta levam o texto incremental e done fecha com a contabilidade de tokens e custo. Um quadro metering_failed quer dizer que a RESPOSTA saiu mas o custo não foi contabilizado — a falha aparece em vez de sumir. Se o orçamento estourar com policy=block, o stream leva error e nenhum delta. Esta rota NÃO leva agente: manda o texto sozinho ao modelo vinculado, sem histórico e sem prompt de sistema. Numa sessão consultiva onde nenhum agente foi ativado ela é recusada antes de qualquer efeito (RN-682) — converse com um agente por .../agents/:agent/message.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
text
required
string

A mensagem do usuário. A resposta volta como stream SSE.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "text": "Summarize what we have already decided about checkout."
}

Resolve qual modelo a sessão usa, e de onde veio

Devolve o binding RESOLVIDO pela cascata, não o binding cru da sessão: sessão sem binding próprio usa o do projeto, e responder null aqui seria a resposta errada para a pergunta certa. O campo origin diz de qual escopo veio o valor.

agentId é opcional e é o agente REALMENTE ativo na sessão agora (o mesmo que RunLlmTurnUseCase usa para rodar o turno) — sem ele, a cascata só enxerga sessão→projeto→workspace (mais o fallback fixo ao Criativo) e nunca reflete PO/Arquiteto/Dev Lead/área depois de um handoff.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
query Parameters
agentId
string

Agente ativo agora nesta sessão (ex.: "po", "arquiteto", "dev-lead").

Respostas

Exemplos de resposta

Content type
application/json
{
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "origin": "project",
  • "routingPreference": null,
  • "skipped": [
    ],
  • "herdadoDoLead": "secops"
}

Fixa o modelo desta sessão

Vence todo o resto da cascata enquanto a sessão viver.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
modelId
required
string <uuid>

Modelo a fixar neste escopo. Tem de existir em GET /models.

routingPreference
string or null
Valores: "price" "throughput" "latency"

Como um HUB escolhe o upstream que serve o modelo (ADR 0166, RN-583). AUSENTE mantém o valor gravado quando o provider do modelo novo o aceita, e o limpa caso contrário; null o limpa; valor para modelo cujo provider não declara a capability routingPreference (GET /llm/provider-capabilities) é recusado com 422. Viaja JUNTO com este binding: nunca cascateia sozinho.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "modelId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "routingPreference": "throughput"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

Quebra o gasto da sessão por agente

O dado sempre esteve em token_usage, mas sem agregação nem rota o painel do time não tinha como mostrar o custo por card. Mesmo papel exigido pelo orçamento da sessão.

Authorizations:
bearer
path Parameters
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Meu próprio consumo neste projeto, por sessão e por dia

O público do MEMBRO. Só as linhas do próprio chamador — o ator vem do token autenticado e não há parâmetro para trocá-lo. Em tokens e custo ESTIMADO, sem quebrar por provider nem por credencial: a chave que rodou é a do owner (RN-058) e a fatura dela é dele (RN-060). O eixo de provider passou a existir no relatório do owner (ADR 0076) e continua inalcançável daqui — não há parâmetro de dimensão nesta rota, e o tipo do repositório recusa a combinação (RN-187). Agente não conta: token_usage registra quem gastou, não quem mandou gastar.

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
dias
string

Janela deslizante. Padrão 30, máximo 180.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "projectId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "dias": 30,
  • "actorId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "totalMicros": 1250000,
  • "assinaturaMicros": 0,
  • "inputTokens": 120000,
  • "outputTokens": 35000,
  • "chamadas": 42,
  • "porSessao": [
    ],
  • "porDia": [
    ]
}

The project's total spend and cost by agent and area

The MEMBER's view of the PROJECT (RN-953, ADR 0233, revising 0063): total and cost per agent/area, NEVER provider or credential — the route has no dimension parameter and never asks for provider.

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
dias
string

Janela deslizante. Padrão 30, máximo 180.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8",
  • "dias": 30,
  • "totalMicros": 1250000,
  • "assinaturaMicros": 0,
  • "inputTokens": 120000,
  • "outputTokens": 35000,
  • "chamadas": 42,
  • "porAgente": [
    ],
  • "porArea": [
    ]
}

Quanto as chaves do owner gastaram, por provider e por mês

Existe porque a chave que os agentes gastam é a do DONO do workspace (RN-058) — quem paga a fatura precisa ver a fatura. Agrupa por provider porque essa é a unidade da credencial, e separa o que saiu por AGENTE do que saiu por uma pessoa no chat: os dois saem da mesma chave e respondem perguntas diferentes. Não devolve segredo nenhum.

Authorizations:
bearer
path Parameters
workspaceId
required
string
query Parameters
meses
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "workspaceId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "ownerId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "meses": 6,
  • "totalMicros": 1250000,
  • "porProvider": [
    ]
}

Cria um pedido de pull PENDENTE — nada é baixado ainda

Primeiro de dois passos explícitos: esta chamada só registra a intenção, em pending_confirmation. Nada é baixado até uma chamada separada a POST .../pull-requests/:id/confirm — o produto nunca roda um pull automático e silencioso.

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
repoId
required
string

<publisher>/<modelo> no Hugging Face Hub.

estimatedSizeBytes
number

Vem da busca quando o Hub publicou o tamanho — nunca estimado por palpite no cliente.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "repoId": "meta-llama/Llama-3.1-8B-Instruct-GGUF",
  • "estimatedSizeBytes": 4900000000
}

Exemplos de resposta

Content type
application/json
{
  • "id": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "workspaceId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "requestedBy": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "repoId": "meta-llama/Llama-3.1-8B-Instruct-GGUF",
  • "estimatedSizeBytes": null,
  • "status": "pending_confirmation",
  • "confirmedAt": null,
  • "failedReason": null,
  • "createdAt": "2026-08-26T12:00:00.000Z",
  • "updatedAt": "2026-08-26T12:00:00.000Z"
}

Status de um pedido de pull, para o frontend consultar

Authorizations:
bearer
path Parameters
workspaceId
required
string
id
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "workspaceId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "requestedBy": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "repoId": "meta-llama/Llama-3.1-8B-Instruct-GGUF",
  • "estimatedSizeBytes": null,
  • "status": "pending_confirmation",
  • "confirmedAt": null,
  • "failedReason": null,
  • "createdAt": "2026-08-26T12:00:00.000Z",
  • "updatedAt": "2026-08-26T12:00:00.000Z"
}

A segunda confirmação — roda o pull de fato

Move pending_confirmation → confirmed → pulling, chama o daemon do Ollama e, em caso de sucesso, faz upsert do modelo no catálogo (models) e o ativa para ESTE workspace. Em caso de falha o pedido termina em failed com um motivo que declara a origem (infra | modelo | código | política) — nunca falha calada. Esta chamada roda de forma SÍNCRONA durante o pull inteiro (ver o caso de uso para o porquê); use a rota GET abaixo para consultar em vez de segurar esta conexão aberta.

Authorizations:
bearer
path Parameters
workspaceId
required
string
id
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "workspaceId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "requestedBy": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "repoId": "meta-llama/Llama-3.1-8B-Instruct-GGUF",
  • "estimatedSizeBytes": null,
  • "status": "pending_confirmation",
  • "confirmedAt": null,
  • "failedReason": null,
  • "createdAt": "2026-08-26T12:00:00.000Z",
  • "updatedAt": "2026-08-26T12:00:00.000Z"
}

Lists the LLM providers the workspace owner has a key for

The owner of record (workspaces.created_by) is whose key the agents spend (RN-058). Only provider NAMES — never a secret, id or date. ollama (local, no key) never appears.

Authorizations:
bearer
path Parameters
workspaceId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "providers": [
    ]
}

Lê o binding de modelo do workspace

O binding CRU deste escopo. É a raiz da cascata.

Authorizations:
bearer
path Parameters
workspaceId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

Define o modelo padrão do workspace

Vale para todo projeto que não tem binding próprio.

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
modelId
required
string <uuid>

Modelo a fixar neste escopo. Tem de existir em GET /models.

routingPreference
string or null
Valores: "price" "throughput" "latency"

Como um HUB escolhe o upstream que serve o modelo (ADR 0166, RN-583). AUSENTE mantém o valor gravado quando o provider do modelo novo o aceita, e o limpa caso contrário; null o limpa; valor para modelo cujo provider não declara a capability routingPreference (GET /llm/provider-capabilities) é recusado com 422. Viaja JUNTO com este binding: nunca cascateia sozinho.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "modelId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "routingPreference": "throughput"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000BINDING00000000001",
  • "scope": "project",
  • "scopeId": "01JC4Z0000PROJETO0000000001",
  • "modelId": "01JC4Z0000MODELO00000000001",
  • "routingPreference": null,
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "createdAt": "2026-07-11T09:00:00.000Z",
  • "updatedAt": "2026-07-11T09:00:00.000Z"
}

Sets a model's curated billing mark (api | subscription | free)

Same curation level as the pricing route. subscription makes the spend report show the cost apart from the US$ paid (RN-954). Never re-prices the past.

Authorizations:
bearer
path Parameters
modelId
required
string
Request Body schema: application/json
required
billing
required
string
Valores: "api" "subscription" "free"

Respostas

Exemplos de requisição

Content type
application/json
{
  • "billing": "subscription"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000MODELO00000000001",
  • "provider": "anthropic",
  • "name": "claude-opus-4-8",
  • "displayName": "Claude Opus 4.8",
  • "inputPricePerMillionMicros": 15000000,
  • "outputPricePerMillionMicros": 75000000,
  • "contextWindow": 200000,
  • "supportsToolCalling": true,
  • "supportsStreaming": true,
  • "supportsVision": false,
  • "supportsReasoning": true,
  • "generatesImage": false,
  • "reasoningBudget": 2048,
  • "manualPricing": true,
  • "availability": "available",
  • "billing": "api",
  • "lastSeenAt": "2026-07-30T03:00:00.000Z",
  • "createdAt": "2026-07-01T00:00:00.000Z",
  • "updatedAt": "2026-07-01T00:00:00.000Z"
}

Histórico das mudanças de preço de um modelo

A mais recente primeiro. É um log imutável: nunca recebe UPDATE, e a linha traz o par antes/depois para que a auditoria não dependa de reconstruir o "antes" a partir da linha anterior.

Authorizations:
bearer
path Parameters
modelId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Corrige o preço de um modelo

Vale daqui em diante e NUNCA reprecifica o passado: cada linha de token_usage guarda o preço que produziu o custo dela. A mudança fica registrada com o par antes/depois — consultável na rota de histórico.

Authorizations:
bearer
path Parameters
modelId
required
string
Request Body schema: application/json
required
inputPricePerMillionMicros
required
number

Preço por milhão de tokens de ENTRADA, em micro-USD.

outputPricePerMillionMicros
required
number

Preço por milhão de tokens de SAÍDA, em micro-USD.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "inputPricePerMillionMicros": 2500000,
  • "outputPricePerMillionMicros": 10000000
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000MODELO00000000001",
  • "provider": "anthropic",
  • "name": "claude-opus-4-8",
  • "displayName": "Claude Opus 4.8",
  • "inputPricePerMillionMicros": 15000000,
  • "outputPricePerMillionMicros": 75000000,
  • "contextWindow": 200000,
  • "supportsToolCalling": true,
  • "supportsStreaming": true,
  • "supportsVision": false,
  • "supportsReasoning": true,
  • "generatesImage": false,
  • "reasoningBudget": 2048,
  • "manualPricing": true,
  • "availability": "available",
  • "billing": "api",
  • "lastSeenAt": "2026-07-30T03:00:00.000Z",
  • "createdAt": "2026-07-01T00:00:00.000Z",
  • "updatedAt": "2026-07-01T00:00:00.000Z"
}

Liga ou desliga modelos no seletor (em lote)

Curadoria do owner, VALENDO SÓ PARA ESTE WORKSPACE (ADR 0049). Só toca isActive — availability é o que o sync observou no provider, é global, e não muda aqui. Lote inteiro ou nada: id inexistente reprova a chamada sem aplicar linha nenhuma.

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
modelIds
required
Lista de strings <uuid> [ items <uuid > ]

Modelos a ligar ou desligar. Lote inteiro ou nada.

isActive
required
boolean

true faz o modelo aparecer no seletor e poder receber binding novo. Não toca availability, que é o que o sync observou no provider.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "modelIds": [
    ],
  • "isActive": true
}

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Lista o catálogo INTEIRO, inclusive inativos e indisponíveis

A tela de curadoria. Modelo descoberto pelo sync entra como isActive: false e só aparece aqui até alguém ativá-lo; modelo que sumiu do provider vem com availability: "unavailable" e nunca é apagado, porque bindings e histórico de custo apontam para ele. isActive é PARA ESTE workspace (ADR 0049); availability é global, porque é o que o sync observou no provider.

Authorizations:
bearer
path Parameters
workspaceId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "local": {
    },
  • "cloud": {
    }
}

Força agora o sync do catálogo que o job periódico faz

Mesmo caso de uso da rota interna que o engine agenda — o botão de atualizar da tela de curadoria não tem caminho próprio, então nunca há duas reconciliações que possam divergir.

Authorizations:
bearer

Respostas

Exemplos de resposta

Content type
application/json
{
  • "porProvider": [
    ]
}

Marca para que o workspace usa cada modelo (em lote)

O eixo que nenhum catálogo publica: "bom para código" não é capability declarada por provider nenhum, é opinião do operador — e vale SÓ para este workspace (ADR 0049). Eixo independente da ativação: marcar um uso não liga o modelo no seletor, e mudar o uso não desliga o que estava ligado. A lista de usos SUBSTITUI a anterior.

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
modelIds
required
Lista de strings <uuid> [ items <uuid > ]

Modelos a marcar. Lote inteiro ou nada.

uses
required
Lista de strings
Itens Valores: "codigo" "documentacao" "analise" "imagem" "conversa"

The COMPLETE list of uses — replaces the previous one, does not add to it. An empty list unmarks all. A closed vocabulary: a use outside it fails the call, because free text would give code, coding, and código in the same filter.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "modelIds": [
    ],
  • "uses": [
    ]
}

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Quebra o gasto do workspace por modelo, provider, projeto, ator e dia

O público do OWNER. O eixo de PROVIDER voltou (ADR 0076, RN-186) e está aqui, não na rota do membro, porque quebrar por provider é quebrar por CREDENCIAL — e credencial é assunto de quem paga (RN-060). Complementa credential-spend, que continua respondendo a pergunta da FATURA (por mês, com o vínculo à chave que existe hoje). Pessoa e agente também vêm em blocos separados, por actor_kind. Janela deslizante em dias, e a série diária vem DENSA — dia sem gasto entra como zero, senão o sparkline mente sobre o ritmo.

Authorizations:
bearer
path Parameters
workspaceId
required
string
query Parameters
dias
string

Janela deslizante. Padrão 30, máximo 180.

projectId
string

Slice to ONE project of this workspace (RN-952). A project from another workspace answers 404.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "workspaceId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "ownerId": "9b1c2d3e-4f50-4a61-8b72-0c3d4e5f6a7b",
  • "dias": 30,
  • "projectId": { },
  • "totalMicros": 1250000,
  • "assinaturaMicros": 0,
  • "inputTokens": 120000,
  • "outputTokens": 35000,
  • "chamadas": 42,
  • "porModelo": [
    ],
  • "porProvider": [
    ],
  • "porProjeto": [
    ],
  • "porSessao": [
    ],
  • "porAtor": [
    ],
  • "porOwner": [
    ],
  • "porAgente": [
    ],
  • "porDia": [
    ]
}

My own consumption in this workspace, summed by project

The non-owner's global page (RN-953). Only the caller's rows, by PROJECT and by day, without provider or credential.

Authorizations:
bearer
path Parameters
workspaceId
required
string
query Parameters
dias
string

Janela deslizante. Padrão 30, máximo 180.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "workspaceId": "ef0efa32-d1c1-43d4-a5e2-fe7b4f00403c",
  • "dias": 30,
  • "actorId": "d2f1b55c-8cee-4a0d-af57-aebaeff77518",
  • "totalMicros": 1250000,
  • "assinaturaMicros": 0,
  • "inputTokens": 120000,
  • "outputTokens": 35000,
  • "chamadas": 42,
  • "porProjeto": [
    ],
  • "porDia": [
    ]
}

projetos

Devolve um projeto pelo id

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000PROJETO0000000001",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "name": "Checkout",
  • "slug": "checkout",
  • "workspaceDirName": "checkout-3f2b1c8e",
  • "executionMode": "container",
  • "workspacePath": null,
  • "workspaceVerifiedAt": null,
  • "mirrorPath": null,
  • "language": "pt-BR",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "taskBudgetMicros": 500000,
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "createdAt": "2026-07-21T11:00:00.000Z",
  • "updatedAt": "2026-07-21T11:00:00.000Z"
}

Muda o nome ou o slug do projeto

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
name
string >= 2 characters
slug
string^[a-z0-9]+(-[a-z0-9]+)*$

kebab-case. Único dentro do workspace.

maxConsecutiveBlocked
number

Circuit breaker (Fase 12b — RN-047): quantas tarefas consecutivas terminando bloqueadas param o dev agent do módulo em idle_tripped. Omitido usa o padrão do domínio (DEFAULT_MAX_CONSECUTIVE_BLOCKED). Vale da PRÓXIMA ativação de execução em diante — não afeta agentes já rodando.

storyPromotion
string
Valores: "manual" "auto"

Quem promove uma história de draft para ready (Fase 12c — RN-048). auto (padrão de projeto novo desde a RN-659): história completa já nasce ready, sem passo humano. manual: o PO propõe e VOCÊ decide, na aba Backlog. Mudar o padrão não reescreveu projeto existente nenhum. As validações de domínio (DoD/DoR/RF/regra/módulos) são as MESMAS nos dois modos; o modo só muda quem dispara.

language
string <= 35 characters

O idioma do PROJETO (RN-619) — artefatos compartilhados e turnos sem autor humano o usam. Qualquer código BCP-47 que o servidor reconhece, gravado na forma canônica; um não reconhecido é 400. Omitido, o projeto começa com o idioma de resposta efetivo de quem o criou (RN-618: escolha da conta > detecção confirmada > idioma da interface).

Respostas

Exemplos de requisição

Content type
application/json
{
  • "name": "Checkout",
  • "slug": "checkout",
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "language": "pt-BR"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000PROJETO0000000001",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "name": "Checkout",
  • "slug": "checkout",
  • "workspaceDirName": "checkout-3f2b1c8e",
  • "executionMode": "container",
  • "workspacePath": null,
  • "workspaceVerifiedAt": null,
  • "mirrorPath": null,
  • "language": "pt-BR",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "taskBudgetMicros": 500000,
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "createdAt": "2026-07-21T11:00:00.000Z",
  • "updatedAt": "2026-07-21T11:00:00.000Z"
}

Remove o projeto

Leva junto as sessões, o event log e as ações propostas.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000PROJETO0000000001",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "name": "Checkout",
  • "slug": "checkout",
  • "workspaceDirName": "checkout-3f2b1c8e",
  • "executionMode": "container",
  • "workspacePath": null,
  • "workspaceVerifiedAt": null,
  • "mirrorPath": null,
  • "language": "pt-BR",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "taskBudgetMicros": 500000,
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "createdAt": "2026-07-21T11:00:00.000Z",
  • "updatedAt": "2026-07-21T11:00:00.000Z"
}

Estado do container do projeto (a decisão de imagem vigente)

Enquanto o status é sem_decisao, o container do projeto não sobe e a aba Código responde 409 — esse é o portão da RN-105. Ver o estado exige a mesma permissão de ver o projeto, então viewer.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "status": "sem_decisao",
  • "decisao": {
    },
  • "version": 0,
  • "eventId": "01JC4Z0000EVENTO000000001",
  • "decidedAt": { }
}

Ciclo de vida do container do projeto (estado registrado)

null quando o projeto nunca foi provisionado — o caso comum hoje, porque nenhum orquestrador real transiciona esta tabela ainda (RN-243/RN-267). status/imageVersion/resources são o que foi REGISTRADO; observado é o que o daemon do Docker relata agora, perguntado pelo broker (ADR 0130). Os dois nunca se fundem: um container morto por fora aparece como running registrado e exited observado. Quando não houve como olhar, observado é null e naoObservado diz por quê — ele nunca herda o estado registrado (RN-468).

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "status": "provisioning",
  • "imageVersion": 1,
  • "resources": {
    },
  • "failureReason": null,
  • "createdAt": "2019-08-24T14:15:22Z",
  • "statusChangedAt": "2019-08-24T14:15:22Z",
  • "observado": {
    },
  • "naoObservado": "broker-nao-configurado",
  • "detalheDaObservacao": null
}

Declared network of the container (artifact.container_network)

The current declaration (ports on 127.0.0.1, DNS, extra hosts), or null. It is what was DECLARED; it only takes effect when the container is recreated (container_recreate).

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ports": [
    ],
  • "dns": [
    ],
  • "extraHosts": [
    ],
  • "version": 1
}

Declares the container network (human only)

Emits a new version of artifact.container_network (the current one replaces the previous). Not an external effect: nothing changes in Docker until a container_recreate is approved (AT-608, RN-932). 400 rede_invalida names the field.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
Lista de objects (PortaDto)

Up to 10 TCP ports published on 127.0.0.1 only. host 1024-65535, never an installation port, no duplicates.

dns
Lista de strings

Up to 3 literal IPs.

Lista de objects (HostExtraDto)

Up to 10 --add-host entries: name in [a-z0-9.-], never localhost or an installation service, IPv4 literal.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "ports": [
    ],
  • "dns": [
    ],
  • "extraHosts": [
    ]
}

Exemplos de resposta

Content type
application/json
{
  • "ports": [
    ],
  • "dns": [
    ],
  • "extraHosts": [
    ],
  • "version": 1
}

Converte o modo de execução do projeto

Migra execution_mode/workspacePath de um projeto que JÁ existe (RN-447..450, ADR 0111) — rota dedicada, separada do PATCH, porque orquestra mais do que gravar uma coluna: move o permissions.json para a raiz de escopo nova, aposenta a linha de ciclo de vida do container ao sair do modo container, e recusa (409) enquanto qualquer dev agent do projeto não estiver ocioso, já que um agente rodando não re-resolve sozinho onde está o worktree dele.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
executionMode
required
string
Valores: "container" "mounted" "runner"

O novo modo de execução. Pode repetir o modo atual do projeto — nesse caso, só workspacePath muda de verdade.

workspacePath
string

O caminho absoluto da pasta do usuário — obrigatório quando executionMode é mounted ou runner, recusado quando é container. Mesma validação da criação (RN-170/RN-422/RN-423): em mounted, precisa existir e ser gravável de dentro do container; em runner, só o formato é validado agora — a confirmação de verdade vem do runner conectando de novo.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "executionMode": "runner",
  • "workspacePath": "/home/you/projects/store"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000PROJETO0000000001",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "name": "Checkout",
  • "slug": "checkout",
  • "workspaceDirName": "checkout-3f2b1c8e",
  • "executionMode": "container",
  • "workspacePath": null,
  • "workspaceVerifiedAt": null,
  • "mirrorPath": null,
  • "language": "pt-BR",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "taskBudgetMicros": 500000,
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "createdAt": "2026-07-21T11:00:00.000Z",
  • "updatedAt": "2026-07-21T11:00:00.000Z"
}

Lista os membros do projeto

Só quem foi associado AQUI, com o papel dessa associação — quem alcança o projeto só pelo workspace não tem linha e não aparece.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Associa um usuário ao projeto

Este papel SOBREPÕE o que a pessoa tem no workspace, nos dois sentidos: associar alguém como viewer aqui restringe de fato um developer do workspace neste projeto. Dois movimentos são recusados com 403 e não podem ser habilitados em lugar nenhum: rebaixar um owner do workspace, e mudar o PRÓPRIO papel — para baixo ou para cima, já que a autopromoção é a metade que escala privilégio.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
userId
required
string <uuid>

Id do usuário a associar.

role
required
string
Valores: "viewer" "developer" "maintainer" "owner"

Papel nesta associação. Num PROJETO ele SOBREPÕE o papel de workspace nos dois sentidos — o papel efetivo é este sempre que a associação existe, maior OU menor — e dois movimentos são recusados com 403: rebaixar um owner do workspace, e mudar o próprio papel (em qualquer sentido). Num WORKSPACE é simplesmente o papel, só com o segundo desses tetos: você não muda o seu.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "userId": "3f1b2c8e-5a4d-4b7e-9c10-2d6f8a1b4c33",
  • "role": "developer"
}

Exemplos de resposta

Content type
application/json
{
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "userId": "01JC4Z0000USUARIO0000000002",
  • "role": "maintainer",
  • "createdAt": "2026-07-22T08:05:00.000Z"
}

Desassocia um usuário do projeto

Remove só a associação de PROJETO. Quem tem papel no workspace continua vendo o projeto por herança — e como o papel de projeto SOBREPÕE o de workspace nos dois sentidos, essa herança pode ser MENOR que o que a linha concedia. Remover a própria linha é, por isso, recusado com 403 sempre que o efeito líquido é rebaixamento (inclusive quando não há papel de workspace nenhum); removê-la quando o workspace segura o mesmo papel, e remover qualquer outra pessoa, continuam funcionando.

Authorizations:
bearer
path Parameters
projectId
required
string
userId
required
string

Respostas

Declara (ou limpa) o destino de espelho do projeto

O caminho absoluto, NA MÁQUINA DO USUÁRIO, para onde o agente local copia o trabalho (RN-515, ADR 0147) — uma pasta FORA da base montada, que é toda a razão de o espelho existir. Por projeto e nunca global: um destino global aterrissaria os artefatos do projeto B na pasta do projeto A, e o usuário descobriria pelo conteúdo, não por um erro. mirrorPath: null o LIMPA e desliga o espelho — a chave é obrigatória, omiti-la é 400, porque um corpo que omite o campo seria indistinguível de pedir para limpar. null é o estado NORMAL de um projeto. maintainer, o mesmo mínimo de execution-mode e projects-base: esta rota fala de um caminho no próprio sistema de arquivos do operador. Valida SÓ a forma LÉXICA e recusa, com 400, destino dentro de workspacePath ou que o contenha (os dois sentidos do mesmo laço), e qualquer destino num projeto container. Nunca toca o disco: a API não enxerga a máquina onde o destino vai morar. Gravar o espelho NÃO é proposed_action — é configuração que o usuário declarou, não agente pedindo para agir.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
mirrorPath
required
string or null

O caminho absoluto, NA MÁQUINA DO USUÁRIO, para onde o agente local copia o trabalho do projeto (RN-515, ADR 0147). Mande null — a chave é OBRIGATÓRIA, omiti-la é 400 — para limpar o destino e desligar o espelho; null é o estado normal de um projeto, não um erro. Só projetos mounted/runner podem ter: em container a origem é um volume gerenciado do lado do servidor que o agente local não enxerga, e o pedido é recusado com 400 nomeando esse motivo. A API valida SÓ a forma LÉXICA (absoluto, sem ../., nunca a raiz, pasta de sistema ou sobreposto ao próprio checkout do Brabo) mais os dois sentidos do laço origem↔destino (o destino não pode estar dentro de workspacePath, nem contê-lo) — nunca toca o disco, porque não enxerga a máquina onde o destino vai morar, exatamente como no modo runner (RN-423). Resolver symlinks é a metade da guarda do agente local, não esta.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "mirrorPath": "/home/you/mirrors/store"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000PROJETO0000000001",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "name": "Checkout",
  • "slug": "checkout",
  • "workspaceDirName": "checkout-3f2b1c8e",
  • "executionMode": "container",
  • "workspacePath": null,
  • "workspaceVerifiedAt": null,
  • "mirrorPath": null,
  • "language": "pt-BR",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "taskBudgetMicros": 500000,
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "createdAt": "2026-07-21T11:00:00.000Z",
  • "updatedAt": "2026-07-21T11:00:00.000Z"
}

O que a última rodada de espelho fez (RN-517)

Telemetria que o agente local empurrou pelo canal depois de copiar o trabalho para a pasta do usuário (ADR 0147, ponto 7) — nunca o event log, porque rodada de espelho não tem sessão e session_events.session_id é NOT NULL (o mesmo raciocínio que fez de rag_searches uma tabela). TRÊS respostas que nunca colapsam numa só (RN-088): never (nenhuma rodada relatada), synced (a última rodada copiou — filesCopied pode ser 0, que quer dizer "olhou e não havia nada a copiar") e failed. Uma falha nunca apaga a última sincronização bem-sucedida, e um sucesso nunca apaga o último erro: qual é o CORRENTE sai da comparação dos dois carimbos, então a tela pode dizer "falhando desde hoje, a última cópia boa foi ontem com 412 arquivos". lastDestination é CONGELADO — diverge de mirrorPath depois que alguém troca o destino, porque a concessão viaja no join e só muda quando o runner reconecta (RN-516). viewer, o mesmo mínimo de ler o projeto, que já traz mirrorPath.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "mirrorPath": "/home/you/mirrors/store",
  • "status": "synced",
  • "lastSyncedAt": "2026-09-07T12:04:00.000Z",
  • "filesCopied": 412,
  • "filesSkipped": 3,
  • "filesRefused": 0,
  • "lastDestination": "/home/you/mirrors/store",
  • "lastError": null,
  • "lastErrorAt": null
}

Lê o permissions.json do projeto

É o arquivo físico na raiz do workspace do projeto, não uma coluna do banco.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "allow": [
    ],
  • "deny": [
    ],
  • "ask": [
    ]
}

Reescreve o permissions.json do projeto

Substitui as três listas de uma vez. deny continua vencendo allow na avaliação — não há como liberar por aqui algo negado.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
allow
required
Lista de strings

Padrões aprovados automaticamente.

deny
required
Lista de strings

Padrões proibidos. deny vence allow e vence a autonomia do agente.

ask
required
Lista de strings

Padrões que sempre pedem decisão humana.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "allow": [
    ],
  • "deny": [
    ],
  • "ask": [
    ]
}

Exemplos de resposta

Content type
application/json
{
  • "allow": [
    ],
  • "deny": [
    ],
  • "ask": [
    ]
}

Lista os próprios Personal Access Tokens deste projeto

Nunca inclui o token bruto — só o que já foi emitido.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Emite um Personal Access Token pro runner local

O token bruto (brb_...) só aparece NESTA resposta — não fica recuperável depois, só o hash é guardado. Use em --token/BRABO_ACCOUNT_TOKEN do brabo-runner.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
name
required
string

Nome pra você reconhecer este token depois — não é único.

expiresInDays
number

Expira em N dias. Omitido = sem expiração (revogável a qualquer hora, mas nunca expira sozinho).

Respostas

Exemplos de requisição

Content type
application/json
{
  • "name": "laptop",
  • "expiresInDays": 90
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000PAT000000000001",
  • "name": "laptop",
  • "projectId": "01JC4Z0000PROJETO000000001",
  • "createdAt": "2026-08-22T12:00:00.000Z",
  • "expiresAt": null,
  • "revokedAt": null,
  • "lastUsedAt": null,
  • "token": "brb_9f8a..."
}

Revoga um Personal Access Token próprio

Idempotente — revogar de novo não é erro. Desde a RN-685 (ADR 0201) também DERRUBA as conexões de runner abertas com ESTE token, e só elas — a chave de dispositivo do mesmo usuário fica de pé —, e anula os tickets dele ainda não usados. Engine fora do ar NÃO faz a revogação falhar.

Authorizations:
bearer
path Parameters
projectId
required
string
tokenId
required
string

Respostas

Revoga o Personal Access Token de QUALQUER usuário no projeto

Resposta a incidente — dev desligado com token vazando (RN-427). Idempotente — revogar de novo não é erro. Desde a RN-685 (ADR 0201) também DERRUBA o runner já conectado com este token, e só ele.

Authorizations:
bearer
path Parameters
projectId
required
string
tokenId
required
string

Respostas

Lista TODOS os Personal Access Tokens do projeto, de qualquer usuário

Visão de maintainer para resposta a incidente (RN-427) — inclui o dono de cada token. Nunca inclui o token bruto.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Lista as próprias chaves de dispositivo deste projeto

Ninguém revoga o que não consegue ver (RN-519). Inclui as já REVOGADAS — sumir com a linha faria a tela afirmar que a chave nunca existiu. Nunca devolve a JWK pública, e a privada a api nunca viu. lastUsedAt nulo é o sinal de uma chave ÓRFÃ: registrada e nunca usada por runner nenhum. Desde a RN-543 inclui também as chaves de MÁQUINA do chamador (especie: "maquina", projectId nulo), que servem este projeto sem pertencer a ele — sem elas na lista, uma chave de máquina seria invisível em toda tela.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Revoga uma chave de dispositivo própria

Idempotente — revogar de novo não é erro. Desde a RN-520 também DERRUBA a conexão viva: antes, revogar só impedia ticket NOVO, e um runner já conectado seguia executando comando aprovado. Desde a RN-685 (ADR 0201) o alvo é a CHAVE: caem só as conexões abertas com ela — em todo projeto, se for de máquina —, e outro runner do mesmo usuário, conectado com PAT ou com outra chave, fica de pé. Os tickets dela ainda não usados são anulados. Engine fora do ar ou nenhum runner conectado NÃO fazem a revogação falhar.

Authorizations:
bearer
path Parameters
projectId
required
string
deviceKeyId
required
string

Respostas

Emite um ticket de uso único para o runner local conectar

Autentica connect/3 do socket Phoenix /runner (tópico terminal:<projectId>, papel "runner") — NÃO é o JWT reaproveitado, e esta rota em si só aceita um Personal Access Token no lugar do JWT de sessão (ADR 0105). TTL de 30s e uso único. Recusa com 400 se o projeto não estiver no modo "runner" (RN-421): o runner não tem o que servir num projeto cujo código mora no container gerenciado.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ticket": "string",
  • "expiresAt": "2026-08-09T12:00:30.000Z",
  • "engineWsUrl": "ws://localhost:4000/runner"
}

Emite um ticket de uso único para a aba Terminal da web

Mesmo socket /runner, mesmo tópico, papel "terminal" — quem VÊ o terminal (o comando em si só roda de verdade se houver um runner conectado). Vale para qualquer modo de projeto.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ticket": "string",
  • "expiresAt": "2026-08-09T12:00:30.000Z",
  • "engineWsUrl": "ws://localhost:4000/runner"
}

Lista os projetos em modo "runner" que este agente local atende

Autenticada por uma chave de dispositivo de MÁQUINA (ADR 0154) — NUNCA por JWT de sessão, e nunca por uma credencial presa a um projeto, que responde 403. Devolve os projetos em execution_mode: "runner" nos quais o dono da chave alcança pelo menos developer (o mesmo mínimo de POST .../runner-ticket), com o nome da pasta e o estado de verificação de cada um. O agente pergunta em vez de varrer o disco: a base da máquina é do usuário e pode ter pasta que não é projeto nenhum.

Authorizations:
bearer

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Lista todo projeto do workspace e o container dele, se houver

Uma linha por projeto do workspace — desde a RN-521 um projeto que nunca provisionou container está PRESENTE com registrado: null em vez de ausente, porque esta página é o caminho humano para subir o primeiro. O estado observado só é perguntado ao broker para linhas provisioning/running, e só até um orçamento por carga — ver naoVerificado nas linhas puladas, e o ADR 0136 para o raciocínio.

Authorizations:
bearer
path Parameters
workspaceId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

ações

Lista as ações PENDENTES do projeto inteiro, de qualquer sessão

status é pending (o padrão) ou failed. actionType filtra por tipo — ex.: git_merge, para a aba de PRs achar a proposta de merge de uma PR sem saber qual sessão a criou. status=failed EXIGE actionType e lista as ações cuja execução falhou — a aba de PRs lê dali o último merge recusado de cada PR (conflito de merge traz executionResult.conflictingFiles).

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
status
string
Exemplo: status=pending
actionType
string
Exemplo: actionType=git_merge

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Lista a autonomia concedida a cada agente

Só as regras gravadas explicitamente. Agente sem linha aqui cai no padrão do permissions.json do projeto.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Define a autonomia de um agente para um tipo de ação

Upsert por (agente, tipo). NÃO sobrepõe o permissions.json: padrão já em deny continua bloqueado por mais autonomia que se conceda aqui. actionType: "*" é o "modo automático" (RN-153) — autonomia para QUALQUER tipo de ação deste agente; regra específica gravada depois continua vencendo a curinga para aquele tipo.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
agentId
required
string

Slug do agente.

actionType
required
string
Valores: "terminal" "git_commit" "git_push" "pr_open" "spend" "git_repo_create" "git_branch_create" "git_branch_protect" "write_file" "open_adr_pr" "git_merge" "open_infra_pr" "instruction_patch" "parallelize" "raise_max_parallel" "propose_execution_plan" "assess_implementability" "container_start" "container_stop" "container_remove" "container_recreate" "container_start_via_runner" "qa_environment_start" "*"

Tipo de ação, ou "*" para TODO tipo de ação deste agente — o "modo automático" do ApprovalCard (RN-153). Regra ESPECÍFICA sempre vence a curinga: gravar terminal: deny com "*": auto_approve já ligado continua negando terminal.

mode
required
string
Valores: "auto_approve" "require_approval" "deny"

A autonomia deste agente para este tipo. NÃO sobrepõe o permissions.json: padrão em deny continua bloqueado por mais autonomia que o agente tenha.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "agentId": "dev-api",
  • "actionType": "terminal",
  • "mode": "auto_approve"
}

Pagina as ações propostas da sessão

Ordenadas por seq; use nextCursor como afterSeq. latest=true busca a CAUDA em vez disso (as limit ações mais novas, ainda em ordem crescente) e ignora afterSeq. status=pending mantém só as ações esperando decisão — com latest, as pendentes mais novas, para que uma sessão com mais de 200 ações não empurre uma pendente nova para fora da janela (RN-637).

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
query Parameters
afterSeq
string
Exemplo: afterSeq=6
limit
string
Exemplo: limit=50
latest
string
Exemplo: latest=true

Busca a cauda da sessão; ignora afterSeq.

status
string
Exemplo: status=pending

Só pending é suportado.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "items": [
    ],
  • "nextCursor": 7
}

Propõe uma ação com efeito externo

A ação é avaliada contra o permissions.json do projeto na criação. O resolvedPolicy da resposta diz o que a política decidiu: auto_approve já sai executável, require_approval espera decisão humana, e deny nasce recusada. Não há caminho que execute sem passar por aqui.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
actionType
required
string
Valores: "terminal" "git_commit" "git_push" "pr_open" "spend" "git_repo_create" "git_branch_create" "git_branch_protect" "write_file" "open_adr_pr" "git_merge" "open_infra_pr" "instruction_patch" "parallelize" "raise_max_parallel" "propose_execution_plan" "assess_implementability" "container_start" "container_stop" "container_remove" "container_recreate" "container_start_via_runner" "qa_environment_start"

Tipo da ação. Cada tipo tem papel mínimo próprio: git_push, git_merge e git_branch_protect exigem maintainer, o resto developer.

required
object

Quem está propondo.

required
object

Parâmetros da ação, com forma específica do actionType.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "actionType": "terminal",
  • "actor": {
    },
  • "payload": {
    }
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z"
}

Aprova a ação, uma vez

Vale só para esta ação. A decisão fica no event log com o id de quem decidiu.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
actionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z"
}

Aprova a ação e grava o padrão no permissions.json

Além de liberar esta ação, acrescenta o padrão correspondente à lista allow do projeto — ações futuras que casem saem auto_approved sem perguntar. Padrão já em deny continua bloqueado. A aprovação e o padrão são gravados na mesma transação. Clicar numa ação já APROVADA é sucesso idempotente (desfecho: ja_aprovada), gravando o padrão só se ele faltar.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
actionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z",
  • "desfecho": "aprovada",
  • "padraoGravado": true
}

Recusa a ação

O motivo, se dado, fica no event log junto com a decisão.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
actionId
required
string
Request Body schema: application/json
required
reason
string

Fica no event log junto com a recusa. Opcional, mas recomendado.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "reason": "The command would delete the working directory."
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRC",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 7,
  • "actionType": "terminal",
  • "payload": {
    },
  • "status": "pending",
  • "resolvedPolicy": "require_approval",
  • "actor": {
    },
  • "decidedBy": null,
  • "decidedAt": null,
  • "rejectionReason": null,
  • "executionResult": null,
  • "createdAt": "2026-07-27T14:33:10.900Z",
  • "updatedAt": "2026-07-27T14:33:10.900Z"
}

execução

As áreas de agentes do projeto, com o teto de cada lead

O projeto nasce com as três áreas (RN-094), então a lista volta cheia mesmo antes de existir module_map. O que ativar a execução acrescenta são os MEMBROS da área de dev, um por módulo.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Define (ou limpa) o teto de gasto de uma área

Exige maintainer, pelo mesmo motivo do teto de paralelismo: é uma checagem INDEPENDENTE e aditiva ao lado dos orçamentos de projeto e de sessão (ADR 0110) — não é cascata, nem substitui nenhum dos dois. O limite entra em DÓLARES e é convertido para micro-USD no servidor, a mesma convenção do BudgetsController. null limpa o teto.

Authorizations:
bearer
path Parameters
projectId
required
string
key
required
string
Request Body schema: application/json
required
limitUsd
required
object or null >= 0

Teto em DÓLARES para a área — a mesma convenção dólar na entrada, micro-USD na saída dos orçamentos de projeto/sessão (BudgetsController). null LIMPA o teto: a área volta a ilimitada, que também é o padrão de área que nunca teve um.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "limitUsd": 20
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "key": "dev",
  • "leadAgentId": "dev-lead",
  • "maxParallel": 2,
  • "budgetMicros": 20000000,
  • "spentMicros": 4300000,
  • "members": [
    ]
}

Muda o teto de paralelismo de uma área

Exige maintainer, não developer, pelo mesmo motivo de ativar a execução: subir o teto é decidir quanto o produto pode gastar sem perguntar. Vale para os PRÓXIMOS pedidos — o que já aguarda a sua decisão continua aguardando.

Authorizations:
bearer
path Parameters
projectId
required
string
key
required
string
Request Body schema: application/json
required
maxParallel
required
number >= 1

Quantos agentes o lead da área pode ter na sessão SEM pedir a sua autorização. Mínimo 1 — zero não quer dizer "ilimitado", quer dizer configuração inválida, e tratá-lo como ilimitado transformaria um erro de digitação em gasto irrestrito.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "maxParallel": 4
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "key": "dev",
  • "leadAgentId": "dev-lead",
  • "maxParallel": 2,
  • "budgetMicros": 20000000,
  • "spentMicros": 4300000,
  • "members": [
    ]
}

Ativa a fase de execução e sobe um dev agent por módulo

Exige maintainer, não developer, porque as ações de git dos dev agents herdam o papel de QUEM ATIVOU na avaliação de IAM — ativar como developer deixaria os agentes sem conseguir abrir PR. Cada módulo do module_map ganha um agente num worktree isolado.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
taskBudgetMicros
number

Orçamento por tarefa em micro-USD. Omitido usa o padrão do domínio (DEFAULT_TASK_BUDGET_MICROS).

maxGateCorrections
number

Quantas idas e voltas dev↔gate antes de a tarefa virar blocked. É o que impede um agente de gastar o orçamento num laço de correção.

devAgentImpl
string
Valores: "real" "noop"

noop sobe os dev agents SEM LLM, para exercitar a infraestrutura de execução de ponta a ponta sem gastar tokens. Omitido usa real.

terminalAllowPatterns
Lista de strings

Padrões liberados no permissions.json para os dev agents rodarem a suíte de testes. deny continua vencendo qualquer coisa listada aqui.

originSessionId
string

Id da sessão de CHAT de onde veio o clique "ativar execução" — a sessão criativa/consultiva do Dev Lead/PO, nunca a de execução. Omitido (chamador legado, ex.: ativação pela Visão geral sem contexto de sessão) não fecha sessão nenhuma, como antes. Quando dado, ela é fechada no fim — mas só se não tiver handoff/ação/turno pendente (RN-135), e nunca se for a própria sessão de execução.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "taskBudgetMicros": 500000,
  • "maxGateCorrections": 3,
  • "devAgentImpl": "real",
  • "terminalAllowPatterns": [
    ],
  • "originSessionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

Exemplos de resposta

Content type
application/json
{
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "modules": [
    ]
}

Devolve a sessão de execução corrente do projeto, ou nada

A sessão active mais recente que já traz execution.activated — o MESMO critério que activate usa para decidir entre reativar ou criar uma (RN-139). null quando não há execução em andamento. Existe para a aba Executores parar de inferir esta sessão a partir da mais recente do projeto, que muda de sessão em sessão sem pista nenhuma na interface.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

Rearma um dev agent desarmado pelo circuit breaker

Zera o contador de tarefas bloqueadas consecutivas (RN-047) e devolve o agente a tentar reivindicar trabalho. É a única saída de idle_tripped — não há desbloqueio automático.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agentId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

Pede mais um dev agent para um módulo

Passa pelo TETO da área de dev (RN-083): abaixo dele, o agente sobe na hora, no próprio worktree; acima, a resposta é uma proposed_action do tipo parallelize aguardando a sua decisão, e NADA sobe até você decidir. O valor do teto é configurável por lead em Configurações.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
module
required
string

Nome do módulo, como aparece no module_map. Sobe um dev agent dedicado a ele, num worktree isolado.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "module": "api"
}

Exemplos de resposta

Content type
application/json
{
  • "estado": "aguardando_autorizacao",
  • "actionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "ativosNaSessao": 2,
  • "maxParallel": 2,
  • "motivo": "string"
}

Desbloqueia uma tarefa bloqueada

Zera o contador de correções do gate e devolve a tarefa ao agente. É a saída humana do teto de correções — não há desbloqueio automático.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
taskId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

anamnese

Lista as versões de instrução de um agente

A mais recente primeiro, cada uma já trazendo o diff contra a anterior, calculado no servidor.

Authorizations:
bearer
path Parameters
projectId
required
string
agent
required
string
Exemplo: dev-api

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Restaura uma versão anterior da instrução de um agente

O histórico é imutável: restaurar não apaga nada, CRIA uma versão nova com o conteúdo antigo. Exige maintainer porque muda o comportamento do agente dali em diante — mesmo calibre do patch.

Authorizations:
bearer
path Parameters
projectId
required
string
agent
required
string
Exemplo: dev-api
version
required
string
Exemplo: 2

Versão a restaurar.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "agent": "dev-api",
  • "restoredFrom": 2,
  • "toVersion": 5,
  • "cacheInvalidated": true
}

Roda a Anamnese agora, sem esperar o tick

Exige maintainer pelo mesmo motivo da reanálise do Psicólogo: roda o ToolLoop e gasta orçamento real.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

Devolve um evento do projeto pelo id, resolvendo a sessão dele

Diferente da rota de evento por sessão: aqui a sessão não é conhecida. É isto que faz o chip de evidência do perfil cair no evento certo, já que a janela da Anamnese atravessa várias sessões.

Authorizations:
bearer
path Parameters
projectId
required
string
eventId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRB",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 41,
  • "type": "chat.message",
  • "actor": {
    },
  • "payload": {
    },
  • "createdAt": "2026-07-27T14:30:58.512Z"
}

Lista o histórico de instruções de todo agente do projeto

Parte de quem TEM versão no projeto, não de uma lista estática — é isso que faz os dev agents por módulo (dev-api) aparecerem.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Devolve o perfil de proficiência

O PRÓPRIO perfil do usuário por padrão; a visão agregada do time só para quem administra o projeto. Perfil de competência é dado SOBRE a pessoa, e o padrão menos surpreendente é ver o seu.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Apaga o próprio perfil e grava o opt-out

Só o PRÓPRIO perfil de quem chama, nunca o de outra pessoa. O opt-out vem junto porque sem ele a próxima rodada re-derivaria tudo e a exclusão seria cosmética. É viewer de propósito: a perfilagem cobre todos os membros, então exigir developer deixaria um viewer perfilado sem conseguir apagar o próprio.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "deleted": 2,
  • "optedOut": true
}

Reativa a perfilagem do próprio usuário

Desfaz o opt-out. Os perfis voltam a ser derivados a partir da próxima rodada.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "optedOut": false
}

backlog

Devolve o module_map vigente, os ADRs e as pendências

O mapa vigente é o de maior version (o histórico é imutável). As pendências são a validação cruzada história↔mapa: história sem módulo, ou apontando para módulo que não existe.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "moduleMap": {
    },
  • "adrs": [],
  • "pendencies": [
    ],
  • "c4Diagram": {
    }
}

Devolve a árvore épico → história → tarefa

Aninhada e completa, numa chamada só. Histórias ARQUIVADAS (RN-727) não são listadas. O backlog é escrito por agentes, pelas rotas /internal/*.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Calcula a cobertura regra de negócio → histórias

Cruza as regras do projeto com os businessRuleIds das histórias. Regra sem história nenhuma é uma DESCOBERTA — pendência para o PO, não erro.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "rules": [
    ],
  • "uncoveredCount": 2
}

Lista as PRs de infra e o estágio de gate de cada uma

Artefatos do InfraAgent (Dockerfile, compose, CI). Passam pelos MESMOS gates de QA e SecOps das PRs de dev, sem tarefa nem worktree por trás.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Lista as perguntas abertas dos agentes do projeto (RN-858)

O status vem do event log: aberta é um artifact.open_question sem open_question.answered. A mais nova primeiro, teto de 50 com total.

Authorizations:
bearer
path Parameters
projectId
required
string
query Parameters
status
string
Padrão: "open"
Valores: "open" "answered" "all"

Respostas

Exemplos de resposta

Content type
application/json
{
  • "itens": [
    ],
  • "total": 0
}

Responde uma pergunta aberta (RN-858)

Só o autor da sessão onde a pergunta nasceu responde. Grava um decision_record (ator: o usuário, com questionId) e open_question.answered, e pede ao engine para retomar o gate de QA estacionado de cada tarefa afetada (RN-860), em melhor esforço.

Authorizations:
bearer
path Parameters
projectId
required
string
questionId
required
string
Request Body schema: application/json
required
resposta
string

Resposta em texto livre. Mande isto OU aceitarSugestao: true.

aceitarSugestao
boolean

Aceita a sugestão do agente como resposta.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "resposta": "404 for a code that does not exist.",
  • "aceitarSugestao": true
}

Exemplos de resposta

Content type
application/json
{
  • "questionId": "ffa0420e-f70b-4e5b-99a0-434bff860467",
  • "eventId": "string",
  • "sessionId": "string",
  • "pergunta": "string",
  • "sugestao": "string",
  • "afeta": {
    },
  • "autor": "criativo",
  • "criadaEm": "2019-08-24T14:15:22Z",
  • "status": "open",
  • "autorDaSessao": "string",
  • "resposta": {
    }
}

Devolve como rodar o entregável na sua máquina

RN-852 (ADR 0213): o artifact.run_instructions vigente, emitido quando um open_infra_pr com run executa. DECLARADO pelo agente de Infra, nunca verificado na máquina de quem lê. null quando não há.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "command": "cp .env.example .env && docker compose up --build",
  • "urls": [],
  • "envExample": true,
  • "app": {
    },
  • "qa": { },
  • "version": 1,
  • "eventId": "01JC4Z0000EVENTORUNINSTRUC01",
  • "declaredAt": "2026-10-11T12:00:00.000Z"
}

Arquiva uma história em rascunho (RN-727)

A história sai do backlog, da cobertura, da fila de promoção, do plano do Dev Lead e do claim — e as tarefas dela também. Nada é apagado: a linha fica com archivedAt, e backlog.story_archived registra quem, por quê e quais tarefas. Só história draft sem tarefa em execução.

Authorizations:
bearer
path Parameters
projectId
required
string
storyId
required
string
Request Body schema: application/json
required
reason
string

Opcional; gravado em backlog.story_archived.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "reason": "Duplicate of \"Register a user\"."
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z"
}

Devolve uma história recusada ao PO, com o motivo

A história sai da fila de proposta e o motivo vira uma mensagem fixada na sessão do PO — o mesmo padrão de devolver um gate ao dev. Se o PO daquela sessão não está mais de pé, a devolução é gravada mesmo assim: é decisão do usuário e não depende de um agente ouvindo.

Authorizations:
bearer
path Parameters
projectId
required
string
storyId
required
string
Request Body schema: application/json
required
reason
required
string

O motivo é OBRIGATÓRIO: vira uma mensagem fixada na sessão do PO, e uma devolução sem motivo devolve trabalho sem informação.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "reason": "The acceptance criteria don't cover the payment refusal case."
}

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

Corrige o título de uma história em rascunho (RN-727)

Só história draft sem tarefa em execução (in_progress/in_review). Grava backlog.story_updated com o título anterior e o novo. Mesmo papel das outras escritas do backlog (promover/devolver).

Authorizations:
bearer
path Parameters
projectId
required
string
storyId
required
string
Request Body schema: application/json
required
title
required
string

Aparado; de 1 a 200 caracteres.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "title": "Register a user"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000HISTORIA000000001",
  • "epicId": "01JC4Z0000EPICO000000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "title": "Add item to cart",
  • "description": "As a buyer, I want to gather items before paying.",
  • "rf": [
    ],
  • "rnf": [
    ],
  • "businessRuleIds": [
    ],
  • "dod": [
    ],
  • "dor": [
    ],
  • "moduleIds": [
    ],
  • "status": "ready",
  • "proposedReady": true,
  • "returnedReason": "DoD too generic — spell out the acceptance criteria.",
  • "returnedAt": "2026-08-02T14:00:00.000Z",
  • "archivedAt": null,
  • "archivedReason": null,
  • "createdAt": "2026-07-25T09:00:00.000Z",
  • "updatedAt": "2026-07-25T09:40:00.000Z"
}

Promove para `ready` histórias que o PO propôs

O passo humano que o modo manual (padrão desde a Fase 12c) devolve ao usuário: até a promoção, NENHUMA tarefa da história é pegável por dev agent algum. Promover libera o lote de tarefas de uma vez e acorda os agentes ociosos do módulo (Fase 12b). O lote NÃO é tudo ou nada — o que não passou volta como failed com o motivo, e o que passou é promovido.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
storyIds
required
Lista de strings

Ids das histórias a promover para ready. Uma só é um lote de 1. Cada história é validada e promovida por si — uma que falha não bloqueia as outras.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "storyIds": [
    ]
}

Exemplos de resposta

Content type
application/json
{
  • "promoted": [
    ],
  • "failed": [
    ]
}

psicólogo

Lista as hipóteses do Psicólogo sobre os agentes

Cada hipótese cita os eventos que a sustentam (evidenceEventIds) — é isso que a torna auditável em vez de aceita por fé.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Aceita uma hipótese

Move proposed → accepted. NÃO é proposed_action: o Psicólogo é somente leitura e nada aqui tem efeito externo.

Authorizations:
bearer
path Parameters
projectId
required
string
hypothesisId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000HIPOTESE000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "analysisId": "01JC4Z0000ANALISE0000000001",
  • "agenteAlvo": "dev-api",
  • "observacao": "The agent reopened the same task three times.",
  • "hipotese": "The instructions don't say when to consider the task done.",
  • "sugestao": "Add an explicit definition-of-done criterion to the instruction.",
  • "confiancaPercent": 72,
  • "evidenceEventIds": [
    ],
  • "terminationAnalysis": {
    },
  • "status": "proposed",
  • "decidedBy": null,
  • "decidedAt": null,
  • "createdAt": "2026-07-26T18:00:00.000Z",
  • "updatedAt": "2026-07-26T18:00:00.000Z"
}

Descarta uma hipótese

Move proposed → dismissed. Mesmo raciocínio do aceite.

Authorizations:
bearer
path Parameters
projectId
required
string
hypothesisId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000HIPOTESE000000001",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "analysisId": "01JC4Z0000ANALISE0000000001",
  • "agenteAlvo": "dev-api",
  • "observacao": "The agent reopened the same task three times.",
  • "hipotese": "The instructions don't say when to consider the task done.",
  • "sugestao": "Add an explicit definition-of-done criterion to the instruction.",
  • "confiancaPercent": 72,
  • "evidenceEventIds": [
    ],
  • "terminationAnalysis": {
    },
  • "status": "proposed",
  • "decidedBy": null,
  • "decidedAt": null,
  • "createdAt": "2026-07-26T18:00:00.000Z",
  • "updatedAt": "2026-07-26T18:00:00.000Z"
}

Lista as rodadas de análise com faixa e custo real

costMicros é somado do token_usage da rodada. É isso que torna VISÍVEL a diferença de custo entre triagem leve e pesada, em vez de só afirmada — as duas faixas usam modelos de fato diferentes.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Informa se o Psicólogo pode rodar uma análise NOVA hoje

Somente leitura — não tem efeito colateral. enabled: false quer dizer que a pausa é decisão de PRODUTO (não bug): análises e hipóteses existentes não são tocadas por ela.

Authorizations:
bearer

Respostas

Exemplos de resposta

Content type
application/json
{
  • "enabled": false
}

Dispara uma reanálise da sessão

Exige maintainer, não developer, porque roda o ToolLoop de novo e GASTA orçamento real — ao contrário de aceitar ou descartar, que só mexem em estado local. A análise anterior é marcada como superada.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

rag

Cobertura do índice: arquivos/sessões indexados contra o total real

Contagem real (nunca estimada) de arquivos .md sob docs/docs/adr no repositório do projeto contra quantos têm chunk, e das sessões do projeto contra quantas têm chunk. Não inclui "há N minutos" para esses três escopos — não há coluna de carimbo de indexação por escopo, e um número chutado mentiria (mesma régua do ADR 0042 para nota de modelo). local (RN-455) é a única exceção: lastAttachedAt é um MAX(created_at) real sobre aquele escopo, porque upload pelo navegador não tem estado de repositório contra o qual comparar.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "docs": {
    },
  • "adr": {
    },
  • "session": {
    },
  • "local": {
    },
  • "chunksTotal": 0,
  • "chunksWithoutVector": 0
}

Julga um acerto de uma busca como útil ou irrelevante (RN-480)

O único sinal de VERDADE que a medição do RAG tem: latência e taxa de degradação dizem se a busca RODOU, nunca se ACERTOU. Mesmo papel de search — quem pode ler o resultado é quem pode julgá-lo. Votar de novo no mesmo chunk da mesma busca sobrescreve o próprio voto em vez de somar um segundo (único por ator), para a métrica medir acerto e não entusiasmo.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
searchId
required
string <uuid>

O searchId devolvido pela busca que produziu este acerto — nunca inventado pelo cliente.

chunkId
required
string <uuid>

O chunk sendo julgado. Tem de ser um dos acertos que AQUELA busca devolveu, senão 400.

verdict
required
string
Valores: "util" "irrelevante"

Dois valores, não uma escala de 1 a 5: uma escala mais fina convida diferenças de régua entre votantes que nenhuma agregação recupera depois.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
  • "chunkId": "90e1f3df-a8a1-438e-8dd5-10e45398d051",
  • "verdict": "util"
}

Exemplos de resposta

Content type
application/json
{
  • "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
  • "chunkId": "90e1f3df-a8a1-438e-8dd5-10e45398d051",
  • "verdict": "util",
  • "rank": 0
}

Anexa uma pasta local (upload pelo navegador) como referência somente leitura (RN-455, ADR 0113)

Conteúdo de texto já lido pelo navegador (<input webkitdirectory>), nunca um caminho do host — essa distinção é todo o ponto do ADR 0113. Reconstrução completa e idempotente do escopo local: toda chamada o apaga e recria a partir dos arquivos enviados DESTA vez, então reenviar é o mecanismo de ressincronização. Recusa (400) acima dos tetos de quantidade de arquivos/bytes totais em vez de cortar em silêncio — é um gesto único do usuário com um seletor de pasta à frente, não uma varredura em segundo plano. Arquivo individual grande demais ou de extensão não reconhecida é só pulado, nunca reprova o lote.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
folderName
required
string

O nome da pasta como escolhido no navegador — mostrado no painel de cobertura.

required
Lista de objects (LocalFolderFileDto)

Até 500 arquivos. O teto exato de bytes somados (RAG_LOCAL_TOTAL_BYTES_LIMIT) e o allowlist de extensões por arquivo são aplicados pelo caso de uso, não por este DTO — um array de strings individualmente válidas ainda pode somar um payload grande demais.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "folderName": "brabo",
  • "files": [
    ]
}

Exemplos de resposta

Content type
application/json
{
  • "folderName": "string",
  • "filesIndexed": 0,
  • "filesSkipped": 0,
  • "chunksCreated": 0,
  • "embedding": {
    }
}

Reindexa docs/ADRs/sessões do projeto (reconstrução completa idempotente)

"Reindexar agora" do painel de RAG do Chat. Apaga e recria os chunks dos três escopos honestos (RN-219) a partir do estado CORRENTE — não há watcher automático em push/fechamento de sessão (decisão registrada nos ADRs 0079/0080). Pode demorar em projetos com muitas sessões: roda uma passada de indexação por sessão, cada uma possivelmente chamando o provider de embedding em lote.

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "docs": {
    },
  • "sessions": {
    },
  • "embeddingAvailable": true,
  • "embeddingReason": "string"
}

Busca híbrida (vetorial + léxica) sobre os chunks indexados do projeto

Combina similaridade de cosseno (pgvector) com ts_rank léxico (tsvector), cada um de uma consulta independente, mesclados por soma ponderada e cortados pelo limiar (ADR 0080). vectorAvailable: false avisa quando o provider de embedding não respondeu e a busca rodou só com o sinal léxico — nunca finge ter rodado o híbrido completo.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
query
required
string

Entre 2 e 500 caracteres — mesma régua da busca da aba Código.

scopes
Lista de strings
Itens Valores: "docs" "adr" "session" "local"

Quando ausente, busca nos quatro escopos (RN-219/454).

limit
number

De 1 a 10 — quando ausente, usa o teto.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "query": "how does the PR gate work",
  • "scopes": [
    ],
  • "limit": 10
}

Exemplos de resposta

Content type
application/json
{
  • "query": "string",
  • "searchId": "9b1a67f9-9477-48e5-8a6c-11b70245e1d9",
  • "hits": [
    ],
  • "vectorAvailable": true,
  • "vectorUnavailableReason": "string"
}

sessões

Lista as sessões do projeto

Cada item traz technical: true só para a sessão aberta pelo provisionamento do repositório (ligada por repo_bootstraps).

Authorizations:
bearer
path Parameters
projectId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Abre uma sessão no projeto

A sessão nasce em created e é o contêiner de tudo o que os agentes fazem: o event log, as ações propostas e o orçamento de tokens ficam pendurados nela. kind é OBRIGATÓRIO e fica gravado: consultiva só conversa, criativa produz e é a única que aceita execution.activated.

Authorizations:
bearer
path Parameters
projectId
required
string
Request Body schema: application/json
required
kind
required
string
Valores: "consultiva" "criativa"

A intenção da sessão. consultiva é só conversa; criativa é a que produz — abre a ideação com o agente Criativo e é a única que entra em execução. OBRIGATÓRIO: sem ele a resposta é 400, porque o tipo é escolha de quem abre e fica gravado.

name
string <= 80 characters

Nome amigável, opcional. Não substitui a hashtag do id — as telas compõem os dois. Em branco conta como ausente.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "kind": "criativa",
  • "name": "Cart checkout"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

Devolve uma sessão pelo id

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

Define ou limpa o nome amigável da sessão

O nome é rótulo de navegação e NÃO substitui a hashtag do id — as telas compõem os dois, e sem nome degradam para só a hashtag. null ou texto em branco limpa o nome. Não há como mudar o kind: é a intenção de criação, e mudá-lo depois o transformaria em estado.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
name
required
object or null <= 80 characters

O nome novo. null (ou texto em branco) LIMPA o nome e a sessão volta a se identificar só pela hashtag — é o caminho de desfazer, por isso o campo aceita null em vez de exigir uma rota de remoção.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "name": "Cart checkout"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

Resumes the turn an engine restart interrupted

Human gesture, with no cap: the automatic resume happens once at boot (ADR 0226) and this is the button for the rest. The reply is the ACCEPT (the turn goes up in the engine); progress arrives on the session channel. Requires developer.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agent
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

Conta a sessão inteira para o painel de contexto

Regras de negócio, registros de decisão e artefatos por agente contados sobre o log INTEIRO da sessão (a tela lê uma cauda de 200 eventos), mais os arquivos tocados por git_commit/git_push nesta sessão e na sessão de execução que o plano aprovado do Dev Lead dela ativou (RN-828). Desde a RN-844 devolve também os ITENS de regras e decisões (os 50 mais recentes de cada; os totais ficam em regras/decisoes) e os arquivos das PRs abertas nessas sessões, lidos do mesmo diff que a aba de PRs lê, para no máximo 20 PRs por chamada; prsNaoLidas diz quantas ficaram de fora ou falharam. Só leitura; nenhuma tabela nova.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "sessoesLidas": [
    ],
  • "regras": 11,
  • "decisoes": 6,
  • "itensDeRegras": [
    ],
  • "itensDeDecisoes": [
    ],
  • "artefatosPorAgente": [
    ],
  • "arquivosTocados": {
    }
}

Pagina o event log da sessão

O log é IMUTÁVEL e ordenado por seq. A paginação normal é incremental: passe o nextCursor da resposta anterior como afterSeq. latest=true faz o contrário — busca a CAUDA e ignora afterSeq, para uma tela que abre no fim em vez de reconstruir a sessão inteira desde o começo (ADR 0021).

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
query Parameters
afterSeq
string
Exemplo: afterSeq=40

Devolve os eventos com seq maior que este.

limit
string
Exemplo: limit=50
latest
string
Exemplo: latest=true

Busca a cauda do log; ignora afterSeq.

actionId
string
Exemplo: actionId=01JC4Z0000ACAO00000000000001

Só os eventos cujo payload.actionId é esta ação — ex.: o proposed_action.created dela, que traz o reason da política e o scopeRoot que a linha da ação não guarda (RN-614). Combina com os outros parâmetros; o seq deixa de ser contíguo na página, então quem filtra por ação não deve derivar dele contagem de omitidos. Valor vazio é 400.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "items": [
    ],
  • "nextCursor": 41
}

Acrescenta um evento ao log da sessão

Append-only: o seq é atribuído pelo servidor e nada no log é atualizado ou removido depois. Não há endpoint de edição, por desenho.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
type
required
string

Tipo do evento. O inventário completo está em docs/reference/events.md.

required
object (ActorDto)
required
object

Forma livre, específica de cada type.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "type": "chat.message",
  • "actor": {
    },
  • "payload": {
    }
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRB",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 41,
  • "type": "chat.message",
  • "actor": {
    },
  • "payload": {
    },
  • "createdAt": "2026-07-27T14:30:58.512Z"
}

Devolve um evento do log pelo id

Existe para que a evidência das hipóteses do Psicólogo alcance o evento citado não importa em que página ele caiu nem os filtros do feed.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
eventId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRB",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "seq": 41,
  • "type": "chat.message",
  • "actor": {
    },
  • "payload": {
    },
  • "createdAt": "2026-07-27T14:30:58.512Z"
}

Reabre uma sessão encerrada, mantendo tudo o que ela tinha

Só closed/closed_abnormally reabrem, e só para active — closing nunca volta (ADR 0183). A sessão mantém o event log, os artefatos, as perguntas respondidas e os handoffs; o kind não é tocado. Um evento NOVO session.reopened registra o closedAt e o terminationReason anteriores, que a linha limpa. Sessão que traz execution.activated é recusada (sessao_com_execucao): abra uma sessão nova e ative a execução nela. Sem prazo. Exige developer (ADR 0184).

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

O idioma em que os agentes respondem a VOCÊ, nesta sessão

Resolvido para QUEM CHAMA, nunca para a sessão: sobreposição da sessão > escolha da Conta > detectado-e-confirmado > idioma da interface (RN-618). Devolve o vencedor, a origem dele e cada elo da cadeia — e, quando as suas mensagens recentes apontam para outro idioma e a tela deveria perguntar sobre isso, detectionQuestion (RN-624).

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "language": "pt-BR",
  • "origin": "interface",
  • "sessionOverride": null,
  • "account": "automatico",
  • "detected": null,
  • "interfaceLocale": "pt-BR",
  • "detectionQuestion": "es"
}

Fixa (ou solta) o SEU idioma de resposta nesta sessão

Só para quem chama, só nesta sessão (RN-618) — os outros participantes e a sua escolha na Conta não são tocados. null volta a herdar da Conta.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
language
required
string or null <= 35 characters

O idioma em que os agentes respondem a VOCÊ, só NESTA sessão (RN-618) — os outros participantes nunca são afetados. Qualquer código BCP-47 que o servidor reconhece, gravado na forma canônica. Mande null (ou automatico) — a chave é OBRIGATÓRIA — para voltar a herdar da sua Conta.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "language": "en"
}

Exemplos de resposta

Content type
application/json
{
  • "language": "pt-BR",
  • "origin": "interface",
  • "sessionOverride": null,
  • "account": "automatico",
  • "detected": null,
  • "interfaceLocale": "pt-BR",
  • "detectionQuestion": "es"
}

Emite um ticket opaco de uso único para o socket da sessão

O ticket autentica o socket Phoenix session:<id> da sessão, no connect/3 do engine — NÃO é o JWT reaproveitado. TTL de 30s e uso único: toda reconexão (inclusive as automáticas) pede um ticket novo. scope: "heartbeat" exige o papel viewer; scope: "terminal" exige developer, o mesmo papel mínimo das ações de terminal.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
scope
required
string
Valores: "heartbeat" "terminal"

heartbeat exige o papel viewer; terminal exige developer — o mesmo papel mínimo de MIN_ROLE_FOR_ACTION_TYPE.terminal.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "scope": "heartbeat"
}

Exemplos de resposta

Content type
application/json
{
  • "ticket": "string",
  • "expiresAt": "2026-08-09T12:00:30.000Z"
}

Move a sessão para outro estado

A transição é validada pela máquina de estados do domínio, não pelo cliente: created → active → closing → closed | closed_abnormally. Salto inválido é 409.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
status
required
string
Valores: "created" "active" "closing" "closed" "closed_abnormally"

Estado alvo. A máquina de estados recusa salto inválido com 409 — de created só se vai para active, e não há volta de estado terminal.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "status": "closing"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "status": "active",
  • "kind": "criativa",
  • "name": "Cart checkout",
  • "nextSeq": 42,
  • "createdAt": "2026-07-27T14:03:22.187Z",
  • "updatedAt": "2026-07-27T14:31:09.004Z",
  • "closedAt": null,
  • "terminationReason": null,
  • "traceParent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

agentes

Cancela o turno em andamento do agente ativo

O botão "Parar" do composer (RN-122): mata a chamada de LLM em voo no engine, cortando a conexão no meio do stream — economiza tokens de verdade, não só para de renderizar no cliente. Idempotente: sem turno em andamento, é aceito sem efeito.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agent
required
string
Exemplo: po

Slug do agente ativo.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

Envia uma mensagem ao agente ativo

A resposta é só a confirmação, e volta no ACEITE — antes de o turno do agente terminar (ADR 0163). O que o agente responde chega pelo event log e pelo canal da sessão — não por esta chamada. Se o agente está no meio de um turno, a mensagem NÃO é recusada: entra na fila do agente (entrega: "enfileirada") e é lida, com as outras enfileiradas, num turno só quando o atual terminar; pode ser cancelada enquanto espera (RN-673, ADR 0191).

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agent
required
string
Exemplo: po

Slug do agente conversacional que lê a mensagem: criativo, po, arquiteto, dev-lead, ux-designer ou staff. Qualquer outro slug — infra inclusive — é recusado com 422; nunca é entregue a um agente padrão (RN-584).

Request Body schema: application/json
required
text
required
string [ 1 .. 10000 ] characters

Mensagem do usuário ao agente ativo da sessão.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "text": "I want to allow discount coupons at checkout."
}

Exemplos de resposta

Content type
application/json
{
  • "ok": true,
  • "mensagemId": "01JC4Z0000EVENTO000000000001",
  • "entrega": "enfileirada",
  • "posicao": 2
}

Cancela uma mensagem que espera na fila do agente

Mensagem enviada com o agente no meio de um turno espera numa fila e é lida quando o turno termina (RN-673). Enquanto espera, quem a ENVIOU pode cancelá-la: o engine a tira da fila e grava chat.message_cancelled; ela nunca é mostrada ao modelo. Mensagem de outra pessoa é 403.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agent
required
string
Exemplo: po

Slug do agente em cuja fila está a mensagem.

messageId
required
string
Exemplo: 01JC4Z0000EVENTO000000000001

Id do evento chat.message (o mensagemId que a rota de mensagem devolveu).

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

Inicia um agente na sessão

Só o Criativo pode ser iniciado por comando direto. Todo outro agente exige um handoff ACEITO apontando para ele — a regra mora no domínio, não aqui, e tentar contorná-la devolve 409.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agent
required
string
Exemplo: criativo

Slug do agente.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "agent": "po",
  • "status": "active"
}

Responde um conjunto de perguntas estruturadas do agente

Grava chat.structured_question_answered e reenvia as respostas ao agente como mensagem normal. Um conjunto de perguntas só pode ser respondido uma vez. Volta no ACEITE, antes de o turno do agente terminar (ADR 0163): o turno segue rodando no engine e a narração, o fim e as falhas dele chegam pelo canal da sessão e pelo event log (agent.status, agent.response, agent.error) — nunca por esta resposta.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
agent
required
string
Exemplo: criativo

Slug do agente que fez as perguntas (e vai ler a resposta).

questionSetId
required
string
Exemplo: 01JC4Z0000EVENTO000000000001

Id do evento chat.structured_question respondido.

Request Body schema: application/json
required
required
object

Resposta indexada pelo id da pergunta — o mesmo id que veio em chat.structured_question.

property name*
additional property
string

Respostas

Exemplos de requisição

Content type
application/json
{
  • "answers": {
    }
}

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

Confirma que a arquitetura está pronta e oferece o handoff à Infra

Endpoint dedicado em vez de reusar readiness, que é do Criativo: são dois marcos diferentes da sessão, e confundi-los tornaria o event log ambíguo. Volta no ACEITE, antes de o turno do agente terminar (ADR 0163): o turno segue rodando no engine e a narração, o fim e as falhas dele chegam pelo canal da sessão e pelo event log (agent.status, agent.response, agent.error) — nunca por esta resposta. O handoff ao Dev Lead continua vindo DEPOIS do de Infra: o engine o segura até o turno de fechamento terminar. Idempotente (ADR 0182, RN-635): alvo que já tem oferta pendente ou está ativo no projeto não é disparado de novo, e com os dois assim nada é gravado.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ok": true,
  • "desfecho": "confirmado",
  • "jaAtendidos": [
    ]
}

Confirma que a necessidade de negócio do Criativo foi validada

Grava necessity.validated. Exige que o Criativo já tenha consolidado um product_brief nesta sessão (RN-406) — sem ele, é recusado: não há o que validar. Desde o ADR 0185 (RN-657) o clique "Estou pronto — a necessidade está validada" (POST .../readiness) grava ele mesmo este evento, e a web não chama mais esta rota; ela fica para sessões cujo clique de prontidão é anterior a esse ADR.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

Lista os handoffs entre agentes da sessão

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Oferece manualmente um handoff a um agente escolhido

Nasce offered, exatamente como o offer_handoff de um agente — a única diferença é quem decidiu. toAgent tem de estar no catálogo endereçável (lead de área ou agente sem área); subagente ou slug desconhecido é recusado com 400. No máximo uma oferta pendente por (projeto, alvo): ver desfecho (ADR 0182, RN-635).

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
Request Body schema: application/json
required
toAgent
required
string

Slug do agente alvo. Tem de ser um lead ou um agente sem área — nunca um subagente.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "toAgent": "staff"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000HANDOFF00000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "fromAgent": "criativo",
  • "toAgent": "po",
  • "artifactId": "01JC4Z0000ARTEFATO000000001",
  • "status": "offered",
  • "createdAt": "2026-07-24T10:00:00.000Z",
  • "updatedAt": "2026-07-24T10:05:00.000Z",
  • "desfecho": "criado"
}

Aceita um handoff e ativa o agente de destino

Uma coisa só: transicionar para accepted E iniciar o agente de destino. É o caminho normal de ativação de todo agente que não é o Criativo.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string
handoffId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000HANDOFF00000000001",
  • "sessionId": "01JC4Z8QK3M7YV2N5T9B0PXHRA",
  • "projectId": "01JC4Z0000PROJETO0000000001",
  • "fromAgent": "criativo",
  • "toAgent": "po",
  • "artifactId": "01JC4Z0000ARTEFATO000000001",
  • "status": "offered",
  • "createdAt": "2026-07-24T10:00:00.000Z",
  • "updatedAt": "2026-07-24T10:05:00.000Z"
}

Confirma que a sessão de descoberta com o Criativo terminou

É o botão que dispara o product_brief e o handoff ao PO. Grava readiness.confirmed no event log. Volta no ACEITE, antes de o turno do agente terminar (ADR 0163): o turno segue rodando no engine e a narração, o fim e as falhas dele chegam pelo canal da sessão e pelo event log (agent.status, agent.response, agent.error) — nunca por esta resposta.

Authorizations:
bearer
path Parameters
projectId
required
string
sessionId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

credenciais

Stores an LLM API key imported by the local runner

Authenticated by a MACHINE device key (never a session JWT, never a project-bound credential). Same envelope encryption as POST /users/me/credentials. 409 credencial_existente when the user already has this provider and substituir is not true. The key is never logged nor returned.

Authorizations:
bearer
Request Body schema: application/json
required
provider
required
string
Valores: "anthropic" "openai" "openrouter" "nvidia-nim" "together" "deepinfra" "bitdeer" "vultr" "9router" "opencode-zen"
apiKey
required
string <= 512 characters

The API key in plain text. Encrypted before touching the database; NEVER logged and NEVER returned.

origem
required
string <= 200 characters

Tool and path the key was read from. Audit log only; never a value.

substituir
boolean

Must be true to replace an existing credential of this provider.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "provider": "anthropic",
  • "apiKey": "string",
  • "origem": "codex: ~/.codex/auth.json",
  • "substituir": true
}

Exemplos de resposta

Content type
application/json
{
  • "provider": "anthropic",
  • "substituida": true
}

Lista as credenciais do próprio usuário corrente

Nenhum papel exigido: credencial é sobre quem chamou, não sobre um workspace ou projeto. Cobre chaves de LLM e tokens de git na mesma listagem.

Authorizations:
bearer

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Registra ou substitui a API key de um provider

Upsert por (usuário, provider). A chave é cifrada por envelope encryption antes de tocar o banco, e a resposta traz só a PROJEÇÃO — nunca o segredo, nem cifrado.

Authorizations:
bearer
Request Body schema: application/json
required
provider
required
string
Valores: "anthropic" "openai" "openrouter" "nvidia-nim" "together" "deepinfra" "bitdeer" "vultr" "9router" "opencode-zen"
apiKey
required
string <= 512 characters

A chave em texto puro. É cifrada por envelope encryption antes de tocar o banco e NUNCA volta em resposta nenhuma — nem cifrada. O teto de 512 caracteres é proteção contra payload absurdo, não validação de formato: se a chave presta quem responde é o provider, em POST /users/me/credentials/{provider}/test.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "provider": "anthropic",
  • "apiKey": "sk-ant-api03-…"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000CREDENCIAL00000001",
  • "provider": "anthropic",
  • "createdAt": "2026-07-10T10:00:00.000Z",
  • "updatedAt": "2026-07-10T10:00:00.000Z"
}

Remove a credencial de um provider

Idempotente: apagar o que não existe também responde { ok: true }.

Authorizations:
bearer
path Parameters
provider
required
string
Exemplo: anthropic

Respostas

Exemplos de resposta

Content type
application/json
{
  • "ok": true
}

Confere contra o provider a credencial JÁ guardada

A checagem é uma ação explícita, separada do registro (ADR 0050): a api decifra o segredo, chama o provider e devolve SÓ o veredito — a chave nunca volta, nem em parte. Responde 200 para os três desfechos, porque o pedido foi processado; refused é um desfecho, não erro de protocolo. 404 quando não há credencial para (usuário, provider) — aí não há o que testar.

Authorizations:
bearer
path Parameters
provider
required
string
Exemplo: openrouter

Respostas

Exemplos de resposta

Content type
application/json
{
  • "resultado": "recusado",
  • "motivo": "connection test failed for openrouter: openrouter responded 401"
}

Registra um token de git (cifrado, sem testar)

Caminho próprio, não o de users/me/credentials, porque o corpo é diferente (token, e o enum de provider é github/gitlab). O token é cifrado e guardado sem verificação prévia (ADR 0050); para verificá-lo, POST /users/me/credentials/{provider}/test. Leitura, remoção e teste reusam as rotas de users/me/credentials — é a mesma tabela.

Authorizations:
bearer
Request Body schema: application/json
required
provider
required
string
Valores: "github" "gitlab"
token
required
string <= 512 characters

Personal access token. Cifrado por envelope encryption antes de tocar o banco e nunca devolvido, nem cifrado. O registro NÃO testa o token (ADR 0050) — para verificá-lo use POST /users/me/credentials/{provider}/test. O teto de 512 caracteres é proteção contra payload absurdo, não validação de formato.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "provider": "github",
  • "token": "ghp_…"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000CREDENCIAL00000001",
  • "provider": "anthropic",
  • "createdAt": "2026-07-10T10:00:00.000Z",
  • "updatedAt": "2026-07-10T10:00:00.000Z"
}

usuários

Lista as próprias chaves de dispositivo de MÁQUINA do usuário autenticado

Por conta, sem projeto no caminho (RN-611): a instalação de uma linha cria uma chave de máquina antes de existir qualquer projeto, e toda outra listagem é por projeto. Devolve SÓ chaves de máquina (especie: "maquina", projectId: null) e SÓ as do chamador — chaves de projeto ficam na listagem do projeto delas, e ninguém vê chave de outro usuário (RN-519). Chaves revogadas ENTRAM: registrar uma chave de máquina nova revoga a anterior (RN-552), e é nesta lista que isso aparece. lastUsedAt é uso registrado, nunca conexão viva; nulo quer dizer que a chave nunca foi usada.

Authorizations:
bearer

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Revoga uma das próprias chaves de dispositivo de MÁQUINA do usuário autenticado

Idempotente — revogar de novo não é erro. Mesma revogação de DELETE /projects/{projectId}/runner-device-keys/{deviceKeyId}: também derruba as conexões VIVAS abertas com esta chave, em TODO projeto (RN-520/RN-543). Desde a RN-685 (ADR 0201) o alvo é a CHAVE: outro runner do mesmo usuário, conectado com PAT ou com outra chave, fica de pé. Os tickets da chave ainda não usados são anulados. Sem projeto ainda, não há conexão a derrubar. Chave de PROJETO, chave que não existe e chave de outro usuário respondem o mesmo 404.

Authorizations:
bearer
path Parameters
deviceKeyId
required
string

Respostas

Lê o idioma da interface e o idioma de resposta dos agentes do usuário autenticado

Authorizations:
bearer

Respostas

Exemplos de resposta

Content type
application/json
{
  • "locale": "pt-BR",
  • "responseLanguage": "automatico",
  • "detectedLanguage": null,
  • "detectedLanguageConfirmedAt": "2019-08-24T14:15:22Z",
  • "effectiveResponseLanguage": {
    }
}

Grava o idioma da interface e/ou o idioma de resposta dos agentes do usuário autenticado

Os dois campos são opcionais e independentes — mandar um nunca toca o outro, e corpo sem nenhum é 400. locale (a interface) continua fechado à lista pt-BR/en. responseLanguage (RN-618) é automatico ou qualquer código BCP-47 reconhecido, gravado na forma canônica; código não reconhecido é 400 e nada do corpo é gravado.

Authorizations:
bearer
Request Body schema: application/json
required
locale
string
Valores: "pt-BR" "en" "ru" "zh-Hans"

O idioma da interface. Fechado à lista — não é BCP-47 livre.

responseLanguage
string <= 35 characters

O idioma em que os agentes respondem (RN-618): automatico ou QUALQUER código BCP-47 cujo idioma o servidor reconhece — lista aberta, ao contrário de locale. Gravado na forma canônica (pt-br vira pt-BR). Código não reconhecido é um 400 que nomeia a regra. Nunca muda locale.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "locale": "en",
  • "responseLanguage": "es"
}

Exemplos de resposta

Content type
application/json
{
  • "locale": "pt-BR",
  • "responseLanguage": "automatico",
  • "detectedLanguage": null,
  • "detectedLanguageConfirmedAt": "2019-08-24T14:15:22Z",
  • "effectiveResponseLanguage": {
    }
}

Responde a pergunta do idioma detectado

O único jeito de um idioma detectado virar preferência (RN-624): a detecção sozinha nunca muda nada. confirm grava detectedLanguage + detectedLanguageConfirmedAt; decline registra a recusa para o mesmo idioma não ser perguntado de novo. Devolve as preferências depois da resposta.

Authorizations:
bearer
Request Body schema: application/json
required
language
required
string <= 35 characters

O idioma sobre o qual era a pergunta — o detectionQuestion de GET .../sessions/:sessionId/response-language.

answer
required
string
Valores: "confirm" "decline"

confirm o grava como o seu idioma detectado-e-confirmado (ele passa a responder a você onde a sua Conta estiver em automático); 409 deteccao_mudou quando as suas mensagens não apontam mais para ele. decline grava a recusa e este idioma nunca mais é perguntado (confirmá-lo depois limpa a recusa).

Respostas

Exemplos de requisição

Content type
application/json
{
  • "language": "es",
  • "answer": "confirm"
}

Exemplos de resposta

Content type
application/json
{
  • "locale": "pt-BR",
  • "responseLanguage": "automatico",
  • "detectedLanguage": null,
  • "detectedLanguageConfirmedAt": "2019-08-24T14:15:22Z",
  • "effectiveResponseLanguage": {
    }
}

workspaces

Lista os workspaces de quem chama

Já filtrada por associação — não há listagem global. Cada item traz o papel do próprio chamador.

Authorizations:
bearer

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Cria um workspace

Não exige papel: quem cria vira owner. É a única porta de entrada para quem ainda não pertence a workspace nenhum.

Authorizations:
bearer
Request Body schema: application/json
required
name
required
string >= 2 characters
slug
required
string^[a-z0-9]+(-[a-z0-9]+)*$

kebab-case. Único no sistema e visível na URL.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "name": "Acme Corp",
  • "slug": "acme-corp"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000WORKSPACE00000001",
  • "name": "Acme Corp",
  • "slug": "acme-corp",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "toolRouterEnabled": true,
  • "createdAt": "2026-07-20T09:12:00.000Z",
  • "updatedAt": "2026-07-20T09:12:00.000Z"
}

Devolve um workspace pelo id

Authorizations:
bearer
path Parameters
workspaceId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000WORKSPACE00000001",
  • "name": "Acme Corp",
  • "slug": "acme-corp",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "toolRouterEnabled": true,
  • "createdAt": "2026-07-20T09:12:00.000Z",
  • "updatedAt": "2026-07-20T09:12:00.000Z"
}

Muda o nome ou o slug do workspace

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
name
string >= 2 characters
slug
string^[a-z0-9]+(-[a-z0-9]+)*$

kebab-case. Único no sistema e visível na URL.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "name": "Acme Corp",
  • "slug": "acme-corp"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000WORKSPACE00000001",
  • "name": "Acme Corp",
  • "slug": "acme-corp",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "toolRouterEnabled": true,
  • "createdAt": "2026-07-20T09:12:00.000Z",
  • "updatedAt": "2026-07-20T09:12:00.000Z"
}

Remove o workspace

Exige owner. Leva junto os projetos, as sessões e o histórico deles.

Authorizations:
bearer
path Parameters
workspaceId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000WORKSPACE00000001",
  • "name": "Acme Corp",
  • "slug": "acme-corp",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "toolRouterEnabled": true,
  • "createdAt": "2026-07-20T09:12:00.000Z",
  • "updatedAt": "2026-07-20T09:12:00.000Z"
}

Lista os membros do workspace

Quem está associado ao WORKSPACE, com o papel de workspace — o papel que todo projeto herda a menos que uma linha de projeto o sobreponha. Completa GET projects/:projectId/members, que lista só linhas de projeto: quem alcança um projeto só pelo workspace aparece aqui e não lá. Só id, nome, e-mail e papel.

Authorizations:
bearer
path Parameters
workspaceId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Associa um usuário ao workspace

Só owner mexe na lista de membros. O papel aqui é herdado por TODOS os projetos do workspace. Esse papel é NECESSÁRIO mas não SUFICIENTE: mudar o SEU PRÓPRIO papel aqui é recusado com 403 nos dois sentidos, e não pode ser habilitado em lugar nenhum. Não há nível acima para segurar a queda, então um autorrebaixamento seria irrecuperável pela interface. Rebaixar OUTRO owner continua permitido — é o único jeito de revogar propriedade.

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
userId
required
string <uuid>

Id do usuário a associar.

role
required
string
Valores: "viewer" "developer" "maintainer" "owner"

Papel nesta associação. Num PROJETO ele SOBREPÕE o papel de workspace nos dois sentidos — o papel efetivo é este sempre que a associação existe, maior OU menor — e dois movimentos são recusados com 403: rebaixar um owner do workspace, e mudar o próprio papel (em qualquer sentido). Num WORKSPACE é simplesmente o papel, só com o segundo desses tetos: você não muda o seu.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "userId": "3f1b2c8e-5a4d-4b7e-9c10-2d6f8a1b4c33",
  • "role": "developer"
}

Exemplos de resposta

Content type
application/json
{
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "userId": "01JC4Z0000USUARIO0000000002",
  • "role": "maintainer",
  • "createdAt": "2026-07-22T08:00:00.000Z"
}

Desassocia um usuário do workspace

Só owner, como o upsert. Remove a linha do workspace E, na mesma transação, as linhas do usuário em todo projeto deste workspace (o papel de projeto sobrepõe o de workspace, então deixá-las manteria o usuário dentro desses projetos), mais as chaves de dispositivo de PROJETO e os personal access tokens do usuário neles. Depois a conexão de runner viva desse usuário em cada projeto é derrubada, em melhor esforço. Chaves de dispositivo de máquina e sessões abertas ficam como estão — deixam de alcançar este workspace porque o papel resolve para nenhum.

Remover a SI MESMO é recusado com 403 e não pode ser habilitado em lugar nenhum: não há nível acima para segurar a queda. Essa mesma cláusula é o que protege o último owner — só um owner chama esta rota e ninguém se remove, então toda chamada bem-sucedida deixa ao menos quem chamou como owner. Remover OUTRO owner é permitido — é como se revoga propriedade —, exceto o TITULAR (createdBy), recusado com 409 criador_do_workspace até PUT :workspaceId/owner-of-record passá-lo a outro owner: a chave de LLM que os agentes gastam e o relatório de gasto são dele. Idempotente: alvo sem linha de workspace ainda tem as linhas de projeto deste workspace limpas, e recebe 204.

Authorizations:
bearer
path Parameters
workspaceId
required
string
userId
required
string

Respostas

Transfere a titularidade do workspace

O titular é createdBy: de quem é a credencial de LLM que os agentes gastam e a credencial de git que as ações de agente usam (RN-058), e de quem é o relatório de gasto (RN-060). Não concede autorização — quem concede são os papéis. O alvo já tem de ser owner do workspace (senão 409 titular_precisa_ser_owner). A partir do commit, os turnos de agente buscam a credencial do NOVO titular; se ele não tem uma para o provider do modelo, o turno termina com o desfecho de sempre de "nenhuma credencial cadastrada" para aquele provider — esta rota não confere isso antes. Qualquer owner pode chamá-la, inclusive para outro owner. Transferir para o titular atual não faz nada.

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
userId
required
string <uuid>

Id do usuário que vira o titular. Tem de já ser owner deste workspace.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "userId": "3f1b2c8e-5a4d-4b7e-9c10-2d6f8a1b4c33"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000WORKSPACE00000001",
  • "name": "Acme Corp",
  • "slug": "acme-corp",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "toolRouterEnabled": true,
  • "createdAt": "2026-07-20T09:12:00.000Z",
  • "updatedAt": "2026-07-20T09:12:00.000Z"
}

Lista as subpastas de uma pasta dentro da base de projetos

O navegador de pastas do modo Mounted, servido pela api em vez do runner (RN-504). Escopado RIGIDAMENTE a BRABO_PROJECTS_BASE (ADR 0141): path é opcional e tem como padrão a própria base, e qualquer path fora dela é 400 — pedido malformado, não problema de permissão, já que papel nenhum navega fora da base.

Com teto de propósito: só diretórios, no máximo 500 (ordenados ANTES do corte, com truncado dizendo isso), nunca recursivo, entradas com ponto no início excluídas, e symlinks relatados mas nunca seguidos. O que fica de fora é CONTADO (arquivos, simbolicos) para uma pasta cheia de código nunca parecer vazia.

Não há POST irmão: criar pasta é parte de materializar o workspace montado, nunca do navegador.

Authorizations:
bearer
query Parameters
path
string

Caminho absoluto a listar. Omitido quer dizer a própria base. Tem de estar dentro de BRABO_PROJECTS_BASE; .., . e caminhos relativos são recusados de cara em vez de resolvidos.

Respostas

Exemplos de resposta

Content type
application/json
{
  • "base": "/home/voce/brabo",
  • "path": "/home/voce/brabo/clientes",
  • "entries": [
    ],
  • "truncado": false,
  • "arquivos": 12,
  • "simbolicos": 1
}

Lista os projetos do workspace

Authorizations:
bearer
path Parameters
workspaceId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Cria um projeto dentro do workspace

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
name
required
string >= 2 characters
slug
required
string^[a-z0-9]+(-[a-z0-9]+)*$

kebab-case. Único dentro do workspace.

maxConsecutiveBlocked
number

Circuit breaker (Fase 12b — RN-047): quantas tarefas consecutivas terminando bloqueadas param o dev agent do módulo em idle_tripped. Omitido usa o padrão do domínio (DEFAULT_MAX_CONSECUTIVE_BLOCKED). Vale da PRÓXIMA ativação de execução em diante — não afeta agentes já rodando.

storyPromotion
string
Valores: "manual" "auto"

Quem promove uma história de draft para ready (Fase 12c — RN-048). auto (padrão de projeto novo desde a RN-659): história completa já nasce ready, sem passo humano. manual: o PO propõe e VOCÊ decide, na aba Backlog. Mudar o padrão não reescreveu projeto existente nenhum. As validações de domínio (DoD/DoR/RF/regra/módulos) são as MESMAS nos dois modos; o modo só muda quem dispara.

executionMode
string
Valores: "container" "mounted" "runner"

ONDE o comando deste projeto EXECUTA (RN-169/RN-421 — ADR 0072/0104). container (padrão): a pasta gerenciada pelo produto dentro de PROJECT_WORKSPACES_ROOT, o comportamento de sempre. mounted: uma pasta SUA, dada em workspacePath, dentro da base da instalação BRABO_PROJECTS_BASE (ADR 0141) — a criação valida só o FORMATO do caminho mais essa base, e a pasta em si é criada depois, quando a Infra sobe o container (RN-501, ADR 0142). runner: uma pasta SUA que NÃO precisa de bind-mount — a criação só valida o formato do caminho e o projeto nasce "não verificado"; rode brabo-runner --project <id> --dir <folder> na sua máquina para confirmá-lo (RN-423).

workspacePath
string

O caminho ABSOLUTO da pasta, obrigatório quando executionMode é mounted ou runner, e recusado quando é container. Nos DOIS só o FORMATO é validado agora — absoluto, sem .., não a raiz do sistema, não pasta de sistema, não sobreposto ao checkout do Brabo (RN-422/RN-423). mounted acrescenta uma regra: tem de ficar dentro de BRABO_PROJECTS_BASE, a única pasta da sua máquina que os containers do Brabo enxergam (ADR 0141) — sem base configurada o modo não está disponível nesta instalação e a criação diz isso. O disco é tocado depois: pelo runner em runner, e quando a Infra sobe o container em mounted (RN-501, ADR 0142).

language
string <= 35 characters

O idioma do PROJETO (RN-619) — artefatos compartilhados e turnos sem autor humano o usam. Qualquer código BCP-47 que o servidor reconhece, gravado na forma canônica; um não reconhecido é 400. Omitido, o projeto começa com o idioma de resposta efetivo de quem o criou (RN-618: escolha da conta > detecção confirmada > idioma da interface).

Respostas

Exemplos de requisição

Content type
application/json
{
  • "name": "Checkout",
  • "slug": "checkout",
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "executionMode": "container",
  • "workspacePath": "/home/you/projects/store",
  • "language": "pt-BR"
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000PROJETO0000000001",
  • "workspaceId": "01JC4Z0000WORKSPACE00000001",
  • "name": "Checkout",
  • "slug": "checkout",
  • "workspaceDirName": "checkout-3f2b1c8e",
  • "executionMode": "container",
  • "workspacePath": null,
  • "workspaceVerifiedAt": null,
  • "mirrorPath": null,
  • "language": "pt-BR",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "taskBudgetMicros": 500000,
  • "maxConsecutiveBlocked": 3,
  • "storyPromotion": "auto",
  • "createdAt": "2026-07-21T11:00:00.000Z",
  • "updatedAt": "2026-07-21T11:00:00.000Z"
}

A pasta base dos projetos no modo Mounted

A única pasta da máquina do operador que os containers da api e do engine enxergam, montada por identidade (ADR 0141). null — estado normal, nunca erro — quer dizer que esta instalação não tem BRABO_PROJECTS_BASE, então o assistente de projeto não deve oferecer o modo Mounted de jeito nenhum. O mesmo valor para todo workspace: é configuração da instalação, e workspaceId só escopa a autorização.

brokerConfigurado responde a outra metade da mesma pergunta: container e mounted só sobem container pelo broker (ADR 0144), então sem ele o assistente não pré-seleciona Mounted e oferece Runner no lugar (ADR 0161, RN-573).

Authorizations:
bearer

Respostas

Exemplos de resposta

Content type
application/json
{
  • "projectsBase": "/home/voce/brabo",
  • "brokerConfigurado": false
}

Contagem de tarefas bloqueadas por projeto

Uma linha por projeto do workspace com tarefa bloqueada — alimenta o ponto de status da barra lateral do painel com uma consulta só em vez de N chamadas ao backlog.

Authorizations:
bearer
path Parameters
workspaceId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Tudo o que os cards do painel desenham, numa chamada só

Uma linha por projeto do workspace com provider de git, status de provisionamento, orçamento, última atividade, histórias aguardando promoção e os fatos que decidem a lista de agentes (RN-090).

Mesma ideia de projects-status, um andar acima: a grade de cards é uma leitura de WORKSPACE, não N leituras de projeto. O caminho anterior fazia sete consultas com poll por card, e com 23 projetos só o painel estourava o rate limit de 300 req/min.

Authorizations:
bearer
path Parameters
workspaceId
required
string

Respostas

Exemplos de resposta

Content type
application/json
[
  • {
    }
]

Resumo agregado do workspace

Contagem de projetos, agentes que gastaram tokens neste mês e o gasto do mês — alimenta a linha de resumo do painel de projetos.

Authorizations:
bearer
path Parameters
workspaceId
required
string

Respostas

Exemplos de resposta

Content type
application/json
{
  • "activeProjects": 4,
  • "agentCount": 6,
  • "spentMicros": 12500000
}

Liga ou desliga o roteamento de ferramentas do Jev no workspace

Ligado por padrão. Quando ligado E o modelo do turno é do OpenRouter, um passo de agente com duas ou mais ferramentas primeiro pergunta ao Jev qual ferramenta cabe, e ao modelo de chat só são oferecidas essa ferramenta e a anterior. O Jev nunca aprova nem nega nada: ação que exige aprovação continua exigindo. Qualquer falha do Jev cai no catálogo inteiro. Desligá-lo para toda chamada ao Jev, e o custo delas junto.

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
enabled
required
boolean

Se o Jev escolhe a ferramenta de cada passo de agente. Ligado por padrão; só age quando o modelo do turno é do OpenRouter.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "enabled": false
}

Exemplos de resposta

Content type
application/json
{
  • "id": "01JC4Z0000WORKSPACE00000001",
  • "name": "Acme Corp",
  • "slug": "acme-corp",
  • "createdBy": "01JC4Z0000USUARIO0000000001",
  • "toolRouterEnabled": true,
  • "createdAt": "2026-07-20T09:12:00.000Z",
  • "updatedAt": "2026-07-20T09:12:00.000Z"
}

Eventos não lidos de vários projetos, numa chamada só

A gaveta do sino, para o workspace inteiro (RN-091). Cada cursor diz até qual seq aquele projeto já foi lido, e a resposta traz o que veio depois disso na sessão mais recente de cada um.

É POST porque é o único verbo com CORPO, não porque muda estado. O servidor não sabe onde cada leitor parou: "lido até aqui" é um seq por projeto guardado no navegador, e (de propósito) não há endpoint de marcar como lido. Então o corte precisa VIAJAR no pedido, e são dezenas de pares — numa query string isso vira uma URL longa, que um proxy corta, e ainda poria os ids de projeto do usuário em logs de acesso. A rota é idempotente e não tem efeito colateral: responde 200, nunca 201.

Substitui um pedido POR PROJETO com a gaveta aberta — 23 projetos custavam 286 req/min contra um limite de 300.

Authorizations:
bearer
path Parameters
workspaceId
required
string
Request Body schema: application/json
required
required
Lista de objects (UnreadCursorDto) <= 200 items

Um cursor por projeto a consultar. Lista VAZIA devolve lista vazia — "não pedi nada" não é "me dê tudo". Projeto de outro workspace é ignorado em silêncio, porque o cursor vem do armazenamento local de quem chama e pode trazer sobras de um workspace antigo.

Array (<= 200 items)
projectId
required
string <uuid>
afterSeq
required
number >= 0

Último seq que ESTE navegador já viu neste projeto. Devolve eventos com seq estritamente maior. 0 quer dizer "nunca vi nada" e traz o começo da sessão mais recente.

Respostas

Exemplos de requisição

Content type
application/json
{
  • "cursors": [
    ]
}

Exemplos de resposta

Content type
application/json
[
  • {
    }
]