Skip to content

Instantly share code, notes, and snippets.

@nicolasmelo1
Last active June 8, 2026 14:26
Show Gist options
  • Select an option

  • Save nicolasmelo1/25aaffa260138a450c62b6995feb5fb1 to your computer and use it in GitHub Desktop.

Select an option

Save nicolasmelo1/25aaffa260138a450c62b6995feb5fb1 to your computer and use it in GitHub Desktop.
Agent loop
#!/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