Opiniões fortes,
mantidas em código

Todo projeto tem crenças. A maioria delas vive na cabeça de alguém e vaza um code review por vez. Estas são as do Duct, escritas, cada uma com o arquivo que a impõe.

Duct é um agente de IA que lê todo o seu stack de produto e crescimento, e que pode alterar coisas nele. Isso é muita confiança para pedir de uma ferramenta que você não escreveu. Então o raciocínio é público, assim como o código que o sustenta.

Nada do que se segue é aspiracional. Cada princípio se conecta ao arquivo que o torna verdadeiro. Se você encontrar um onde o código discorda da página, isso é um bug e eu gostaria de receber o problema.

01

O agente propõe. Um humano aprova.

Duct pode preparar uma alteração nos seus sistemas ativos: pausar uma campanha, adicionar palavras-chave negativas, marcar um evento chave do GA4. Ele mostra uma prévia e uma verificação de segurança. Depois ele para.

Não há ferramenta de aprovação ou aplicação voltada para o agente. Nem uma desabilitada, nem uma atrás de uma flag. Ela não existe no registro de ferramentas que o modelo vê, então o modelo não pode chamá-la, não pode ser persuadido a chamá-la, e não pode ser injetado por prompt para chamá-la. O portão destrutivo é absoluto: nenhuma configuração permite que uma operação destrutiva seja auto-aplicada. Reverter faz parte do contrato de todo executor, não um item secundário.

Maior autonomia é uma postura, não uma lista de permissões mais ampla. Ela muda a frequência com que o agente te interrompe. Nunca muda o que pode ser aplicado sem um clique.

backend/service/execution/policy.py
02

Duct aluga uma estrutura de agente. Não se casa com uma.

Frameworks de agentes são a camada de maior rotatividade e menos diferenciada nesta pilha. Eles são 0.x, são lançados semanalmente, e cada um deles forçou uma migração disruptiva em alguém. Construir seu produto em cima de um é alugar uma fundação.

Assim, o código de domínio aqui não importa nenhum framework de agente. Prompts, ferramentas, esquemas, metas, pontuação e o contrato de artefato são Python puro. As importações de framework vivem apenas em runners e binders, e um teste impõe o limite com uma lista de permissões explícita. Adicionar um arquivo a essa lista de permissões é um ato deliberado, não a maneira de corrigir um teste vermelho.

Não há deliberadamente nenhuma interface AgentHarness, e nunca deveria haver uma. Pegue a interseção e você perde subagentes, sistema de arquivos, habilidades, granularidade e compactação HITL, que é a razão completa para alugar uma estrutura. Pegue a união e você está escrevendo um framework.

backend/agents/core/ports/__init__.py
03

Escreva o adaptador na segunda implementação, não na primeira.

Uma porta com uma implementação é um palpite. Uma porta com duas é um fato. Abstrações construídas antes que o segundo caso exista codificam o que o primeiro caso precisava, e então tudo depois luta contra a forma.

Toda porta na camada do agente tem dois adaptadores, exceto uma, e essa uma diz isso em sua própria docstring e nomeia a implementação que a mereceria. Nomear a lacuna é o que impede que ela seja preenchida silenciosamente com um palpite.

STYLE.md
04

Autorização é associação, e uma chave de API não é um limite.

A chave API do app é enviada para o navegador. Ela prova “esta requisição veio do app Duct”. Ela nunca provou “este chamador é proprietário daquela linha”, e tratá-la como se provasse é como vazam dados multi-tenant.

Assim, toda rota que toca uma linha com escopo de projeto resolve um usuário logado e verifica a associação. Um não-membro recebe 404, não 403, porque 403 lhes diz que a linha existe. Um teste percorre cada rota na árvore e falha a compilação se uma não tiver portão sem um motivo escrito.

backend/tests/test_route_auth_boundaries.py
05

Sua máquina, suas chaves, seus dados.

Duct funciona como um app para desktop que empacota o backend como um sidecar local: SQLite em disco, apenas loopback, chaves do provedor no chaveiro do SO. Sem conta, sem servidor, nada saindo da máquina. Ou hospede o backend por conta própria. Ou use a versão hospedada em getduct.ai, que executa o mesmo código que você pode ler.

Traga seu próprio modelo também. Anthropic, OpenAI, Gemini, ou qualquer coisa no OpenRouter, atribuído por tarefa em três níveis para que trabalhos que exigem muito raciocínio e resumos baratos não paguem o mesmo preço. Uma ferramenta que lê todo o seu negócio não deve também decidir quem é seu fornecedor.

desktop/README.md
06

Comentários carregam o porquê. O diff já mostra o quê.

Um comentário que reafirma a linha abaixo dele é pior do que nenhum comentário, porque ensina os leitores a pular comentários. Os que valem a pena escrever carregam o que o código não pode: a restrição, o contrato, a falha que motivou a linha, a alternativa que foi rejeitada e o porquê.

Isso importa mais, não menos, em uma base de código escrita parcialmente por agentes. Um conjunto de alterações individualmente defensáveis que juntas dissolvem uma arquitetura é a maneira específica como as bases de código aceleradas por agentes falham: cada alteração argumenta por si mesma e nada argumenta pelo todo. O raciocínio deixado no arquivo é o que permite à próxima pessoa, ou ao próximo modelo, perceber a diferença.

STYLE.md
07

Contribuições escritas por agentes são bem-vindas. Revisadas com mais rigor, não menos.

Muitos projetos estão silenciosamente banindo pull requests assistidos por IA. Duct pede o oposto: o template do PR pergunta onde um agente ajudou, para que um revisor saiba onde procurar com mais atenção. Isso não é uma caixa de penalidade. É o mesmo motivo pelo qual você diz qual parte de uma alteração você tinha menos certeza.

Duct é um produto agente construído com agentes. Fingir o contrário no processo de contribuição seria desonesto, e jogaria fora o sinal mais útil que um revisor pode obter.

CONTRIBUTING.md

Discorda?

Bom. Abra um issue.

Cada um desses é um padrão com um motivo, não uma lei. Se o motivo estiver errado, o motivo é o que deve mudar. Essa conversa pertence ao público.

Iniciar uma discussão → Leia o código →