Você pede ao seu copiloto de IA para capturar uma janela. O copiloto digita peek app "Xcode". A ferramenta procura uma janela cujo nome do proprietário seja exatamente Xcode. Não encontra, porque o processo se chama Xcode-16.3. A ferramenta imprime Erro: aplicativo não encontrado. O copiloto, que é um LLM e tem a memória emocional de um peixe dourado, tenta peek app "Xcode-16.3". Funciona. Mas custou uma interação, tokens de entrada, tokens de saída e a paciência de quem paga a conta.
Agora imagine outra versão: o copiloto digita peek app xcode. A ferramenta normaliza o nome, faz uma busca aproximada, encontra Xcode-16.3, captura a janela e retorna /tmp/peek/Xcode-16.3-1712524800.png. Um token de saída. Zero iterações desperdiçadas.
A diferença entre essas duas versões não é um bug. É uma decisão de design.
O usuário que não lê seu --help
No início de 2025, Mathias Biilmann (CEO da Netlify) cunhou o termo Agent Experience — AX — para descrever a experiência que agentes de IA têm ao interagir com um produto. Assim como UX é para humanos e DX para desenvolvedores, AX é para LLMs.
O conceito pode parecer abstrato até que você o aplique a algo concreto. Uma CLI, por exemplo. As CLIs vêm sendo projetadas para humanos há mais de quarenta anos: mensagens descritivas, cores, barras de progresso, páginas de --help. Tudo isso é ruído para um LLM. Um LLM não lê a ajuda — deduz os flags pelo nome do comando. Não aprecia o texto verde em “Success” — processa texto puro. Não olha uma barra de progresso — espera o processo terminar.
O design tradicional de CLIs otimiza para que um humano entenda o que está acontecendo. AX otimiza para que um agente aja com o mínimo de tokens e interações.
Cinco princípios, três ferramentas
Nos últimos meses, construí três CLIs com essa filosofia: peek (captura de janelas no macOS), lql (gestão de issues no Linear) e driftkit (auditoria de harness para agentes). Todas foram projetadas para que um LLM as use sem manual. Da experiência, surgiram cinco princípios.
1. O output é um contrato, não uma conversa
Uma CLI tradicional para capturar uma janela diria algo como:
✅ Captura salva com sucesso!
Arquivo: /tmp/peek/Xcode-1712524800.png
Tamanho: 1920x1080
Formato: PNG
Bonito. Informativo. E completamente inútil para um LLM que só precisa do caminho do arquivo para passá-lo a outra ferramenta. Ele teria que processar essa saída, ignorar o emoji, encontrar a linha que começa com Arquivo:, extrair o caminho. Tokens desperdiçados.
peek imprime uma coisa:
/tmp/peek/Xcode-1712524800.png
Um caminho. Nada mais. O LLM lê, usa e segue em frente. O output de stdout é um contrato: sempre um caminho, sempre legível, sempre confiável. Se você mudar o formato, quebra o contrato e todos os agentes que dependem da ferramenta.
Ou seja: seu stdout não é para decoração. É uma API.
2. Tolere alucinações — não as penalize
Os LLMs alucinam nomes. É um fato da natureza, como a gravidade ou o Wi-Fi falhar na hora errada. Se sua ferramenta exige nomes exatos, está pedindo precisão de uma máquina probabilística. Isso não vai dar certo.
peek tem três fases de busca para encontrar um aplicativo:
- Busca exata (insensível a maiúsculas):
xcode→Xcode - Busca normalizada (sem espaços nem hífens):
thinklocal→ThinkLocal - Busca aproximada:
xcode→Xcode-16.3
O LLM não precisa saber o nome exato do processo. Apenas diz algo próximo, e a ferramenta faz o resto. O mesmo acontece no lql com nomes de projetos e teams — ele resolve tokamak para Tokamak sem precisar de um UUID.
O princípio é simples: se o humano que supervisiona o agente pode deduzir o que ele quis dizer, a ferramenta também deveria.
3. Erros devem indicar o que fazer, não o que aconteceu
Compare esses dois erros:
Erro: aplicativo não encontrado na lista de janelas
Erro: "Xcode" não está em execução. Inicie-o com: open -a "Xcode"
O primeiro descreve o problema. O segundo resolve o problema. Um humano lê o primeiro e pensa “ah, não está aberto”. Um LLM lê o primeiro e… tenta outro nome, pesquisa no Google, ou inventa um flag --force. Com o segundo, o LLM executa open -a "Xcode", espera e tenta novamente. Problema resolvido com uma interação.
Outro exemplo. Quando peek não sabe a qual aplicativo você se refere porque o nome combina com vários:
Erro: "code" corresponde a múltiplos aplicativos:
Visual Studio Code
Xcode
Seja mais específico.
O LLM recebe a lista de opções, escolhe a correta e tenta novamente. Não precisa adivinhar nem procurar referências. Sua ferramenta fornece todas as informações necessárias para agir.
Regra: cada mensagem de erro deve conter um comando executável ou uma lista de opções válidas. Se o agente precisa “pensar” depois de ler seu erro, ele não é bom o suficiente.
4. Zero flags obrigatórias
Uma CLI comum para capturar janelas poderia exigir:
capture --app "Xcode" --format png --output /tmp/screenshot.png --window-id 12345
Quatro flags obrigatórias. O LLM precisa lembrar (ou adivinhar) todas elas. Para cada flag faltante, uma interação de correção.
peek só precisa:
peek app Xcode
O formato sempre é PNG. O output tem um default sensato (/tmp/peek/<app>-<timestamp>.png). A window ID é resolvida automaticamente buscando a maior janela. Se quiser personalizar algo, pode — --output, --panel. Mas não é obrigatório.
lql segue a mesma filosofia: lql create "Login falha com OAuth" classifica automaticamente tipo, prioridade, team e projeto com base no diretório de trabalho. Zero flags obrigatórias.
O princípio: defaults sensatos não são um conforto — são resiliência contra alucinações. Quanto menos parâmetros o agente precisar, menos ele pode inventar.
5. Captura silenciosa — não interrompa o agente
Essa é específica para o peek, mas ilustra um princípio geral: a ferramenta não deve interferir no fluxo do agente.
No macOS, capturar uma janela com screencapture exige trazê-la para frente. Isso rouba o foco do terminal onde o agente está ativo. O agente perde a janela ativa. É como tirar a chave de fenda de um eletricista no meio de uma instalação.
peek usa o ScreenCaptureKit com um filtro de conteúdo que seleciona uma janela individual pelo ID (SCContentFilter(desktopIndependentWindow:)). A janela é capturada exatamente como está, sem ativá-la, sem movê-la, sem tocar no foco. O terminal permanece como janela ativa.
Princípio geral: uma ferramenta projetada para agentes não deve ter efeitos colaterais visíveis. Nada de abrir janelas, exibir caixas de diálogo ou mensagens “Pressione Enter para continuar”. O agente opera em segundo plano — sua ferramenta também deveria.
Antes e depois
Resumo da comparação entre design tradicional vs design orientado a AX para as mesmas operações:
| Operação | CLI Tradicional | CLI AX-First |
|---|---|---|
| Output de captura | ✅ Capturado com sucesso em /tmp/... + metadados | /tmp/peek/App-123.png |
| App não encontrado | Erro: não encontrado | Erro: "X" não está rodando. Inicie com: open -a "X" |
| Nome inexato | Erro | Busca aproximada automática |
| Flags obrigatórios | 3-4 | 0 (apenas o argumento posicional) |
| Criar issue | --team T --type bug --priority 2 --project P | "Login falha" (classificação automática) |
| Rouba o foco | Sim (screencapture) | Não (ScreenCaptureKit) |
A coluna da direita não é apenas mais cômoda para LLMs. Também melhora a experiência para todo mundo. Esse é o ponto interessante: projetar para agentes geralmente aprimora a experiência para humanos também.
Como aplicar isso agora
Não é necessário reescrever suas ferramentas do zero. Comece com três mudanças simples que você pode implementar rapidamente:
Reveja seu
stdout. Se a ferramenta imprime algo que não é diretamente utilizável como entrada para outra ferramenta, isso é decoração, não output. Adicione um--quietou--jsonque retorne apenas os dados. Melhor ainda: faça disso o padrão.Audite suas mensagens de erro. Analise cada ocorrência de
Error:no código e pergunte: “Um agente poderia resolver isso sem contexto adicional?” Se a resposta for não, adicione um comando sugerido ou lista de opções válidas.Conte seus flags obrigatórios. Cada flag obrigatório é um ponto de falha para um agente. Ele pode ter um default sensato? Pode ser inferido a partir do contexto? Use diretórios de trabalho, arquivos de configuração ou nomenclaturas consistentes para evitar adivinhações.
O que ainda não funciona
Esses princípios não são uma solução mágica. Por exemplo, o mecanismo de busca aproximada do peek funciona bem na maioria dos casos, mas falha com nomes semelhantes — Code versus Xcode, por exemplo. Nesses casos, a ferramenta retorna uma lista de candidatos, e o agente precisa escolher, custando uma interação extra.
A inferência automática do lql (classificação automática de tipo, prioridade e equipe com base no texto da issue) acerta em cerca de 70% dos casos. Nos outros 30%, o agente precisa corrigir. É melhor do que exigir várias flags, mas longe de perfeito.
Além disso, o design de “output mínimo por padrão” tem um custo real: humanos que usam peek diretamente no terminal sentem falta de uma confirmação visual. Um caminho simples não gera a mesma confiança que um Salvo em... com metadados. O flag --verbose existe por um motivo.
Experimente
peek está disponível no Homebrew:
brew tap frr149/tap
brew install peek
peek app Safari
O código está em github.com/frr149/peek. Se você desenvolve CLIs para agentes (ou quer adaptar uma existente), abra um issue — estou curioso para ver como você aplica esses princípios ao seu caso.
O futuro é bilíngue
Não estou dizendo que você deve ignorar seus usuários humanos. Estou dizendo que suas ferramentas terão dois tipos de usuários: humanos, que querem um output legível, e agentes, que precisam de um output parseável. Projetar primeiro para o agente e, depois, adicionar a camada humana é mais fácil do que o oposto.
Um caminho no stdout é perfeito para um agente e aceitável para um humano. Uma mensagem cheia de emojis e cores é perfeita para humanos, mas infernal para um agente.
A direção do futuro é clara. As CLIs do futuro falam dois idiomas. Comece com o que não precisa de decoração.
Este artigo foi publicado originalmente em espanhol e traduzido com a ajuda de IA.