O que o Prompt 05 Entrega
Auditoria das 6 primitivas + integração GitHub + configuração por repo
O Prompt 05 é o safety pass — o prompt que transforma um plugin que funciona em condições ideais em um plugin que funciona em produção. Toda edge case não coberta aqui vai manifestar no pior momento possível.
gh pr comment para postar relatório no PR.claude/review-config.yaml com configuração por repoO Prompt 05 Completo
Cole este texto no Claude Code com o SPEC.md em contexto
Prompt 05 — Cole no Claude Code
Read SPEC.md — the safety invariants section is your audit checklist.
You are building Prompt 05: the safety pass.
Audit every script against the 6 primitives, then add GitHub
integration and repo configuration.
**Part A — Safety Audit (audit each file, fix what's missing):**
For every .sh file in the plugin, verify and fix:
1. ERR trap:
- Present as FIRST active line?
- Does it print to stderr and exit 0 (not exit 1)?
- Fix any script where it's missing or exits non-zero.
2. Atomic writes:
- Every write to state/review.yaml goes through write_state_atomic?
- No direct `echo > state/review.yaml` anywhere?
- Fix any direct writes found.
3. CAS on state transitions:
- Every status change in stop-hook.sh uses cas_state?
- Fix any status write that bypasses CAS.
4. Lockfile:
- stop-hook.sh acquires lock at entry?
- EXIT trap releases it?
- Stale lock: add check — if lock exists but PID in it is dead, remove.
- Implement: `if [ -f state/review.lock ]; then
lock_pid=$(cat state/review.lock 2>/dev/null || echo "")
if [ -n "$lock_pid" ] && ! kill -0 "$lock_pid" 2>/dev/null; then
rm -f state/review.lock # stale lock — safe to remove
fi; fi`
5. Path validation:
- All scripts that receive a path argument validate it starts
with /tmp/pr-review- before using it.
- Implement: `[[ "$WORKTREE_PATH" == /tmp/pr-review-* ]] ||
{ echo "Invalid path: $WORKTREE_PATH" >&2; exit 0; }`
6. Subprocess timeouts:
- runner scripts use `timeout 120 claude --print` not bare `claude`.
- Fix any runner that calls claude without timeout.
**Part B — GitHub Integration:**
In scripts/generate-report.sh, after saving the report file:
Read .claude/review-config.yaml (use `yq` or manual grep fallback).
If `post_to_github: true` (default true):
`gh pr comment $PR_NUMBER --body-file .claudex/reviews/PR-$PR_NUMBER-*.md`
Handle gh failure gracefully (log error, don't abort).
**Part C — repo configuration:**
Create `.claude/review-config.yaml` with defaults:
max_rounds: 3
min_severity: MEDIUM # CRITICAL|HIGH|MEDIUM|LOW — filter for gh comment
ignore_paths: # paths to skip in diff
- "*.lock"
- "*.sum"
- "vendor/"
timeout_seconds: 120 # per runner invocation
post_to_github: true
**Part D — E2E test script:**
Create `tests/e2e-test.sh <pr_number>`:
1. Assert: state is clean (no active review)
2. Invoke: `/pr-reviewer $pr_number` (simulate: set state=SETUP, run hook)
3. Assert: state transitions SETUP → REVIEWING (round 1)
4. Simulate 3 runner completions (inject mock findings)
5. Assert: state transitions to SUMMARIZING
6. Assert: report file created at .claudex/reviews/PR-$pr_number-*.md
7. Assert: gh pr comment was called (check with mock or --dry-run)
8. Assert: state is DONE, worktree removed
**Report after delivery:**
- List of fixes applied in Part A (by primitive)
- Confirm all 6 primitives now covered
- E2E test result: all 7 assertions PASS
O Safety Pass
As 6 primitivas que todo plugin de produção deve ter
Cada primitiva cobre uma classe de falha diferente. Ausência de uma única primitiva é suficiente para transformar um edge case comum em uma corrupção de estado irrecuperável.
ERR trap em todo script
Qualquer erro não tratado é capturado. O hook não lança exceção para o Claude Code. Exit 0 sempre.
Falha coberta: erro de bash inesperado em qualquer linha
Escrita atômica universal
Todo write de estado usa tmp + rename. Nunca escrita direta.
Falha coberta: interrupção durante escrita → arquivo corrompido
CAS em toda transição de estado
Toda mudança de status verifica version antes de escrever.
Falha coberta: duas instâncias modificando estado simultaneamente
Lockfile com varredor de stale
flock não-bloqueante + verificação de stale locks de processos mortos.
Falha coberta: crash deixa lock órfão, bloqueando execuções futuras
Validação de paths
worktree_path deve começar com /tmp/pr-review- antes de qualquer uso.
Falha coberta: path traversal acidental ou malformado apaga dados
Timeout em subprocessos
Todo `claude --print` envolto em `timeout 120`. Runner não bloqueia indefinidamente.
Falha coberta: API travada deixa o loop preso para sempre
Integração GitHub
gh pr comment com o relatório gerado automaticamente
Postar o relatório diretamente no PR elimina o passo manual. A revisão aparece no contexto onde o time já está discutindo — sem precisar abrir outro arquivo.
# Pegar o relatório mais recente para este PR
REPORT_FILE=$(ls -t .claudex/reviews/PR-${PR_NUMBER}-*.md 2>/dev/null | head -1)
if [ -z "$REPORT_FILE" ]; then
echo "[pr-reviewer] No report file found, skipping comment" >&2
exit 0
fi
# Postar no PR (fail gracefully se gh não está disponível)
if command -v gh >/dev/null 2>&1; then
gh pr comment "$PR_NUMBER" \
--body-file "$REPORT_FILE" \
2>/dev/null || echo "[pr-reviewer] gh comment failed (ignored)" >&2
fi
min_severity filter
Se min_severity=HIGH, apenas findings CRITICAL e HIGH vão para o comment. MEDIUM e LOW ficam no relatório local mas não são postados — reduz ruído no PR.
post_to_github: false
Para repos onde você não quer comentários automáticos (ex: OSS público), desabilitar no review-config.yaml. O relatório ainda é salvo localmente.
Configuração por Repositório
.claude/review-config.yaml — defaults que o time pode ajustar
Hardcoded defaults funcionam para um repo mas não para todos. Configuração por repo permite que cada time ajuste o revisor ao seu contexto sem modificar o código do plugin.
Exemplo de review-config.yaml
# .claude/review-config.yaml
# PR Reviewer Configuration — customize for this repo
# Number of review rounds (1 = Author only, 2 = +Reviewer, 3 = +Security)
max_rounds: 3
# Minimum severity to include in the GitHub PR comment
# CRITICAL|HIGH|MEDIUM|LOW — lower severity findings still appear in local report
min_severity: MEDIUM
# Paths to skip in the diff (supports glob patterns)
ignore_paths:
- "*.lock"
- "*.sum"
- "vendor/"
- "*.generated.go"
- "testdata/"
# Timeout per runner invocation (seconds)
timeout_seconds: 120
# Whether to post the report as a PR comment via gh
# Set false for OSS repos or when you prefer manual review of the report
post_to_github: true
# Override max diff size (lines) — diffs larger than this are split
max_diff_lines: 3000
E2E Sintético
Rodando o revisor completo num PR de teste — validação ponta a ponta
O teste E2E é o único que valida a integração ponta a ponta. Cada ponto de integração — Claude Code → hook → worktree → runner → relatório → GitHub — pode falhar silenciosamente. Este teste confirma que todos funcionam juntos.
Criar PR de teste no GitHub
Um PR real com pelo menos um arquivo modificado. Não precisa ter bugs — é para validar o fluxo, não a qualidade da revisão.
Rodar o plugin completo
Invocar `/pr-reviewer NNN` no Claude Code. Observar as 3 rodadas completarem. Não interferir — deixar o loop rodar até DONE.
Verificar todos os artefatos
State DONE? Worktree removido? Relatório em .claudex/reviews/? Lock liberado? Runners limpos?
Verificar integração GitHub
Abrir o PR no GitHub. O comentário do revisor deve estar lá. Se não está, verificar: gh autenticado? post_to_github: true? gh pr comment rodou sem erro?
Testar falha e recovery
Matar o Claude Code durante uma rodada (Ctrl+C). Rodar novamente. O revisor deve detectar o stale lock, limpar e continuar de onde parou.
Se o E2E passa — incluindo o teste de falha e recovery — o plugin pr-reviewer está pronto para produção. Você construiu um segundo plugin seguindo os mesmos 5 prompts incrementais da Trilha 2, aplicados a um sistema mais complexo com integração externa.
🏁 Trilha 4 Completa
O padrão que você aprendeu:
SPEC.md → Scaffold → Estado → Loop → Conteúdo → Safety. Cinco prompts incrementais, cada um verificado antes do próximo. Este é o método para construir qualquer plugin Claude Code complexo.