Engenharia reversa do Hermes
O Hermes Agent é o "agente de IA auto-aperfeiçoável" da Nous Research — uma base de código Python de mais de um milhão de linhas. Você não pode fundir o que não entende, então a fusão começou com um mapa. Esta lição é o núcleo desse mapa: o que o Hermes é, a única ideia estrutural que o torna extensível, e o ciclo fechado de aprendizado que se tornou a razão inteira da fusão.
Esta lição destila esse mapa (§1, §5, §6) + os repos satélites. Todos os números têm fonte (rodapé). Por que importa pra missão: é o degrau que decide o que do Hermes vale clonar para dentro do Alembic — assunto da Lição 03.
- Descrever o que o Hermes é: um núcleo de agente único rodando em várias superfícies (CLI, gateway, TUI, desktop).
- Explicar as duas restrições de design das quais tudo decorre — cache de prompt sagrado e cintura estreita.
- Reconhecer o linchpin portável: tools que se auto-registram no import via
registry.register(...). - Separar os três números (87 / 30 / 64) e dizer o que cada um mede de fato.
- Traçar o ciclo fechado de aprendizado (§1.10) peça a peça — e por que ele é um fork.
Realidade de escala: o mapa não é uma leitura linha-a-linha de todas as 1,18M LOC — ele aprofunda as prioridades e cataloga a cauda longa, com a fronteira de cobertura declarada explicitamente. Fonte: docs/hermes-complete-map.md §1, §6.
01 · O que é o Hermes
Antes de mapear peças, fixe a forma do todo. Em uma frase: o Hermes é um agente de IA pessoal que roda o mesmo núcleo de agente em várias superfícies — uma CLI, um gateway de mensagens (Telegram, Discord, Slack e ~20 outras plataformas), uma TUI Ink/React e um app desktop Electron. Construído pela Nous Research, licença MIT.
A analogia: um cérebro, muitas bocas
Pense num atendente que é a mesma pessoa esteja você falando com ele pelo telefone, pelo balcão ou por carta. O "cérebro" (o núcleo de agente) é um só; o que muda é a superfície por onde você chega até ele. É esse desenho — núcleo único, muitas bordas — que vai ecoar no Alembic.
Seus diferenciais de destaque, nas próprias palavras dele:
- Um ciclo fechado de aprendizado — memória curada pelo agente com cutucadas periódicas; criação autônoma de skills após tarefas complexas; skills que se auto-aprimoram durante o uso; busca de sessão FTS5 com sumarização por LLM para recall entre sessões. a parte que importa para nós
- Agnóstico de modelo — Nous Portal, OpenRouter (200+ modelos) e muitos outros; troque com
hermes model, sem mudanças de código. - Vive onde você vive — um processo gateway faz ponte entre Telegram / Discord / Slack / WhatsApp / Signal / CLI, com transcrição de áudio-memo.
- Delega e paraleliza — gera subagentes isolados para fluxos paralelos.
- Roda em qualquer lugar — seis backends de terminal atrás de uma ABC: local, Docker, SSH, Singularity, Modal, Daytona.
O "roda em qualquer lugar" tem a mesma estrutura do núcleo único: uma interface abstrata (ABC) esconde seis implementações de terminal. O agente fala com a ABC; trocar de execução (local → Docker → nuvem) não muda o código que a usa.
02 · As duas restrições de design das quais tudo decorre
Quase toda decisão estranha no Hermes faz sentido quando você conhece duas restrições. Elas não são detalhes — são o motivo de o sistema ter a forma que tem. Veja as duas primeiro em linguagem simples, depois no nível preciso.
2 · O centro é pequeno de propósito. Toda ferramenta do centro viaja em toda chamada ao modelo — então pôr coisa nova lá custa caro pra sempre. Capacidade nova entra pela borda (um comando + skill, ou um plugin), não pelo miolo.
1 · O cache de prompt por conversa é sagrado. Uma conversa longa reusa um prefixo em cache a cada turno; qualquer coisa que mute o contexto passado ou reconstrua o system prompt no meio da conversa invalida o cache e multiplica o custo. A única exceção sancionada é compressão de contexto. 2 · O núcleo é uma cintura estreita; capacidade vive nas bordas. Toda tool de modelo é enviada em toda chamada de API, então a barra para uma nova tool de núcleo é alta — nova capacidade chega como um comando de CLI + skill ou um plugin, não como superfície de núcleo.
Note a rima com a Lição 1: Hermes e Alembic chegaram independentemente a "uma cintura estreita + prompt estável de cache". Esse instinto compartilhado é exatamente por que a fusão compõe em vez de brigar — e é o fio que puxamos na Lição 3.
03 · O linchpin: a arquitetura de auto-registro de tools
Esta é a ideia estrutural mais importante e mais portátil do Hermes — a peça que mais vale clonar. Em uma linha: as tools se auto-registram no momento do import; nada mantém uma lista central de imports.
A analogia: cada funcionário se apresenta ao chegar
Imagine uma recepção onde, em vez de o gerente manter uma lista de quem trabalha lá, cada funcionário assina o livro de ponto ao entrar. Para saber quem está no prédio, basta abrir a porta de cada sala — ninguém precisa atualizar uma lista mestre. É exatamente assim que as tools entram no registro do Hermes.
No concreto: cada arquivo de tool chama registry.register(...) no nível de módulo; um passo de descoberta faz glob no diretório e importa cada arquivo, e o side-effect do import popula o registro. Acompanhe a pilha de baixo para cima:
tools/*.py e cada um chama registry.register(...). Logo, todas as 87 tools ficam disponíveis para o agente conversar, certo? Pense antes de revelar.
toolsets.py (são 30 chaves). Vários dos 87 arquivos são infra — registry.py, scanners de segurança, helpers — e nem são tools voltadas ao agente. Se você respondeu "sim, 87", caiu na confusão mais comum do mapa — desfeita na seção 05.Por que o registry.py fica embaixo da pilha, sem dependências? Porque ele é o contrato: tudo o mais depende dele, e ele não depende de nada. São quatro responsabilidades concentradas num único lugar — é isso que permite que cada tool seja só um arquivo que se anuncia.
04 · O catálogo de tools (mapa por toolset)
Como o Hermes empacota capacidade? Pelas chaves de toolset de toolsets.py — bundles nomeados que uma plataforma herda. O mapa cita explicitamente browser, memory, skills e web como exemplos dessas chaves; somados aos diferenciais que nomeiam capacidades concretas (transcrição, subagentes, busca de sessão), eles desenham o catálogo. Use o mapa abaixo como índice — cada caixa é uma família, com as portagens que cada uma rende ao Alembic na Lição 03.
As chaves browser, memory, skills e web são nomeadas explicitamente no mapa (§1.9); transcrição, subagentes e busca de sessão FTS5 vêm dos diferenciais de §1.1. As "+ ~26 outras" são o restante das 30 chaves de toolset — [uncertain] o mapa não lista as 30 por nome, então só rotulamos as citadas.
| Família (toolset) | O que faz | Vira no Alembic (Lição 03) |
|---|---|---|
| memory | Lê/escreve a memória durável (MEMORY.md / USER.md). | MemoryStore (Lição 07) |
| skills | Cria e atualiza skills do agente. | SkillStore (Lição 12) |
| web | Busca e extrai conteúdo de páginas. | webSearch / webExtract (Lição 11) |
| transcrição | Converte áudio-memo em texto. | transcribe / analyzeImage (Lição 13) |
05 · 87 / 30 / 64 — três números, três significados
Há uma nuance crucial em que o mapa insiste — e é a fonte de um número que é mal-citado. A auto-descoberta registra o schema de uma tool, mas a tool só é exposta a um agente se seu nome aparecer num toolset. Então três contagens diferentes descrevem três coisas diferentes — não as colapse num número só.
| Contagem | O que realmente mede |
|---|---|
| 87 | arquivos de tool em tools/*.py (verificado ls | wc -l). Inclui arquivos de infra como registry.py, scanners de segurança e helpers compartilhados — nem todos são tools voltadas ao agente. |
| 30 | chaves de toolset em toolsets.py (browser, memory, skills, web, …) — os bundles nomeados que uma plataforma herda. |
| "64 tools" | O número que o material de aprendizado orange-book cita para tools voltadas ao agente. Mantemos a distinção arquivo/tool explícita em vez de colapsar os três num número só. |
Sinta o funil você mesmo
Arraste para ver como a fração exposta muda. Mesmo registrando todos os arquivos, só os que estão num toolset chegam ao agente — a barra mostra a fração que de fato aparece para ele:
Resolva você: "essa tool chega ao agente?"
Você já viu a regra (registrar ≠ expor). Agora aplique-a passo a passo a um caso concreto — depois um exercício é seu. Recuperar o procedimento (não só ver o veredito) é o que fixa de verdade.
tools/browse_pdf.py. O passo de descoberta faz glob em tools/*.py e o importa — então o import roda.registry.register(...) no nível de módulo. Logo o schema entra no registry (engrossa a contagem dos 87 arquivos).toolsets.py. Se ele não está em nenhuma das 30 chaves → não é exposta, o agente não a vê.browser ou web).tools/registry.py aparece nos 87. Um agente pode chamar registry como uma tool? Decida antes de revelar.
registry.py é infra — ele é o balcão de registro, não uma tool voltada ao agente, e seu nome não está em nenhum toolset. Por isso ele conta nos 87 arquivos mas não nas ~64 tools do orange-book. Dica: o procedimento é sempre o mesmo — arquivo → registra → está num toolset? — e é exatamente a diferença entre 87 e 64.06 · O ciclo fechado de aprendizado — o "auto-aperfeiçoável", mecanicamente (§1.10)
A propriedade de destaque é concreta no código, não marketing. Após um turno, o agente pode forkar a si mesmo para revisar o que acabou de acontecer e decidir se algo vale a pena lembrar — e as escritas caem em stores duráveis que a próxima sessão lê.
A analogia: um estagiário que toma notas depois da reunião
Pense num estagiário que, depois que a reunião acaba, relê a ata e anota no caderno da equipe o que valeu aprender — sem nunca interromper a reunião em si. A reunião (a conversa viva) segue intocada; as notas (memória durável) só são lidas na próxima reunião. É literalmente assim que o Hermes "se aperfeiçoa": de forma diferida, num fork.
As peças, cada uma concreta na fonte:
- Fork de revisão de fundo (
agent/background_review.py): após um turno,spawn_background_reviewdispara uma thread daemon que reproduz o snapshot da conversa numAIAgentforkado e pergunta "alguma skill/memória deve ser salva ou atualizada?". Roda com uma whitelist de tools limitada a tools de memória + gerenciamento de skill apenas, e herda o system prompt em cache do pai literalmente — então acerta o mesmo prefix cache e nunca toca a conversa viva. - Cutucadas de skill: o loop incrementa um contador
_iters_since_skille cutuca o modelo a persistir uma skill após iterações suficientes de chamada de tool. - Curador (
agent/curator.py): auto-gerencia o ciclo de vida de skills criadas pelo agente — active → stale → archived, nunca deleta, skills pinadas isentas, só skillscreated_by: "agent"tocadas. - Memória vive dentro do prompt: o tier
volatiledo system prompt segura o snapshot de MEMORY.md + USER.md, que é exatamente por que são congelados no início da sessão — mutá-los no meio da sessão quebraria o cache.
Por que "congelar no início da sessão"? Porque a memória mora dentro do system prompt — e o system prompt é justamente o prefixo que o cache reusa. Veja onde o snapshot fica e por que ele tem de ficar imóvel durante a sessão:
E como o fork escreve memória sem invalidar o cache que ele próprio usa? Ele herda o mesmo prefixo: o revisor reaproveita o system prompt em cache do pai, então acerta o mesmo cache e suas escritas vão para o disco, não para a conversa.
O ciclo de vida do curador, como autômato
O curador nunca deleta — ele move skills entre estados. Acompanhe as transições; repare que dois estados são protegidos (skills pinadas e as não criadas pelo agente nunca entram no ciclo):
Para o Alembic, este ciclo inteiro — fork-após-turno → auto-revisão sob uma whitelist só de memória/skill → escrever em stores duráveis → ciclo de vida do curador → próxima sessão lê o snapshot atualizado — é o CLONE conceitual de maior valor, e compõe limpo com o pipeline de validador/portão existente do Alembic.
07 · A disciplina do mini-loop (§5)
O repo hermes-mini-loop é uma implementação de referência mínima da mesma ideia, e declara a disciplina como três regras — as regras que impedem um ciclo de auto-aperfeiçoamento de se afogar no próprio ruído. Sem elas, um loop que aprende de tudo rapidamente se envenena.
| Regra | O que previne |
|---|---|
| Aprender só de vitórias (score ≥ 0.7) | Sedimentar lições de turnos falhos ou de baixa confiança. Só sucessos validados viram memória durável. |
| Reforçar, não duplicar | Rever o mesmo fato deve fortalecer a entrada existente, não anexar uma quase-cópia que incha o store limitado. |
| Recombinar átomos provados | Novas skills são compostas de peças já validadas em vez de inventadas do zero — melhoria por recombinação. |
Segure o limite 0.7 e o "reforçar-não-duplicar" — ambos reaparecem, portados literalmente, como o portão padrão e o comportamento de dedup do ciclo do Alembic na Lição 4.
08 · Confusões comuns
Três armadilhas que aparecem sempre que alguém descreve o Hermes de memória. Cada uma vira uma das questões da revisão — guarde-as.
providers/ + plugins/model-providers/ + um proxy local compatível com OpenAI — um subsistema inteiramente diferente.tools/. A exposição é controlada pelas 30 chaves de toolset; o orange-book conta ~64 tools voltadas ao agente. Três números, três significados.Como isso se encaixa
Esta lição não é um beco sem saída — é o primeiro elo de uma cadeia que termina em código rodando dentro do Alembic. O método de engenharia reversa (esta lição) produz dois mapas; os mapas alimentam a matriz de fusão; a matriz decide o que clonar; e o que foi clonado virou os subsistemas de @alembic/hermes que você vai abrir um a um nas Lições 07–13. Siga a cadeia — clique para iluminar cada degrau.
Os elos concretos — cada um leva à lição que aprofunda aquele degrau:
- Lição 03 · A matriz de fusão — o destino direto deste mapa: é onde cada capacidade do Hermes recebe um veredito CLONE/ADAPT/MERGE/IGNORE. Sem o mapa desta lição, a matriz não tem o que decidir.
- Lição 20 · O método de engenharia reversa — generaliza o que você acabou de ver num caso só: o procedimento reusável de "ler antes de fundir", aplicável a qualquer agente, não só ao Hermes.
- Lição 21 · O framework de fusão — formaliza os quatro vereditos (CLONE / ADAPT / MERGE / IGNORE) que a matriz da Lição 03 aplica item a item.
- Lições 07–09 · MemoryStore, reviewAndLearn, UsageStore + curador — o ciclo fechado da seção 06 desta lição, já embarcado: a memória durável, o passe de revisão e o ciclo de vida do curador, agora em TypeScript testado.
- Lições 10–13 · ClarifyGateway, web, SkillStore, mídia — as outras famílias de toolset do catálogo da seção 04, cada uma virou um subsistema concreto do pacote
@alembic/hermes.
No motor todo do Alembic (contratos → adapters → council → swarm → harness → gates → loop de aprendizado), esta lição vive antes do código: é a fase LEARN do loop-engineering aplicada a um sistema externo. Você está mapeando um agente alheio para decidir, com prova, o que merece entrar no nosso. O resultado dessa fase é exatamente o que as Lições 07–13 mostram já rodando. Para ver o motor inteiro de uma vez, comece pelo hub do curso. [uncertain] não existe um mapa interativo ../metodologia.html no diretório course/ (só index.html e galeria.html) — então apontamos para o hub real e para a Lição 20, que é a lição-método do curso.
Na prática
Mapa é teoria; o subsistema embarcado é executável. Aqui você inspeciona com as próprias mãos o que esta lição mapeou — primeiro provando que o subsistema clonado passa nos testes, depois vendo o loop de aprendizado escrever e ler de uma store durável real. Tudo offline, $0, determinístico.
1 · Prove o subsistema embarcado
O ciclo fechado de aprendizado da seção 06 não ficou no papel — virou o pacote @alembic/hermes. Rode a suíte dele:
# a partir da raiz do repositório pnpm --filter @alembic/hermes test # exercita os subsistemas que este mapa decidiu clonar: # memory/ learning/ curator/ clarify/ web/ skills/ media/ # saída esperada (vitest): # ✓ src/memory/memory-store.test.ts # ✓ src/learning/review.test.ts # ✓ src/curator/curator.test.ts # Test Files N passed (N)
Os arquivos de teste existem em packages/hermes/src/<subsistema>/*.test.ts (verificado). [uncertain] o número exato de testes/arquivos varia com a versão do repo — por isso não fixamos um total aqui; rode e leia a linha Test Files.
2 · Veja o loop de aprendizado escrever e ler
A peça-âncora desta lição é o ciclo fechado: escrever em stores duráveis que a próxima sessão lê. O CLI expõe exatamente essas stores via alembic memory — cinco substores append-only (episodic, semantic, procedural, decision, transcript). Anexe um aprendizado e depois liste-o:
# anexa um registro à store "semantic" (offline, append-only JSONL) alembic memory semantic add --agent cli --record '{"text":"87 = arquivos, 30 = chaves de toolset"}' # saída esperada: # memory semantic: appended <id> (agent cli) # <dataDir>/memory/semantic.jsonl # lê de volta — newest-first — o que a "próxima sessão" enxergaria alembic memory semantic list --agent cli # saída esperada: # memory semantic: 1 record(s) under <dataDir>/memory/semantic.jsonl # <id> [agent cli] at <timestamp>
Sinopse real (de apps/cli/src/args.ts + index.ts): alembic memory <substore> <add|list> [--agent <id>] [--dir <path>] [--record <json>] [--limit <n>]. add exige --record <json>; list aceita --agent/--limit; a store padrão é <dataDir>/memory/<substore>.jsonl. É o mesmo "MemoryStore" da Lição 07, pela borda da CLI.
cd no clone do Alembic e rode pnpm install (uma vez). Os comandos abaixo rodam da raiz.pnpm --filter @alembic/hermes test e confirme a linha Test Files … passed — é o ciclo da seção 06 já embarcado e verde.alembic memory semantic add … acima. Procure na saída o appended <id> e o caminho do arquivo semantic.jsonl.alembic memory semantic list e veja o registro voltar, newest-first — é literalmente o "a próxima sessão carrega o snapshot" da seção 06, do disco. Abra o semantic.jsonl para ver a linha JSON crua que você acabou de escrever.Fixe os conceitos (flashcards)
Clique pra virar. Tente lembrar a resposta antes de virar — recuperação ativa fixa mais que reler.
registry.register(...) no import; a descoberta faz glob e importa, e o side-effect popula o registro. Nada mantém lista central.Revisão cumulativa — recupere de memória
Antes de clicar: responda de cabeça. As quatro opções têm o mesmo tamanho de propósito — sem pista pela forma.
_iters_since_skill), outra parte do loop. d é trabalho do curador (ciclo de vida das skills), não do piso de aprendizado.