Caso de estudo de Gabriel Espinheira, engenheiro full-stack sénior
Relay, o meu próprio harness de IA
Uma app para macOS onde modelos de quatro fornecedores escrevem, desenham, falam e renderizam numa só pasta de projeto, com planos que já pago. Construí-a a dirigir agentes de programação: primeiro commit a 28/09/2026, v0.9.0 a 08/10/2026.
Uma ferramenta privada que só corre no meu Mac. Disponível para emprego a tempo inteiro e contratos.

O que o repositório diz
236
commits em 12 dias, a partir de 28/09/2026
7
versões marcadas em quatro dias, até à v0.9.0
163.636
linhas de TypeScript de produto
3.983
testes declarados em 543 ficheiros
73
ferramentas que os agentes chamam por MCP
4
agentes de chat, mais 9 geradores de media
Contado a partir do repositório a 09/10/2026, no commit d0aa1e5. Os números de testes são declarações no código, não uma execução de testes.
Bons modelos, nenhum estúdio
O meu estúdio, a SharpHaw, faz imagens, vozes, filmes e textos para clientes todas as semanas. O modelo que quero para cada trabalho está numa app diferente. Um modelo sozinho esquece o prompt por trás da imagem da semana passada, não consegue manter uma personagem igual entre planos e nunca olha para a frame que acabou de renderizar.
O Relay é o harness à volta desses modelos. Acrescenta cinco coisas que os modelos sozinhos não têm, e cada funcionalidade desta página responde a uma delas.
- Estrutura
- traços e briefings transformam-se no prompt
- Proveniência
- cada ficheiro guarda o prompt exato que o criou
- Consistência
- uma personagem ou uma voz mantém-se igual entre planos
- Escolha
- mudar de modelo a meio da sessão, criar ramos, comparar versões
- Feedback
- os agentes renderizam e inspecionam as suas próprias frames
Um projeto, todos os meios
Um projeto é qualquer pasta no meu Mac. O Relay guarda as sessões, os prompts e os media numa pasta relay/ ao lado dos ficheiros. Cada filme abaixo é uma gravação real do Relay 0.9.

Todos os agentes num só compositor
O Claude Code, o Codex, o Grok e o Antigravity correm atrás de um só contrato de fornecedor, cada um no seu próprio CLI com sessão iniciada. O Claude Code corre através do Agent SDK e o Codex através de um app server partilhado. O Grok e o Antigravity partilham um único adaptador Agent Client Protocol. Mude de agente a meio da conversa e o novo recebe a transcrição, cortada para caber em 24.000 caracteres.

O Auto escolhe o modelo para cada mensagem
Antes de cada vez no Auto, um modelo encaminhador escolhe o agente, o modelo e o esforço. Escolhe entre os modelos que ativei, conforme a rapidez com que cada subscrição está a ser gasta e uma tabela de encaminhamento feita a partir de benchmarks públicos. A resposta só conta se indicar uma dessas opções, e qualquer falha corre a vez no modelo por defeito.

Um estúdio onde o prompt fica com o ficheiro
Um artefacto é um ficheiro markdown cujo corpo é o prompt. Cada geração escreve um registo de execução ao lado do resultado, com o prompt, os parâmetros, o modelo e o tempo, para que qualquer imagem ou voz possa ser rastreada e refeita. As personagens constroem-se a partir de traços, e escrever o nome de uma personagem num prompt anexa a sua ficha.

Filmes escritos em código
Um filme é uma página HTML cuja função de seek pinta qualquer frame como função pura do tempo, com molas resolvidas em forma fechada. O Relay pré-visualiza-o ao vivo, renderiza-o com oito subframes de motion blur e mistura o som a −14 LUFS. Os agentes fazem lint aos seus próprios filmes, provam que cada frame se renderiza igual duas vezes e leem folhas de contacto do resultado.

Quadros onde os agentes desenham
Os canvas são quadros Excalidraw com cartões para artefactos, sessões e links. Os agentes leem-nos e desenham neles com seis ferramentas, e as minhas edições e as dos agentes fundem-se elemento a elemento. O quadro deste filme é o plano desta página, desenhado por um agente a partir de um só prompt.

Trabalho que corre sem mim
As rotinas correm instruções num horário dentro de um projeto, e o agendador lê o relógio a cada 15 segundos porque os temporizadores param quando um Mac adormece. Os subagentes dividem o trabalho de uma sessão entre agentes e reportam de volta. Os Bits são assistentes sempre ativos com memória própria. Só alteram um projeto através de uma tarefa, e só com o acesso que lhes dou.
Um daemon, clientes finos
Um só processo Node é dono de todos os projetos, sessões, agentes e ficheiros. O browser e a app Electron só o mostram. Os comandos seguem por HTTP, e cada alteração volta como um evento, reproduzido a partir de um buffer de 10.000 quando uma janela volta a ligar-se. Fechar todas as janelas nunca para uma vez.
O estado da app vive em SQLite, integrado no Node, com pesquisa de texto completo mantida em sincronia por triggers. O conteúdo dos projetos vive em ficheiros: prompts, registos de execução, filmes e gravações ficam na pasta do projeto, onde qualquer agente os pode ler.
Um registo de execução é um ficheiro, não uma linha.
- Separadores do browser
- A app Electron
Comandos HTTP, eventos SSE
Daemon do Relay · API Hono, registo de eventos, ferramentas MCP, terminais
Agentes · Claude Code, Codex, Grok, Antigravity
Geradores · GPT Image, Qwen3-TTS, ElevenLabs, Stable Audio, movimento
SQLite para o estado da app
Pastas de projeto para o conteúdo
Construído como se a web fosse hostil
O daemon corre agentes que executam comandos, numa porta a que qualquer página web chega. O README diz a todos os agentes para tratarem a web e o output dos modelos como hostis, e estas são as defesas que daí resultam.
Só local
O daemon liga-se a 127.0.0.1, aceita apenas o seu próprio cabeçalho Host contra DNS rebinding e rejeita pedidos de outros sites. Cada chamada precisa de um cookie HttpOnly ou do token de arranque, comparado em tempo constante.
Os agentes têm as suas próprias chaves
O endpoint MCP do Relay só aceita tokens por sessão guardados em memória, nunca o token de arranque. Os subagentes não podem delegar mais, e o conjunto de ferramentas de um Bit não tem shell nem ferramentas de projeto.
Os ficheiros ficam no projeto
Cada caminho é resolvido dentro da raiz do projeto antes de uma leitura ou escrita, nada escreve em .git, e o que se apaga vai para o Lixo.
O browser espera por uma pessoa
No browser do próprio Relay, as submissões, envios, pagamentos e eliminações de um agente esperam pelo meu Permitir, e o Permitir recusa se a página mudou entretanto.
Só endereços públicos
As pré-visualizações de links e os pedidos dos agentes só chegam a endereços públicos, verificados de novo na resolução DNS para que o rebinding não os troque.
Os filmes escritos por agentes correm em sandbox
Um filme é JavaScript escrito por um agente, por isso carrega numa frame em sandbox através de URLs de capacidade assinados por arranque e que expiram ao fim de seis horas.

As verificações que cada alteração tem de passar
As instruções do repositório dizem a todos os agentes de programação para escreverem primeiro o teste que falha. Uma alteração está feita quando passam o lint, os tipos e o conjunto completo de testes, e o hook de pre-push corre os três em cada push.
Um agente falso para testes reais
Um fornecedor falso e determinístico, guiado por palavras-chave no prompt, corre vezes inteiras de ponta a ponta sem gastar um crédito: ferramentas, aprovações, perguntas e falhas.
Regras de design como teste
Um teste aplica o sistema de design com sete listas de exceções de contagem exata. Um novo controlo em bruto fá-lo falhar, e também corrigir um antigo sem baixar a contagem.
Planos que admitem desvios
Cada um dos 30 planos de design termina com o que foi construído, como foi verificado e onde a construção se afastou do plano. O código ganha ao plano.
Uma versão recusada passou a barreira
A 08/10/2026, um merge de versão chegou ao main sem o seu commit de versão, e o fluxo de publicação recusou marcá-lo e abriu uma issue. Seguiu-se uma nova verificação nos pull requests de versão, e a v0.9.0 saiu cerca de dez minutos depois.
Doze dias, um autor, muitos agentes
Todos os commits têm o meu nome, e o trabalho aconteceu em sessões de agentes. Os meus registos locais têm cerca de 250 sessões do Claude Code e 164 do Codex no repositório. O Relay corre sessões sobre si próprio desde 30/09/2026.
Sou responsável por código que não escrevi através do que o rodeia. Cada funcionalidade grande começa com um plano escrito, todos os agentes leem as mesmas regras e as verificações acima têm de passar antes de qualquer push.
O primeiro código do Relay chegou quatro horas depois do esqueleto, num commit de 17.941 linhas com 216 testes. Os filmes dos casos de estudo SharpOS e Taste Vault foram compostos e renderizados no motor de movimento do Relay e depois codificados para a web.
| Dia | Commits |
|---|---|
| 28/09 | 3 |
| 29/09 | 19 |
| 30/09 | 18 |
| 01/10 | 50 |
| 02/10 | 17 |
| 03/10 | 17 |
| 04/10 | 18 |
| 05/10 | 27 |
| 06/10 | 30 |
| 07/10 | 24 |
| 08/10 | 7 |
| 09/10 | 6 |
Uma decisão difícil: filmes como função do tempo
Problema
Os agentes tinham de fazer motion graphics com texto, interface e marca exatos, e pré-visualizá-los ao vivo. Cada frame tinha de sair igual todas as vezes, para que as renderizações, as verificações e as correções fossem de confiança.
Opções
Um modelo de vídeo não consegue manter texto exato nem uma marca, e cada correção obriga a pagar uma nova geração. O Remotion precisa de um bundle React por filme e de uma licença de empresa paga para o meu estúdio.
Escolha
Uma página HTML com uma função de seek e um pequeno motor incluído no código. Cada valor animado é uma mola amortecida avaliada no instante t, sem estado entre frames, para que qualquer frame possa ser pintada por qualquer ordem. Isso torna possíveis o motion blur, a renderização em paralelo e uma verificação de determinismo.
Temporizadores, animation frames, transições CSS e números aleatórios ficam proibidos pelo lint.
Custo
Os agentes têm de escrever num estilo restrito e passar o lint. A renderização é offline e pesada: os filmes deste site levaram 2 a 8 minutos cada a 1080p, e 83 a 131 minutos com supersampling a dobrar.
Uma decisão mais pequena: um daemon Node num repositório Bun
O repositório corre em Bun, mas o daemon corre em Node com o seu SQLite integrado, porque o Claude Agent SDK e o conjunto de testes visam o Node. O custo são dois runtimes num repositório, nenhuma API do Bun no servidor e uma API experimental de SQLite guardada atrás de uma só função.
Precisa de alguém responsável pela construção?
Estou disponível para uma função a tempo inteiro ou para um projeto por contrato. Leio todas as mensagens pessoalmente e respondo em 2 dias úteis.
- Função a tempo inteiro
Um engenheiro sénior na sua equipa
Remoto no horário europeu, ou híbrido e presencial em Lisboa.Falar sobre uma função - Projeto por contrato
O seu produto, de ponta a ponta
Web, desktop e mobile em TypeScript, Next.js, Convex e Expo, incluindo funcionalidades de IA.Falar sobre um projeto
