Pular para conteúdo

Motor Hermes supervisionado

Pipeline do PD Framework que implementa issues planejadas, faz revisão independente e prepara PRs para aprovação humana sem entregar credenciais externas ao agente.

Por que foi construído assim

O cron Hermes anterior concentrava planejamento, implementação, revisão, PR e tracking numa sessão longa. O novo motor divide o trabalho em três estágios independentes e usa ticks curtos para recovery. O worker executa como LocalService sem GitHub, Linear ou 1Password; um controller determinístico revalida evidências e executa somente efeitos externos allowlisted.

Essa separação reduz auto-revisão, torna handoffs obrigatórios e permite recuperar execução após timeout, reboot ou falha parcial sem adivinhar o estado.

Stack

Camada Tecnologia
Linguagem Python
Runtime de agente Hermes Agent com openai-codex
Isolamento de processo Windows LocalService, Scheduled Tasks e Job Objects
Estado confiável claims, fencing e manifests controller-only em ProgramData
Transporte de código Git bundle + evidence importados em quarentena controller-only
Integrações externas Linear e GitHub CLI somente no controller
Onde roda máquina Windows dedicada ao Hermes

Como funciona

flowchart TD
    classDef component fill:#D1FAE5,stroke:#10B981,color:#111
    classDef flow fill:#DBEAFE,stroke:#3B82F6,color:#111
    classDef decision fill:#EDE9FE,stroke:#8B5CF6,color:#111
    classDef core fill:#FEE2E2,stroke:#EF4444,color:#111
    classDef warning fill:#FEF9C3,stroke:#EAB308,color:#111

    subgraph SG_component["Componentes"]
        controller["Controller determinístico"]
        worker["Worker LocalService"]
        launcher["Launcher + gates"]
    end
    class controller,worker,launcher component

    subgraph SG_flow["Fluxo do processo"]
        eligible["1. Issue elegível"]
        impl["2. Implementation (22h)"]
        quality["3. Quality (06h)"]
        final["4. Finalization (10h)"]
    end
    class eligible,impl,quality,final flow

    subgraph SG_decision["Decisões"]
        tick["Tick */15"]
        valid["Resultado válido?"]
        publish["Sim: publicar handoff"]
        human["Gate humano"]
    end
    class tick,valid,publish,human decision

        title["Motor Hermes supervisionado"]
    class title core

        blocked["Não: falhar fechado"]
    class blocked warning

    title -->|"componentes"| controller
    title -->|"entrada"| eligible
    title -->|"supervisão"| tick
    controller -->|"lança com spec"| worker
    worker -->|"resultado + bundle"| launcher
    eligible -->|"22h"| impl
    impl -->|"handoff"| quality
    quality -->|"PR draft"| final
    tick -->|"run terminou"| valid
    valid -->|"sim"| publish
    valid -->|"não"| blocked
    publish -->|"ready"| human

Uma issue começa em Todo/Backlog, já planejada e com own:hermes, hermes:ready e hermes:planned. O implementation pode iniciar às 22h, entrega código e handoff sem abrir PR. O quality review pode iniciar às 06h, revisa/corrige e abre apenas PR draft. O finalizer pode iniciar às 10h, revalida tudo e converte o draft para ready for human.

Cada cron acorda a cada 15 minutos, mas fora da sua janela apenas reconcilia execução em andamento, coleta resultados, trata timeout/reboot e faz cleanup seguro. Um mutex global mantém somente um worker ativo entre os três estágios.

Decisões técnicas

  • Controller e worker em trust domains diferentes: o worker não possui credenciais de publicação.
  • Handoff persistido obrigatório: sem manifest/handoff válido, o próximo estágio não começa.
  • Bundle em vez de Git privilegiado no repo do worker: metadata Git controlada pelo agente nunca é executada pelo controller.
  • Fail-closed em toda fronteira: ACL, host fence, task, Job Object, plano, scope, diff, gates, PR e postconditions precisam bater.
  • Aprovação humana: o motor nunca aprova ou mergeia PR.

Gotchas & armadilhas

  • Tick não significa launch*/15 supervisiona; launches são restritos a 22h/06h/10h.
  • Três labels são cumulativas — faltar uma delas torna a issue inelegível.
  • Plano é contrato — precisa existir na main e declarar ## Escopo de arquivos.
  • Python do scheduler difere do shell — validar pywin32 no processo real no_agent.
  • Cleanup é fail-closed — não remover run/repo até task e Job Object estarem comprovadamente ausentes.

Como operar

python _core/hermes_worker_bootstrap.py verify
python _core/hermes_supervised_pipeline.py smoke
python -m unittest _core.test_hermes_worker_isolation _core.test_hermes_supervised_pipeline _core.test_hermes_supervisor_adversarial _core.test_hermes_worker_bootstrap _core.test_hermes_stage_launcher _core.test_hermes_cron_entrypoints

Os jobs operacionais usam workdir C:\ProgramData\PD-Hermes-Control\pd-framework, no_agent=true e schedule */15 * * * *.

FAQ

Como uma issue entra no pipeline? Ela deve estar em Todo/Backlog, ter plano publicado em times/dev/context/plano-<ISSUE>.md e as labels own:hermes, hermes:ready e hermes:planned.

Ele implementa uma issue a cada 15 minutos? Não. O tick frequente serve para supervisão e recovery. Novo implementation só começa na janela das 22h.

Quem abre o PR? Somente o controller, depois do Quality Review, e sempre como draft.

Quem aprova e mergeia? Felipe. Worker e controller são tecnicamente impedidos de aprovar ou mergear.

AppContainer é obrigatório? Não neste host dedicado, por decisão explícita de risco. Continua como hardening opcional.