Delegar uma tarefa a outro agente CLI
Executa uma tarefa em um agente CLI externo em segundo plano e retorna um resultado normalizado.
Driver: delegate.mjs, no próprio diretório desta skill (Node ≥ 18, sem dependências).
O comportamento é definido por três contratos em contracts/ — leia-os antes de alterar o driver.
start retorna um run_id imediatamente; collect recupera o resultado. Nada bloqueia você.
Resolva o driver e o diretório de execuções primeiro
Onde esta skill está instalada define onde delegate.mjs reside, e os artefatos de execução
ficam, por padrão, ao lado do driver. Defina ambos uma vez por sessão e, em seguida, use
$DELEGATE em cada comando abaixo:
# Instalação como plugin do Claude Code (agent-tools@sanduq)
DELEGATE="$CLAUDE_PLUGIN_ROOT/skills/delegate-task/delegate.mjs"
# npx skills install, ou uma cópia commitada no repositório
DELEGATE=".claude/skills/delegate-task/delegate.mjs"
# Mantenha os artefatos de execução no projeto em que está trabalhando, não ao lado do driver
export DELEGATE_RUNS_DIR="$PWD/.delegate/runs"
DELEGATE_RUNS_DIR é obrigatório para uma instalação como plugin: sem ele, artefatos de cada
projeto se acumulam dentro do diretório compartilhado do plugin, e eles contêm o texto da sua
tarefa e a saída bruta do agente. Adicione .delegate/ ao .gitignore do projeto. Todos os comandos
que tocam uma execução — start, status, collect, list, prune — devem ver o mesmo valor.
Verifique o que está disponível primeiro
node "$DELEGATE" doctor
doctor testa a versão de cada CLI, distinguindo não instalado de instalado mas quebrado
— e imprime o que --sandbox realmente solicita de cada um deles.
| Agente | id | nível | continuar | solicitações de --sandbox |
|---|---|---|---|---|
| Claude Code | claude | verificado | verificado | --permission-mode plan |
| OpenAI Codex | codex | verificado | verificado | -s read-only (imposto pela CLI) |
| OpenCode | opencode | verificado | verificado | --agent plan |
| GitHub Copilot | copilot | experimental | experimental | --mode plan |
| Pi | pi | experimental | experimental | --no-approve --tools read,grep,find,ls |
Prefira claude, codex, ou opencode.
Execute uma delegação
node "$DELEGATE" start \
--harness codex \
--cwd /caminho/para/workspace \
--timeout 600 \
--task "Adicione validação de entrada em parse_config() e um teste cobrindo o caminho de entrada inválida."
Imprime {"run_id": "codex-…", "state": "running", ...} e retorna. Em seguida:
node "$DELEGATE" collect codex-… --wait 300
--wait N faz polling por até N segundos. Sem ele, collect sai com código 3 se a execução
ainda estiver em andamento.
Outros comandos:
node "$DELEGATE" status <run_id> # starting|running|stalled|adrift|lost|done
node "$DELEGATE" collect <run_id> --json # o resultado legível por máquina — analise isso
node "$DELEGATE" list # todas as execuções, da mais antiga para a mais nova
node "$DELEGATE" prune --keep 20 --yes # exclui artefatos antigos de execução
node "$DELEGATE" contract # flags, campos e códigos de saída legíveis por máquina
Lendo o resultado
Status SUCCESSFUL
Because harness_telemetry
Changes
measured greeting.txt
claimed greeting.txt
Permission requested=bypass applied=codex: --dangerously-bypass-approvals-and-sandbox
Três campos carregam a maior parte do significado:
status—successful/failed/abandoned.status_provenance.primary— por que aquele status, em uma palavra:timeout,spawn_error,signal,exit_code,parse_error,telemetry_incomplete,harness_telemetry,self_report,head_moved,index_moved,relay_aborted,supervisor_lost,legacy. Nunca relate um status sem saber qual destes o produziu.evidencelista toda observação que era verdadeira, não apenas a que venceu.dirty_paths_changed— o que o git mediu, ao contrário defiles_claimed, que é o que o delegado disse.files_mismatchsinaliza discordância.
Permissões
Padrão é bypass total. O delegado executa comandos arbitrários sem supervisão.
--sandbox solicita o modo somente leitura real de cada CLI (tabela acima) e ativa o tripwire:
read_only_violation é true / false / null. null significa desconhecido — o git
estava indisponível ou a cobertura de impressão digital estava incompleta. Nunca é colapsado em
false.
false não significa "nenhuma escrita ocorreu." Significa que nenhum delta de estado final
coberto foi detectado. Ele não consegue ver escrita-se-desfaz, nada ignorado pelo git, ou qualquer
escrita fora do repositório.
true não significa que o delegado fez isso — uma edição concorrente na mesma árvore de
trabalho parece idêntica.
O envelope instrui o delegado a não commitar, mas isso é política, não imposição. O que
impõe é a medição: se HEAD se mover durante a janela de execução, o resultado é forçado para
revisão-necessária (head_moved) a menos que você tenha passado --allow-commit.
Continuando uma execução
node "$DELEGATE" start --harness codex --cwd <mesmo diretório> --resume <run_id> \
--task "A correção está certa, mas use a fixture real em vez de um mock."
Envie apenas o delta. resume recebe um novo run_id com parent_run_id definido, e recusa
se o agente, o diretório de trabalho ou o id de sessão do pai não coincidirem.
Uma requisição retomada repete toda regra de política em vez de assumir que a sessão pai ainda as honra.
Flags
| flag | uso |
|---|---|
--cwd DIR | diretório de trabalho — sempre defina-o explicitamente |
--model M | substitui o modelo |
--timeout SEC | padrão 1800; validado antecipadamente; ao expirar, a árvore é morta → abandoned |
--deliverable TEXT | o que entregar ("um diff unificado, não commite") |
--constraint TEXT | regra extra repetível |
--sandbox | solicita o modo somente leitura do agente |
--allow-commit | permite commit, e para de tratar um HEAD movido como revisão-necessária |
--resume <run_id> | continua a sessão de uma execução finalizada com uma tarefa delta |
--clean-env / --keep-env N | entrega à CLI apenas o básico de runtime; repita --keep-env por variável necessária para autenticação |
--raw | envia a tarefa literal (perde status/resumo; incompatível com --resume) |
Pontos de atenção
- Código de saída 0 não significa que a tarefa foi concluída — e até esta refatoração, um
código de saída não-zero não significava que falhou. Os adaptadores recebiam o código de
saída e nenhum o lia, então um evento com formato de sucesso mais saída 1 era publicado como
successful. Corrigido; fixado pelo casoREPAIR-D1emtest/run.mjs. Sempre leiastatus_provenance, nunca apenasexit_code. - Campos de token significam coisas diferentes por agente. Os campos
input_tokens/cache_creation/cache_readdo Claude são disjuntos — some-os (uma sonda reportouinput_tokens: 2para uma requisição que realmente enviou 58.065). Oinput_tokensdo Codex é inclusivo decached_input_tokens— subtraia para a contagem fresca. Useinput_total/input_fresh;usage_rawmantém os números do próprio agente para auditoria mas nunca é exibido como total. - Totais não são comparáveis entre agentes. OpenCode emite um
step_finishpor passo e o driver os soma, então o contexto reenviado a cada passo é contado a cada vez. Mesma tarefa trivial: 66.341 (codex), 117.014 (claude), 426.523 (opencode). Não é uma classificação de eficiência. - Delegar para
claudetem um piso de ~58k tokens.claude -pcarrega CLAUDE.md e toda skill descoberta antes de ler a tarefa. - Codex herda seus servidores MCP. Se o codex estiver lento, leia
runs/<run_id>/stderr.log— a demora geralmente é do MCP, não do modelo. - Codex emite eventos
item.type: "error"em execuções bem-sucedidas. Apenasturn.failedou a ausência deturn.completedconta. - Bypass total realmente não tem sandbox. Um delegado OpenCode uma vez escreveu um arquivo
fora do seu
--cwd. Use--sandbox, ou um diretório descartável. - Nem todo agente reporta todos os campos. Copilot não emite contagens de token
(
fidelity: "unavailable"— zeros significam desconhecido, não grátis). Codex não emite nem custo nem modelo em lugar nenhum do seu JSONL, entãocost_usdemodelsão null por natureza, não por uma falha de parsing —cost_reported/model_reporteddizem quais, e o resultado impresso lê "não reportado por este agente". Claude reporta ambos; OpenCode reporta custo. - O texto da tarefa nunca chega a um shell. Cada CLI é resolvida para um executável real e
iniciada com
shell:false. pipersiste uma sessão em seu próprio armazenamento.--no-sessioné deliberadamente não passado — sem sessão não há o que retomar. As sessões vão para~/.pi/agent/sessions/<cwd-slug>/, chaveadas por diretório de trabalho;prunenão as toca. A autenticação do Pi é baseada em arquivo (~/.pi/agent/auth.json), então--clean-envnão a quebra.- Uma execução cujo supervisor é morto fica
lost, não travada.collectsintetiza um resultado terminal a partir do diário e dos logs. Seu delta git énull: nenhuma linha de base de início de execução sobreviveu, e reportarfalseseria uma garantia de nada medido. - Os ids de execução são validados. Eles devem corresponder a
<harness>-<14 dígitos>-<6 hex>, e devem resolver diretamente sob o diretório de execuções. Um id fornecido pelo chamador não pode navegar para fora dele. - Um supervisor morto cujo agente ainda está vivo fica
adrift, nãolost.collectrecusa publicar, porque um resultado escrito então capturaria uma execução ainda em movimento. Aguarde o processo filho, ou mate o pid questatusnomeia.prunetambém não excluirá uma execuçãoadrift. DELEGATE_BIN_<HARNESS>substitui onde um binário é encontrado — por exemplo,DELEGATE_BIN_CODEX=/opt/codex/bin/codex. Também é como o conjunto de testes dirige um agente falso de ponta a ponta sem gastar um token.
Solução de problemas
| sintoma | causa / correção |
|---|---|
<bin> não encontrado no PATH | essa CLI não está instalada; execute doctor |
encontrado <caminho> mas não foi possível resolver o que ele inicia | a CLI está instalada por trás de um shim .cmd não-npm que este driver não consegue decodificar |
doctor mostra BROKEN: probe timed out | geralmente uma inicialização a frio; execute doctor novamente antes de concluir qualquer coisa |
supervisor falhou ao iniciar (código de saída 5) | o supervisor destacado nunca confirmou; verifique runs/<id>/journal.jsonl. A execução é finalizada como failed com containment_evidence: "the harness never launched"; se o diário contém apenas created e terminal e o pid do supervisor se foi, nenhum agente rodou |
execução <id> ainda em execução (código de saída 3) | adicione --wait <segundos> |
Recusando publicar … ainda em execução (código de saída 6) | a execução está adrift: o supervisor morreu mas o agente ainda vive. Aguarde, ou mate o pid que ele nomeia |
outro processo está finalizando esta execução (código de saída 7) | um escritor ativo detém a reivindicação; tente novamente em um momento |
escrito por um driver diferente (código de saída 8) | o resultado carrega um esquema desconhecido; esta versão não vai adivinhar |
status abandoned, proveniência supervisor_lost | o supervisor foi morto; inspecione a árvore de trabalho antes de redespachar |
status failed, proveniência head_moved / index_moved | algo fez commit ou stage durante a execução; a árvore foi preservada, revise-a |
| Resumo lê "(nenhum resumo produzido)" | o delegado nunca emitiu o bloco de resultado; leia runs/<run_id>/stdout.log |
Arquivos
Os artefatos de execução ficam em $DELEGATE_RUNS_DIR/<run_id>/ (prompt.txt, meta.json,
journal.jsonl, stdout.log, stderr.log, result.json). Se não definido,
DELEGATE_RUNS_DIR assume como padrão runs/ ao lado do driver — que é o diretório
compartilhado do plugin em uma instalação como plugin, portanto defina-o. Limite o tamanho do
log com DELEGATE_MAX_LOG_BYTES (padrão 32 MB por fluxo) e a janela de retenção pós-limite com
DELEGATE_LOG_TAIL_BYTES (padrão 512 KB).
Acima do limite, o driver mantém registros analisados completos em vez de um sufixo de bytes,
portanto a telemetria ainda é analisada. Registros que a janela não consegue reter são contados
em records_dropped — um valor não-zero significa que o status ainda é válido, mas a
resposta final do delegado pode estar incompleta.
⚠️ Os artefatos contêm o texto da sua tarefa, o prompt completo e a saída bruta do agente —
trate-os como confidenciais. A finalização mascara formas de token e pares NOME=valor com
aparência de credenciais em stdout.log e stderr.log (não em result.json). Em POSIX, o
diretório de execuções recebe chmod 0700; no Windows, as permissões são herdadas e este driver
não pode restringi-las. Um collect bem-sucedido exclui execuções finalizadas mais antigas que
DELEGATE_PRUNE_DAYS dias (padrão 30; 0 desativa); limpe antes com prune.
Aprofundando
-
Para um lote de verificações CLI locais conhecidas, leia o contrato nativo do check-runner. Ele cobre planos JSON argv, tentativas imutáveis, coleta limitada e invocação PowerShell. Use a mesma referência para
collect --summary, diagnósticos apenas de heartbeat e prazos de início opcionais. -
contracts/status-precedence.md— como um status é decidido, e o produto cruzado para testar -
contracts/git-fields.md— o que o tripwire mede e o que ele não pode ver -
contracts/result-schema-v2.md— a forma do resultado, leitura retroativa v1, diário, escritor único -
references/writing-the-brief.md— como escrever uma tarefa que o delegado pode executar às cegas -
references/reviewing-the-result.md— como revisar o que retorna, incluindo a varredura -
references/task-queues.md— executar várias tarefas dependentes sem perder o fio
Testes: node test/run.mjs, a partir do diretório desta skill.
Regressões de execução: node --test test/execution.test.mjs (fixtures CLI Node/Python).