📡 O que é ACP — JSON-RPC 2.0 sobre stdio
Bidirecional, simétrico, language-agnostic.
O que é
Agent Client Protocol é um protocolo proposto em agentclientprotocol.com para padronizar comunicação entre IDE/orchestrator e agente de coding. JSON-RPC 2.0 sobre stdio (stdin/stdout do processo do agente), bidirecional (cliente→agente e agente→cliente), simétrico (cada lado pode iniciar request).
// cliente envia
{"jsonrpc":"2.0","id":1,"method":"agent/run","params":{"prompt":"..."}}
// agente streams
{"jsonrpc":"2.0","method":"output/append","params":{"chunk":"Hello"}}
{"jsonrpc":"2.0","method":"todo/update","params":{"items":[...]}}
Por que aprender
É a aposta da indústria para "LSP do mundo de agentes". Hoje, cada IDE inventa protocolo (Cursor, Continue, Cline, Aider…). ACP padroniza. Saber ACP = entender futuro próximo da integração agente-IDE.
Conceitos-chave
- JSON-RPC 2.0: mesmo protocolo de LSP
- stdio transport: stdin/stdout, sem porta
- Bidirecional: agente pode pedir input ao cliente
- Simétrico: mesmo schema nos dois sentidos
- Implementações: Hermes, Kimi K2, Kiro, e crescendo
📞 Por que stdio (não HTTP)
Process isolation, language independence, sem porta.
O que é
stdio > HTTP para 3 razões:
- Process isolation: mata o processo = mata a sessão; sem socket leak
- Language independence: agente em Rust, Go, Python, Node — mesma interface
- Sem porta: sem conflito, sem firewall, sem auth
Por que aprender
Mesma decisão do LSP, MCP, Jupyter kernel. Padrão consagrado para tooling local: stdio reduz superfície de ataque, simplifica spawn de subprocess. Saber por que stdio = entender por que ACP encaixa naturalmente em IDEs.
Conceitos-chave
- child_process.spawn(): Node API canônica
- Newline-delimited JSON: 1 mensagem por linha
- stderr para logs: stdout só pro protocolo
- Process group: kill cascateia para children
🌳 Os 11 CLIs suportados — por stream format
Taxonomia em 6 famílias.
O que é
11 CLIs, 6 famílias:
Por que aprender
Cada família tem semântica de eventos diferente. Saber a taxonomia = saber por que adicionar um CLI novo cabe em uma das 6 (e não 7). Reduz superfície de adapter para tamanho conhecido.
Conceitos-chave
- claude-stream-json: evento por chunk, tool_use blocks
- json-event-stream: eventos tipados (output, tool_call, finish)
- acp-json-rpc: RPC bi-direcional
- plain: texto livre + sentinel string
🔍 Detecção automática no boot — PATH scan
O daemon descobre CLIs no startup.
O que é
No boot, o daemon escaneia $PATH procurando por executáveis conhecidos. Para cada match, registra a CLI no availableAgents:
async function detectAgents() {
const found = [];
for (const def of AGENT_DEFS) {
const path = await which(def.executable);
if (path) found.push({ ...def, path });
}
return found;
}
UI exibe lista; usuário escolhe.
Por que aprender
É a UX-chave do "BYOK em todas camadas": OD não vem com agente; usa o que você já tem. Saber o mecanismo = saber configurar PATH custom (ex: ~/bin/claude), debugar "agente não aparece", e adicionar CLI nova.
Conceitos-chave
- which() / npm which: resolução cross-platform
- PATH override:
OD_PATH=/custom/bin:$PATH - Re-scan: botão "Refresh agents" na UI
- Health check:
cli --versionantes de listar
🪟 Argv builders & promptViaStdin
Windows-friendly fallbacks.
O que é
Cada CLI espera prompt de jeito diferente:
- Argv:
claude "prompt aqui"— string como argumento - Stdin:
echo "prompt" | aider— pipe via stdin - File:
codex --input-file prompt.txt— referência a arquivo
Em Windows, argv tem limites de tamanho e quoting fora do padrão; fallback para stdin resolve.
Por que aprender
"Funciona no meu Mac" não basta. Adapter sério lida com Windows. Saber qual CLI usa qual transport = não falhar em deploy multi-OS.
Conceitos-chave
- argvBuilder(prompt) → string[]: função no AGENT_DEFS
- promptViaStdin: true: flag que ativa pipe
- Windows quoting: escape diferente de POSIX
- Tempfile fallback: prompt > 8k chars
📚 AGENT_DEFS — anatomia
A tabela canônica de CLIs em apps/daemon/src/agents.ts.
O que é
Cada entrada em AGENT_DEFS:
{
id: 'claude-code',
label: 'Claude Code',
executable: 'claude',
family: 'claude-stream-json',
argvBuilder: (prompt) => ['--no-color', '--stream-json', prompt],
promptViaStdin: false,
eventParser: parseClaudeStreamJson,
envVars: ['ANTHROPIC_API_KEY'],
}
Por que aprender
É onde se adiciona um agente novo. Sem editar código fora dessa tabela, novo CLI fica disponível. Se você precisa entender uma coisa só sobre adapters, é AGENT_DEFS.
Conceitos-chave
- id: chave única (kebab-case)
- family: qual dos 6 stream formats
- eventParser: referência a função em
apps/daemon/src/<family>-stream.ts - envVars: chaves API que precisam estar no env
- timeout, maxTokens: overrides opcionais
➕ Como adicionar um novo CLI
Uma entrada em AGENT_DEFS + um eventParser.
O que é
Receita em 4 passos:
- Identifique a família: CLI emite stream-json? json-event-stream? acp? plain?
- Reusa parser: se família existe, importe o parser correspondente
- Cria parser novo: se família nova, escreva
parseFooStream()emapps/daemon/src/foo-stream.ts - Adiciona em AGENT_DEFS: 1 entrada com id, executable, family, argvBuilder, eventParser
Reinicia daemon → CLI aparece no picker.
Por que aprender
A maioria dos times tem CLI custom (interna, fork, build próprio). Saber adicionar = não esperar PR no upstream. 15 minutos por CLI nova.
Conceitos-chave
- eventParser signature:
(line: string) → AgentEvent | null - AgentEvent types: output, tool_call, todo_update, finish, error
- Tests: golden file de stream + assert events
- PR upstream: CLIs públicos vão pro repo OD oficial
🛠️ Hands-on
Brief: Adicionar um adapter "fake" (mock CLI que responde com texto fixo) ao AGENT_DEFS e ver aparecer no picker.
- Crie executável fake: shell script
~/bin/fake-agentque fazecho "Olá! Sou o fake."e sai. - Registre em AGENT_DEFS: id
fake, familyplain, eventParserparsePlainStream. - Reinicie daemon:
pnpm tools-dev restart - Verifique picker: "Fake Agent" aparece. Inicie sessão e digite qualquer brief.
- Output esperado: "Olá! Sou o fake." aparece na resposta — confirma que pipeline está funcionando até o end.
Snippet de adapter
// apps/daemon/src/agents.ts
export const AGENT_DEFS = [
// ...existentes
{
id: 'fake',
label: 'Fake Agent',
executable: 'fake-agent',
family: 'plain',
argvBuilder: () => [],
promptViaStdin: true,
eventParser: parsePlainStream,
},
]
📚 Fontes
No repositório
apps/daemon/src/agents.tsdocs/agent-adapters.md(279L)apps/daemon/src/claude-stream.ts
Externas
- agentclientprotocol.com
- github.com/agentclientprotocol/agent-client-protocol
- Kiro ACP docs (kiro.dev/docs/cli/acp)
- JSON-RPC 2.0 spec
📌 Resumo do Módulo
1. ACP = JSON-RPC 2.0 sobre stdio bidirecional simétrico — "LSP de coding agents".
2. stdio > HTTP por process isolation, language independence, sem porta.
3. 11 CLIs em 6 famílias: claude-stream-json, copilot, json-event-stream, acp-json-rpc, pi-rpc, plain.
4. Boot scan via $PATH detecta CLIs e popula picker.
5. argvBuilder + promptViaStdin lidam com Windows quoting e tamanho de prompt.
6. AGENT_DEFS é a tabela canônica — single source of truth.
7. Adicionar CLI nova = 1 entrada em AGENT_DEFS + reuso ou novo eventParser.
Próximo módulo:
Módulo 3.3 · Brand-Spec Extraction →