16 KiB
AGENT-OPS — operação do paradigma de agentes paralelos
Uma página. Norte: simplicidade (só GitHub + Cursor), agente entrega em main, deploy de produção só após o verificador full-suite verde.
Ambientes de dados (test ladder — nunca misturar)
| Ambiente | Conteúdo | Quem usa |
|---|---|---|
Mínimo (teqo_test local / service CI) |
schema migrado + pnpm db:seed:minimal (sintético, sem PII) |
agentes, Cursor Cloud, CI |
Prod (teqo_1313, homeserver) |
real | job deploy do ci.yml (OPS53) |
Agentes nunca recebem DATABASE_URL de prod e nunca setam ALLOW_REMOTE_DB. Não há mais smoke Neon stage / ALLOW_STAGE_TEST_DB / ci-stage.yml.
Fluxo
claim → feature branch → PR --base main → CI PR green (cascade + skips) → auto-merge em main
main → ci.yml full suite verde → job `deploy` (homeserver, OPS53 — merge em main == site atualizado)
Skills: plan-issue (intenção + Issues) → work-issue (humano: Issue já claimada → impl plan → confirmação → execução) ou agent-work-issue (pool: já claimada → impl plan → execução sem pausa) → /simplify → capture-review-debts → PR --base main → project-status. docs/roadmap.md = legado congelado; fonte canônica = GitHub Issues.
- Agente faz sozinho: claim (pool-supervisor no pool; humano via
pnpm agent:claimfora da sessão — OPS33:worktree nextclaima) → implementa →pnpm push→ PR Ready (nunca draft) comCloses #N→gh pr merge --auto --rebase→gh pr checks --watch --required. Regra always-on:.agents/rules/agent-pr-workflow.mdc. Em Cursor Cloud:ManagePullRequestcomdraft: false, depois armar auto-merge viagh pr merge --auto --rebase(o default draft da tool não vale neste repo). - Só humano: secrets Vercel (
VERCEL_TOKEN,VERCEL_ORG_ID,VERCEL_PROJECT_ID),POOL_GITHUB_TOKEN,pnpm configure:branch-protection, editar envs Neon/Vercel.
Dono do PR, dono do CI
Done = PR mergeado em main com CI verde. Falha de CI no teu PR — infra, teste pré-existente ou regressão — é tua até o merge. Exceção de blast radius: migration / access / Consent → pare e escale.
Bypass de CI (cutover / transição)
- Local: se
gate:pushainda espelha pipeline antigo e bloqueia push legítimo da PR que o muda →git push --no-verifypermitido como escape de transição (não WIP permanente). Documentado aqui; após o cutover, entregas passam no CI novo sem bypass. - Cutover humano: pode relaxar temporary required checks se o flip de proteção travar merges; reverter para
CI (PR) / checksemmainassim que o CI novo estiver verde.
Comandos
| Comando | Faz |
|---|---|
pnpm agent:claim [-- --dry-run] |
Fila ready+unblocked por prio → in-progress + brief |
pnpm worktree next [--issue N] [--stay] |
Claim determinístico (mesma fila/lock do claim) → worktree + provisionamento |
pnpm agent:register -- --id X --title T [--prio P1] [--depends A,B] [--plan docs/plans/x.md] [--model slug] |
Cria Issue (--plan ⇒ blocked até agent:ready; sem plano ⇒ ready) |
pnpm agent:ready -- --issue N[,N…] |
Pós-merge do plano: blocked→ready (só Issues com link docs/plans/) |
pnpm agent:status |
Overview / fila / mermaid |
pnpm agent:prioritize -- <issue> <P0..P3> |
Troca prio:* |
pnpm agent:file-miss -- --title ... |
Issue kind:agent-miss |
pnpm agent:pool -- status|tick --dry-run|doctor |
Pool Cloud; start/stop via gh workflow run agent-pool.yml |
pnpm push [-- -u origin HEAD …] |
Canônico: ensure-deps + gate:push + push |
pnpm configure:branch-protection [-- --dry-run] |
Proteção de main: required status check CI (PR) / checks (rollup do ci-pr; idempotente — cria/atualiza/no-op) |
pnpm db:seed:minimal |
DB mínimo sintético |
Labels: ready|in-progress|blocked|done|in-prod, prio:*, kind:*, needs:*.
plan-issue (OPS17 + OPS18): gate pós-overview fecha o lote antes de qualquer Issue/PR; register com --plan nasce blocked (não entra na fila do claim/pool); após o PR de planos mergear em main (Related #N), promote dual idempotente: (A) pnpm agent:ready na sessão; (B) Action plan-issue-ready-on-main-merge.yml lê Related #N e promove Issues ainda “aguardando plano” (blocked + link docs/plans/). Chores sem plano continuam nascendo ready.
Contrato de PR
- Schema → atualizar
db:seed:minimalno mesmo PR (needs:migration). - Migrations NÃO são serializadas entre PRs: o CI (migrate + int, incl.
campaignMigrationReconciliation) valida a cadeia em todo PR e na main; rebase antes demigrate:createcontinua obrigatório. - Ready + auto-merge:
gh pr create --base main→gh pr merge --auto --rebase;gh pr checks --watch --required(Vercel Git não é gate). Merge é por rebase (nunca merge commit): preserva a linha histórica limpa domaine é o modo que o CI guarda contra conflitos latentes. - Changelog da entrega (OPS44): toda entrega escreve
docs/changelog/<data>-<id>.md(ex.2026-08-13-ops44.md) e rodapnpm changelog:buildantes do push — o agregadodocs/CHANGELOG-AGENTS.mdé insert-only (nunca remove/reescreve entradas; entradas históricas não são migradas). Guard de CIdocs-guards: (a) agregado é append-only (multiset sobre blobs — perda de linha falha); (b)docs/changelog/é additions-only (M/D falham); (c) agregado está up to date comdocs/changelog/(changelog:check); (d) nenhum marcador de conflito em diffs de markdown (docs/, AGENTS.md, .agents/ — cobre PRs docs-only, onde a suíte unit não roda). Desde OPS63 os mesmos três checks rodam também no pre-push local (gate:push→gate:ci, fase 1 — mesmos scripts, defaultorigin/main). Restauração legítima (header muda, restauração estilo D8) escapa escrevendochangelog-rewrite: <motivo>como linha própria no body do PR — definição canônica aqui; o texto do checkbox do PR template nunca ativa (linha-ancorado). O escape é CI-only (body do PR): no pre-push local a restauração legítima falha com a mesma mensagem do CI — bypass documentado égit push --no-verifydireto (o CI, com o escape no body, continua sendo a via da restauração). A própria troca--merge→--rebasedeste doc usou o escape — header do agregado mudou.
Registries compartilhados (serialização por arquivo, não por PR)
Arquivos de "lista" que N agentes escrevem em paralelo (changelog, plans, migrações, catalog) conflitam por construção: cada escrita reescreve o arquivo inteiro. Regras:
- Cada entrega escreve UM arquivo por registro (
docs/changelog/<data>-<id>.md,docs/plans/<slug>.md, migration com nome único, etc.) — o arquivo comum é derivado (build/CI) ou só-leitura por PR (guard). serializesno plano de intenção nomeia o registro exato que a Issue toca (ex.serializes: 'docs/plans/'), para o executor agendar com clareza — é dica de ordem, não lock (rebase continua obrigatório).- O rebase (Contrato de PR item 3) é o mecanismo real de conciliação: conflitos de append resolvem com
git checkout --ours/--theirspor lado.
CI por alvo
| Workflow | Trigger | Banco | Passos |
|---|---|---|---|
ci-pr.yml |
PR → main |
2× service Postgres 17 | Job único checks sequencial (OPS62 X1): guards → lint→format→typecheck→knip→cycles→unit→int→build→e2e; skips via ci-scope.mjs (step scope); fail-fast estrutural — step vermelho interrompe o job, o run falha e o slot é liberado; e2e 1 processo com PLAYWRIGHT_WORKERS=4; 2 services por nome na rede do job (postgres-int/postgres-build, sem publish host) |
ci.yml |
push / dispatch main |
2× service Postgres 17 | Full sempre; job único checks sequencial (mesma mecânica X1); job deploy (runs-on host) publica no homeserver via scripts/deploy-homeserver.sh (OPS53) |
issue-done-on-main-merge.yml |
PR merged → main (same-repo) |
— | Closes/Fixes → done + in-prod (PAT FORGEJO_API_TOKEN; GITHUB_TOKEN 403 em Issues) |
plan-issue-ready-on-main-merge.yml |
PR merged → main (same-repo) |
— | Related #N aguardando plano → ready (OPS18; soft-skip; mesmo PAT) |
agent-pr-ready-automerge.yml |
PR same-repo → main (open/sync/…) |
— | Safety net via forgejo-pr-automerge.mjs (plain Node): espera o rollup checks e mergea por rebase com FORGEJO_API_TOKEN (o GITHUB_TOKEN nativo não tem write no repo — o push do merge é rejeitado com 409); draft cursor/* → Ready; draft não-cursor/* = veto, skip |
agent-pool.yml |
schedule / PR closed main / dispatch |
— | Supervisor do pool (POOL_GITHUB_TOKEN) |
Action runtimes: actions/checkout@v5, actions/setup-node@v5 e pnpm/action-setup@v6 usam Node 24 nativo — sem FORCE_JAVASCRIPT_ACTIONS_TO_NODE24.
Action runtimes: actions/checkout@v5, actions/setup-node@v5 e pnpm/action-setup@v6 usam Node 24 nativo — sem FORCE_JAVASCRIPT_ACTIONS_TO_NODE24.
Fast gate: pnpm gate:fast. Push: pnpm push.
Secrets (humano, uma vez)
| Secret | Uso |
|---|---|
FORGEJO_API_TOKEN |
Supervisor do pool e scripts Forgejo (forgejo-api.mjs); também nos workflows pós-merge (issue-done, plan-issue-ready) — o GITHUB_TOKEN nativo 403 em Issues (OPS61) |
CURSOR_API_KEY |
Supervisor do pool (Cursor Cloud) |
POOL_GITHUB_TOKEN |
PAT actions:write + issues:write (variables do pool; GITHUB_TOKEN costuma 403) |
Branch protection de main (aplicada em 2026-08-18, OPS61): required status check CI (PR) / checks (o rollup do ci-pr.yml — único contexto que cobre a cascata inteira), strict=false, 0 reviews. O waitForChecks do safety net espera esse mesmo rollup antes de mergear (o próprio status do job é pending durante o run e nunca entra no veredito); a regra no servidor é o gate real — o Forgejo bloqueia o merge POST com 405 se o contexto exigido não estiver verde, inclusive merges manuais via API (a PR #52 entrou em main com CI vermelho por merge manual). Reaplicar/consertar drift: pnpm configure:branch-protection (idempotente).
Deploy (OPS53): o job deploy do ci.yml roda no host do runner (workstation) e streama scripts/deploy-homeserver.sh para o homeserver via SSH — build no homeserver (secrets de ~/stack/teqo-1313.env), registry localhost:5000, migrate pelo serviço de maintenance teqo-1313-migrate antes do rollout, smoke pós-deploy. Nenhum secret novo no Forgejo. Runbook (rollback, falhas conhecidas): docs/ops/teqo-1313-deploy.md. O deploy Vercel (vercel-promote.yml, scripts, vercel.json) foi removido no OPS50.
Cursor Cloud
.cursor/environment.json instala deps + Postgres nativo + db:seed:minimal. Sem secrets de prod. Preferir pnpm push; escape git push --no-verify só no cutover documentado acima.
Agent pool
Supervisor remoto (agent-pool.yml): schedule + replenish em merge → main + dispatch. Workers PR --base main. Default model composer-2.5. Secret POOL_GITHUB_TOKEN obrigatório se GITHUB_TOKEN 403 em /actions/variables. Doctor: pnpm agent:pool -- doctor. Skill: agent-pool.
Guardrails / leitura
pnpm agent:file-miss → harvest → docs/GUARDRAILS.md. Always-on: AGENTS.md → codebase-map → engineering-standards → esta página → PRODUCT/DESIGN/CUSTOMER.