DocsAbrir Studio

Gate

Depois que uma Submission entra, o Forma pode avaliá-la. Se passar, dispara submission.accepted para o AI do cliente começar o trabalho. O Forma não escreve código no repo deles.

O fluxo

1. Ingest grava a Submission e dispara submission.created como hoje.

2. Se o Form é feedback e o gate está ligado, avalia nesta ordem: URL do avaliador, senão a key OpenAI do Workspace, senão regras locais. Categoria é Auto classify, um recurso à parte.

3. Passou → webhooks com evento submission.accepted, corpo com evaluation + a Submission crua. Falhou → fica no Studio, não chega no destino do cliente.

Survey não entra neste fluxo. Ligar o gate num survey não dispara aceite.

OpenAI

Cole uma API key sk-… em Workspace → Configurações. O Gate chama gpt-4o-mini (ou OPENAI_MODEL no ambiente) com as instruções do Form, em ordem, e pede JSON: pass, reason, summary. Se Auto classify também estiver ligado, pede category na mesma resposta.

A categoria aparece na lista de Submissions quando Auto classify está ligado. A lista padrão é bug, feature, question, praise, spam, other — ou a que você escrever no Form.

Enquanto o Studio não tem login, quem abre o Studio alcança a key. Não use uma key de produção compartilhada.

Instruções

Uma por linha na Integração do Form. O modelo segue a sequência. Sem key e sem URL, as linhas min:N e -palavra ainda funcionam como gate local.

Gate local

Na aba Integrações do Form. Critérios, uma regra por linha:

min:N
Mínimo de caracteres de texto no payload. Padrão 12.
-palavra
Bloqueia se o texto (case-insensitive) contém a palavra.
resto
Vai no body do avaliador remoto; o gate local ignora.

Avaliador remoto

Opcional. O Forma POSTa e o teu serviço decide. Timeout 5 s. 2xx com pass boolean. Qualquer outro resultado vira error no Studio e não dispara aceite.

evaluate.ts
export async function POST(request: Request) {
  const { submission, criteria } = await request.json();
  // o teu modelo decide
  return Response.json({
    pass: true,
    reason: "actionable",
    summary: submission.payload.message,
  });
}

Destino do cliente

Crie um webhook com evento submission.accepted. É o mesmo POST assinado dos webhooks. O agente no cliente (Cursor, CI, bot) escuta esse URL e começa o build.

accepted.json
{
  "event": "submission.accepted",
  "evaluation": {
    "pass": true,
    "reason": "actionable_bug",
    "summary": "O botão de salvar some no mobile.",
    "category": "bug"
  },
  "submission": {
    "id": "7e583034-1a0a-47d5-ab72-74d4541f8486",
    "formId": "form_demo",
    "receivedAt": 1788182240254,
    "origin": "https://app.acme.com",
    "userAgent": "Mozilla/5.0 …",
    "payload": { "email": "ana@acme.com", "message": "…" }
  }
}

A mesma Submission nunca gera dois aceites: o status do gate é gravado, e cada par webhook+Submission só tem uma entrega.