Hefesto

Assistente de IA pessoal e local-first que conhece de verdade os meus repositórios: cita arquivo, linha e commit em vez de inventar, e coordena agentes de escrita sob aprovação humana explícita

2026
Capa do projeto Hefesto
Hefesto - chat
Como o front reconecta o stream sem perder eventos?

O endpoint mantém um log append-only por execução. Ao reconectar, o navegador envia o Last-Event-ID e a API reproduz só os eventos que faltaram, sem duplicar nada.

src/devmate/api/chat.py:118-142 · commit 4a7c9e1

Visão Geral

Hefesto nasceu de dois problemas do meu dia a dia como desenvolvedor: assistentes de IA genéricas alucinam sobre um repositório quando o contexto é só um recorte ad hoc, e ferramentas que 'escrevem código sozinhas' costumam esconder o quanto de autonomia real estão exercendo. Em vez de um chatbot plugado num repositório, é uma assistente com memória estruturada do histórico do projeto (commits → documentos → decisões → perguntas em aberto → conversas) e uma camada separada de execução autônoma, com aprovação humana obrigatória e isolamento real de escrita.

O que a assistente faz

Respostas com fonte, sempre

Toda resposta sobre documentação ou código cita path, linha inicial/final e hash do commit de onde a informação saiu. Sem evidência no repositório, a resposta diz isso em vez de inventar.

Conversa por voz ponta a ponta

Grava, transcreve localmente com Whisper (CPU), responde e narra de volta usando a Web Speech API nativa do navegador, sem pipeline de áudio extra nem chave de API obrigatória.

Streaming resiliente a reconexão

O chat em stream mantém um log append-only por execução; reconectar reproduz só os eventos que faltaram via Last-Event-ID, sem duplicar nem perder nada.

Escrita isolada e aprovada

A tela de agentes leva ao orquestrador de escrita: cada tarefa roda numa branch e worktree isolados, com aprovação humana explícita antes de qualquer mudança em disco.

O Desafio

  • Garantir que o chat em stream sobreviva a uma reconexão do navegador sem duplicar nem perder nenhum evento, mesmo com o EventSource tentando reconectar sozinho depois de uma resposta já ter terminado.
  • Fazer com que toda resposta cite arquivo, linha e commit reais, não uma aproximação: inventar uma citação seria pior do que admitir que não encontrou evidência.
  • Coordenar múltiplos agentes de IA sobre o mesmo repositório expôs um comportamento não determinístico: às vezes um provider respondia como se não tivesse acesso a um arquivo que estava, de fato, disponível no sandbox.

A Solução

  • Cada execução mantém um log append-only de eventos por trás do endpoint de stream; a reconexão usa o Last-Event-ID do navegador para retomar exatamente do ponto onde parou, em vez de reiniciar a resposta.
  • Escopo padrão é sempre 'só documentação'; código só entra com --scope code explícito, e cada resposta carrega path, linhas e hash do commit de onde a informação saiu, ou diz que não sabe.
  • A lição virou prática de engenharia: tratar toda resposta de agente como potencialmente inconsistente, nunca como uma chamada de função garantida, e isolar qualquer escrita em branch e worktree próprios, revisáveis antes de qualquer merge.

Arquitetura do Sistema

Três serviços locais independentes, cada um seu próprio repositório, conversando por HTTP em loopback e nunca expostos fora da máquina. O front web é a porta de entrada visual tanto do chat de documentação quanto do orquestrador de agentes de escrita.

[Front web] React 19 + TanStack Router/Query, localhost:5174, chat, timeline de commits, leitura em voz alta, tela de agentes
↓ HTTP local, contrato OpenAPI tipado
[Backend de chat] FastAPI, 127.0.0.1:8000, indexa commits/docs em SQLite, cita path + linha + commit em toda resposta
[Orquestrador de agentes] FastAPI, 127.0.0.1:8765, escrita isolada em branch/worktree, sob aprovação humana

O orquestrador de agentes é um projeto próprio, com página dedicada: veja o Maestro.

Local-First por Padrão Real

Local-first aqui não é discurso de marketing, é a premissa de projeto:

  • As três APIs escutam só em 127.0.0.1, sem autenticação, porque nunca deveriam sair da máquina; CORS restrito às origens locais conhecidas dos próprios dev servers.
  • Nada é escrito sem aprovação explícita, seja uma edição pontual de arquivo no chat ou uma tarefa completa de agentes, e a escrita é sempre isolada em branch e worktree próprios.
  • Redação de segredos em múltiplas camadas: variáveis de ambiente nunca entram na configuração persistida, e padrões de chave/token/senha são removidos de contexto, diffs, logs e respostas antes de serem gravados.
  • Comandos destrutivos de Git/terminal (git reset --hard, git push --force, rm -rf e equivalentes) são bloqueados por política, a menos que explicitamente confirmados.