Last active
June 8, 2026 14:26
-
-
Save nicolasmelo1/25aaffa260138a450c62b6995feb5fb1 to your computer and use it in GitHub Desktop.
Agent loop
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -Eeuo pipefail | |
| # ============================================================ | |
| # agent-loop.sh | |
| # | |
| # Orquestra: | |
| # 1. Claude Code -> planejamento | |
| # 2. Hermes Agent -> execução | |
| # 3. Codex -> revisão estruturada | |
| # 4. Loop infinito até Codex aprovar | |
| # | |
| # Uso: | |
| # ./agent-loop.sh "Crie uma API em FastAPI..." | |
| # | |
| # Ou: | |
| # cat prompt.txt | ./agent-loop.sh | |
| # | |
| # Configure os comandos conforme seu ambiente: | |
| # | |
| # CLAUDE_CMD='claude -p' \ | |
| # HERMES_CMD='hermes run' \ | |
| # CODEX_CMD='codex exec' \ | |
| # ./agent-loop.sh "Seu prompt" | |
| # | |
| # Importante: | |
| # - Os comandos devem aceitar o prompt via STDIN. | |
| # - O Codex deve retornar JSON puro. | |
| # ============================================================ | |
| CLAUDE_CMD="${CLAUDE_CMD:-claude}" | |
| HERMES_CMD="${HERMES_CMD:-hermes}" | |
| CODEX_CMD="${CODEX_CMD:-codex}" | |
| REPO_DIR="${REPO_DIR:-$(pwd)}" | |
| RUN_ROOT="${RUN_ROOT:-$REPO_DIR/.agent-loop-runs}" | |
| MAX_ITERS="${MAX_ITERS:-0}" # 0 = infinito | |
| SLEEP_SECONDS="${SLEEP_SECONDS:-0}" # pausa entre iterações | |
| timestamp="$(date +"%Y%m%d-%H%M%S")" | |
| RUN_DIR="$RUN_ROOT/run-$timestamp" | |
| mkdir -p "$RUN_DIR" | |
| if [[ $# -gt 0 ]]; then | |
| INITIAL_PROMPT="$*" | |
| else | |
| INITIAL_PROMPT="$(cat)" | |
| fi | |
| if [[ -z "${INITIAL_PROMPT// }" ]]; then | |
| echo "Erro: prompt inicial vazio." >&2 | |
| exit 1 | |
| fi | |
| printf '%s\n' "$INITIAL_PROMPT" > "$RUN_DIR/initial_prompt.md" | |
| log() { | |
| printf '\n[%s] %s\n' "$(date +"%H:%M:%S")" "$*" >&2 | |
| } | |
| run_agent() { | |
| local label="$1" | |
| local cmd="$2" | |
| local input="$3" | |
| log "Rodando $label..." | |
| ( | |
| cd "$REPO_DIR" | |
| printf '%s' "$input" | bash -lc "$cmd" | |
| ) | |
| } | |
| json_get() { | |
| local key="$1" | |
| local json="$2" | |
| python3 - "$key" <<'PY' <<< "$json" | |
| import json | |
| import sys | |
| key = sys.argv[1] | |
| raw = sys.stdin.read() | |
| obj = json.loads(raw) | |
| value = obj.get(key, "") | |
| if isinstance(value, bool): | |
| print("true" if value else "false") | |
| elif isinstance(value, (list, dict)): | |
| print(json.dumps(value, ensure_ascii=False)) | |
| elif value is None: | |
| print("") | |
| else: | |
| print(str(value)) | |
| PY | |
| } | |
| build_claude_prompt() { | |
| local iteration="$1" | |
| local codex_feedback="$2" | |
| local previous_plan="$3" | |
| local previous_execution="$4" | |
| cat <<EOF | |
| Você é o AGENTE PLANEJADOR. | |
| Sua função é transformar o pedido inicial em um plano claro, executável e verificável para outro agente implementar. | |
| Você NÃO deve executar a tarefa. Você deve apenas planejar. | |
| Contexto da iteração: $iteration | |
| PROMPT INICIAL DO USUÁRIO: | |
| $INITIAL_PROMPT | |
| PLANO ANTERIOR, SE EXISTIR: | |
| $previous_plan | |
| RESULTADO/TRACE TÉCNICO DO HERMES, SE EXISTIR: | |
| $previous_execution | |
| FEEDBACK DO CODEX, SE EXISTIR: | |
| $codex_feedback | |
| Produza uma resposta em Markdown com esta estrutura: | |
| # Objetivo | |
| # Escopo | |
| # Restrições e cuidados | |
| # Plano de execução | |
| Use uma lista numerada objetiva. | |
| # Critérios de aceitação | |
| # Instruções para o Hermes Agent | |
| Diga exatamente o que o executor deve fazer agora. | |
| Regras: | |
| - Seja específico. | |
| - Não use linguagem vaga. | |
| - Se houver feedback do Codex, incorpore-o ao plano. | |
| - Não inclua chain-of-thought privado. | |
| - Inclua apenas justificativas técnicas resumidas quando necessário. | |
| EOF | |
| } | |
| build_hermes_prompt() { | |
| local plan="$1" | |
| cat <<EOF | |
| Você é o HERMES AGENT, o AGENTE EXECUTOR. | |
| Você deve executar a tarefa com base no prompt inicial e no planejamento do Claude. | |
| PROMPT INICIAL DO USUÁRIO: | |
| $INITIAL_PROMPT | |
| PLANEJAMENTO DO CLAUDE: | |
| $plan | |
| Sua missão: | |
| - Implementar as alterações necessárias. | |
| - Criar, editar ou remover arquivos quando necessário. | |
| - Rodar comandos relevantes de teste, lint, build ou validação quando possível. | |
| - Registrar o que foi feito de forma auditável. | |
| Ao final, retorne um relatório estruturado em Markdown com: | |
| # Status | |
| # Resumo da execução | |
| # Arquivos alterados | |
| # Comandos executados | |
| # Resultado dos testes/verificações | |
| # Trace técnico | |
| Inclua apenas um resumo técnico das decisões, sem chain-of-thought privado. | |
| # Pendências ou riscos conhecidos | |
| Regras: | |
| - Não invente resultados de testes. | |
| - Se não conseguir executar algo, diga claramente. | |
| - Não inclua raciocínio privado oculto. | |
| EOF | |
| } | |
| build_codex_prompt() { | |
| local plan="$1" | |
| local execution="$2" | |
| cat <<EOF | |
| Você é o CODEX, o AGENTE REVISOR. | |
| Você deve revisar criticamente o resultado produzido pelo Hermes com base no prompt inicial e no planejamento do Claude. | |
| PROMPT INICIAL DO USUÁRIO: | |
| $INITIAL_PROMPT | |
| PLANEJAMENTO DO CLAUDE: | |
| $plan | |
| RELATÓRIO/TRACE TÉCNICO DO HERMES: | |
| $execution | |
| Sua tarefa: | |
| - Verificar se o resultado atende ao prompt inicial. | |
| - Verificar se o plano foi cumprido. | |
| - Identificar bugs, lacunas, problemas de qualidade, falta de testes ou inconsistências. | |
| - Decidir se o resultado está aprovado. | |
| Retorne APENAS JSON PURO, sem Markdown, sem comentários e sem texto fora do JSON. | |
| Formato obrigatório: | |
| { | |
| "approved": true, | |
| "score": 0, | |
| "reason": "Explique resumidamente a decisão.", | |
| "blocking_issues": [], | |
| "non_blocking_issues": [], | |
| "next_instructions": "Se approved=false, explique exatamente o que o Claude deve planejar na próxima iteração. Se approved=true, deixe vazio.", | |
| "final_response": "Se approved=true, escreva a resposta final resumida para o usuário. Se approved=false, deixe vazio." | |
| } | |
| Regras: | |
| - "approved" deve ser true somente se o resultado estiver realmente satisfatório. | |
| - "score" deve ser um número de 0 a 10. | |
| - Se houver qualquer problema bloqueante, use approved=false. | |
| - Se approved=false, next_instructions deve ser claro, acionável e específico. | |
| EOF | |
| } | |
| iteration=1 | |
| codex_feedback="" | |
| previous_plan="" | |
| previous_execution="" | |
| while true; do | |
| if [[ "$MAX_ITERS" != "0" && "$iteration" -gt "$MAX_ITERS" ]]; then | |
| log "MAX_ITERS atingido sem aprovação do Codex." | |
| exit 2 | |
| fi | |
| ITER_DIR="$RUN_DIR/iteration-$iteration" | |
| mkdir -p "$ITER_DIR" | |
| log "Iniciando iteração $iteration" | |
| claude_prompt="$(build_claude_prompt "$iteration" "$codex_feedback" "$previous_plan" "$previous_execution")" | |
| printf '%s\n' "$claude_prompt" > "$ITER_DIR/claude_prompt.md" | |
| claude_plan="$(run_agent "Claude Code" "$CLAUDE_CMD" "$claude_prompt")" | |
| printf '%s\n' "$claude_plan" > "$ITER_DIR/claude_plan.md" | |
| hermes_prompt="$(build_hermes_prompt "$claude_plan")" | |
| printf '%s\n' "$hermes_prompt" > "$ITER_DIR/hermes_prompt.md" | |
| hermes_result="$(run_agent "Hermes Agent" "$HERMES_CMD" "$hermes_prompt")" | |
| printf '%s\n' "$hermes_result" > "$ITER_DIR/hermes_result.md" | |
| codex_prompt="$(build_codex_prompt "$claude_plan" "$hermes_result")" | |
| printf '%s\n' "$codex_prompt" > "$ITER_DIR/codex_prompt.md" | |
| codex_review="$(run_agent "Codex" "$CODEX_CMD" "$codex_prompt")" | |
| printf '%s\n' "$codex_review" > "$ITER_DIR/codex_review.json" | |
| approved="false" | |
| if approved_parsed="$(json_get "approved" "$codex_review" 2>/dev/null)"; then | |
| approved="$approved_parsed" | |
| else | |
| codex_feedback="O Codex não retornou JSON válido. Na próxima iteração, planeje uma correção e reforce que o Codex deve retornar apenas JSON puro." | |
| previous_plan="$claude_plan" | |
| previous_execution="$hermes_result" | |
| log "Codex retornou JSON inválido. Continuando loop." | |
| iteration=$((iteration + 1)) | |
| if [[ "$SLEEP_SECONDS" -gt 0 ]]; then | |
| sleep "$SLEEP_SECONDS" | |
| fi | |
| continue | |
| fi | |
| reason="$(json_get "reason" "$codex_review" 2>/dev/null || true)" | |
| score="$(json_get "score" "$codex_review" 2>/dev/null || true)" | |
| log "Revisão Codex: approved=$approved score=$score" | |
| log "Motivo: $reason" | |
| if [[ "$approved" == "true" ]]; then | |
| final_response="$(json_get "final_response" "$codex_review" 2>/dev/null || true)" | |
| log "Codex aprovou o resultado final." | |
| echo | |
| echo "========================================" | |
| echo "RESULTADO FINAL APROVADO PELO CODEX" | |
| echo "========================================" | |
| echo | |
| if [[ -n "${final_response// }" ]]; then | |
| printf '%s\n' "$final_response" | |
| else | |
| echo "Execução aprovada. Logs salvos em:" | |
| echo "$RUN_DIR" | |
| fi | |
| echo | |
| echo "Logs completos:" | |
| echo "$RUN_DIR" | |
| exit 0 | |
| fi | |
| next_instructions="$(json_get "next_instructions" "$codex_review" 2>/dev/null || true)" | |
| if [[ -z "${next_instructions// }" ]]; then | |
| next_instructions="O Codex reprovou, mas não forneceu instruções. Replaneje revisando possíveis falhas de implementação, testes e aderência ao prompt inicial." | |
| fi | |
| codex_feedback="$next_instructions" | |
| previous_plan="$claude_plan" | |
| previous_execution="$hermes_result" | |
| log "Codex não aprovou. Voltando para o Claude." | |
| iteration=$((iteration + 1)) | |
| if [[ "$SLEEP_SECONDS" -gt 0 ]]; then | |
| sleep "$SLEEP_SECONDS" | |
| fi | |
| done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment