🔌 Projeto 2: MCP e hooks entre Claude e Codex
Ferramentas viajam, eventos não. Este projeto registra no Codex os MCP que hoje só o Claude enxerga (magnific, metricool, klingai, cerebro-vip), destrava as 15 skills de adaptador que dependiam deles, e depois encara a parte que não tem equivalente: os hooks. O Codex tem PostToolUse e Stop, mas não tem SessionStart — e é justamente no SessionStart que mora o fable-mindset. O que não vira evento vira texto lido, e os 7 subagentes viram skills de papel.
🎯 O projeto em uma tela
~/.codex/AGENTS.md e 7 skills de papel em .agents/skills/.codex mcp list mostra os servidores; uma skill de adaptador roda no Codex; grep -R 'sk-' ~/.codex não acha nada; e uma sessão nova do Codex consegue assumir um dos 7 papéis citando o arquivo.🧾 Inventário: quem tem qual ferramenta
Antes de mexer em qualquer coisa, o inventário. O diagnóstico de 2026-09-14 mediu os dois runtimes lado a lado e o resultado para MCP é curto e brutal: o Claude tem magnific e metricool globais, mais dois MCP registrados por projeto — wifi → klingai e 2cerebrox → cerebro-vip. O Codex tem nenhum. Não é "tem menos": é zero. Toda skill sua que chama uma dessas ferramentas simplesmente não existe do lado do Codex, por mais bem escrita que ela esteja.
Vale separar dois eixos que as pessoas costumam confundir. MCP é ferramenta: um processo externo que o agente chama para fazer algo no mundo (gerar imagem, agendar post, consultar métrica). Hook é evento: um gancho do harness que dispara sozinho em um momento do ciclo de vida da sessão. O primeiro é um contrato de protocolo e por isso viaja entre runtimes. O segundo é um detalhe de implementação do harness e por isso não viaja — e quando não viaja, a única saída é transformar o efeito do hook em algo que o agente lê.
O painel da esquerda é a boa notícia: MCP é um protocolo, então o mesmo servidor atende Claude e Codex sem duplicar nada. O da direita é a má: hook é implementação do harness, morre na fronteira. O bloco roxo de baixo é a saída deste projeto — o que não pode ser evento tem que virar leitura obrigatória.
📊 O inventário medido
| Escopo | Claude Code | Codex CLI |
|---|---|---|
| MCP global | magnific, metricool | nenhum |
| MCP por projeto | wifi → klingai, 2cerebrox → cerebro-vip | nenhum |
| Hooks | 2 SessionStart (context-mode, fable-mindset) | PostToolUse + Stop (impeccable) |
| Subagentes | 7 em ~/.claude/agents | sem equivalente |
| Skills bloqueadas por isso | — | 15 de adaptador + 2 nativas |
Objetivo: reproduzir o inventário na sua máquina antes de mudar qualquer coisa, para ter linha de base.
# MCP que o Claude enxerga (global + por projeto)
claude mcp list
# esperado nesta máquina: magnific, metricool
# MCP por projeto ficam no .mcp.json de cada repo
ls ~/projetos/wifi/.mcp.json ~/projetos/2cerebrox/.mcp.json 2>/dev/null
# MCP que o Codex enxerga
codex mcp list
# esperado HOJE: lista vazia — este é o gap do projeto
# hooks dos dois lados
grep -o '"SessionStart"\|"PostToolUse"\|"Stop"' ~/.claude/settings.json | sort | uniq -c
grep -o '"SessionStart"\|"PostToolUse"\|"Stop"' ~/.codex/hooks.json | sort | uniq -c
Como verificar: anote as duas listas em context/overview.md do projeto onde você está trabalhando. No fim deste módulo, codex mcp list tem que deixar de ser vazio — e essa é a única métrica que importa no tópico 2.
Regra de ouro do inventário: não confie na memória. Um MCP "que você jurava ter registrado" e não aparece no list é um MCP que não existe para o agente. O mesmo vale para hook: se não está no arquivo de settings, não dispara — e você vai passar uma hora depurando comportamento que nunca foi ligado.
Conceitos-chave
Ferramenta externa falada por protocolo; qualquer runtime que fale o protocolo a usa.
Gancho de evento do harness; não é protocolo, é implementação local.
Um MCP pode valer em toda a máquina ou só dentro de um repo.
O estado medido antes da mudança; sem ele não existe "melhorou".
🔑 codex mcp add sem copiar um único segredo
O comando é simples: codex mcp add <nome> -- <comando>. O que exige cuidado é o que vai junto. A regra global desta máquina é explícita: as API keys sempre moram em ~/projetos/openpcbotv2/.env ou ~/projetos/wifi/.env, são carregadas em runtime e nunca duplicadas em outro lugar. Registrar um MCP colando a key no argumento do comando viola isso duas vezes: cria uma segunda cópia do segredo e a grava num arquivo de configuração que você vai acabar sincronizando, versionando ou colando num chat.
A saída é indireta: o comando registrado não é o servidor, é um wrapper de três linhas que carrega o .env e só então exec-uta o servidor. O padrão do carregamento é set -a; source .env; set +a — o set -a faz toda variável atribuída virar variável de ambiente exportada, o source lê o arquivo, o set +a desliga. O segredo passa pela memória do processo e nunca encosta na configuração do Codex.
Descobrir o comando real
No Claude, cada MCP já tem um comando de inicialização. Copie o comando, não a key.
Escrever o wrapper
Um .sh por servidor em ~/.local/bin/, com set -a; source ...; set +a e exec no fim.
Registrar apontando para o wrapper
codex mcp add magnific -- ~/.local/bin/mcp-magnific.sh. A configuração guarda um caminho, não um segredo.
Provar que não vazou
Um grep na árvore ~/.codex procurando prefixos de key. Zero resultado é o aceite.
Objetivo: registrar magnific e metricool no Codex referenciando as keys do .env, sem gravar valor nenhum.
# 1. wrapper que carrega o .env em runtime e passa o bastão pro servidor
mkdir -p ~/.local/bin
cat > ~/.local/bin/mcp-magnific.sh <<'SH'
#!/usr/bin/env bash
set -euo pipefail
set -a; . "$HOME/projetos/openpcbotv2/.env"; set +a # carrega, não copia
exec npx -y @magnific/mcp-server # troque pelo comando real do seu MCP
SH
chmod 700 ~/.local/bin/mcp-magnific.sh
# 2. registrar no Codex: a config guarda um CAMINHO, nunca uma key
codex mcp add magnific -- "$HOME/.local/bin/mcp-magnific.sh"
codex mcp add metricool -- "$HOME/.local/bin/mcp-metricool.sh"
# 3. conferir
codex mcp list
Como verificar: codex mcp list deixa de vir vazio e mostra os dois nomes. Depois abra codex numa pasta qualquer e peça "liste as ferramentas de MCP disponíveis" — os nomes têm que aparecer na resposta, não só no arquivo.
Objetivo: provar que nenhum segredo foi parar na configuração — este é o teste que fecha o tópico.
# procura prefixos típicos de key dentro da config do Codex
grep -rIl -e 'sk-' -e 'API_KEY=' -e 'TOKEN=' ~/.codex 2>/dev/null
# esperado: NENHUMA linha de saída
# confere que o wrapper não é legível por outros usuários
stat -c '%a %n' ~/.local/bin/mcp-*.sh
# esperado: 700 em todos
# confere que o .env continua sendo a fonte única
grep -c '=' ~/projetos/openpcbotv2/.env # só a contagem; nunca imprima o conteúdo
Como verificar: o primeiro comando tem que sair mudo. Se ele imprimir qualquer caminho, pare tudo: alguma key foi copiada. Remova o registro com codex mcp remove <nome>, rotacione a key, e refaça pelo wrapper.
✓ Jeito certo de levar a key
- ✓O wrapper faz
sourcedo.envem runtime, a cada inicialização. - ✓A configuração do Codex guarda só o caminho do wrapper.
- ✓Rotacionar a key é editar um arquivo só; nada mais precisa mudar.
- ✓
chmod 700no wrapper e.envfora de qualquer repo publicado.
✗ Jeito que cria dívida
- ✗Colar a key no
codex mcp add ... --env KEY=sk-...: vira texto em disco. - ✗Duplicar o
.envpara dentro de~/.codex"só para facilitar". - ✗Exportar a key no
.bashrc: passa a vazar para todo processo da máquina. - ✗Imprimir o valor para "conferir se está certo" — o terminal fica no histórico e no log da sessão.
Os dois MCP por projeto: klingai (no wifi) e cerebro-vip (no 2cerebrox) seguem exatamente o mesmo padrão, mas registrados de dentro do repo, para continuarem com escopo local. A pergunta que decide o escopo é simples: "outro projeto qualquer vai querer chamar isso?" Se a resposta for não, mantenha por projeto — MCP global é superfície de ataque e ruído de contexto em toda sessão.
Conceitos-chave
Script curto que carrega ambiente e faz exec no servidor real.
set -aFaz o source exportar tudo; set +a desliga logo em seguida.
Apontar para a fonte do segredo; nunca criar uma segunda fonte.
O aceite é um grep que não acha nada — ausência verificada.
🔓 As 15 skills de adaptador destravam depois
A auditoria de skills classificou 89 skills que só existem no Claude em quatro classes. 72 são reutilizáveis — Markdown e scripts comuns, portam sem alteração. 15 são de adaptador: dependem de um MCP ou de um plugin do Claude e por isso só fazem sentido no Codex depois que a ferramenta correspondente estiver registrada. Duas são nativas (dependem de hook SessionStart) e uma está sem SKILL.md.
É por isso que este projeto vem antes da migração em lote de skills. Portar uma skill de adaptador com o MCP ausente produz o pior resultado possível: ela é descoberta, é escolhida, e falha no meio da execução — o agente já prometeu ao usuário que ia gerar o vídeo. Ferramenta primeiro, skill depois. A ordem não é preferência, é o que separa "não instalado" de "instalado e quebrado".
🧩 As 15 de adaptador, por dependência
Oito delas são variantes do printing-press, que contam como uma dependência só. Resolver três MCP (heygen, comfy e o do espiona-ads) libera o bloco inteiro.
✓ Pronta para portar agora
- ✓Só lê e escreve arquivos, ou chama binários que já existem na máquina.
- ✓O
SKILL.mdnão cita nenhummcp__…no corpo das instruções. - ✓Os scripts auxiliares são bash ou node sem dependência de plugin.
- ✓Dá para rodar o caminho feliz inteiro sem rede.
✗ Espera o MCP correspondente
- ✗O
SKILL.mdmanda "chamemcp__magnific__images_generate". - ✗Depende de um plugin do Claude (superpowers, context-mode, claude-mem).
- ✗Depende de subagente: "despache para o
analista-neutro". - ✗Assume
AskUserQuestionou outro recurso de UI só do Claude.
Objetivo: classificar automaticamente as suas skills entre "reutilizável" e "adaptador", para saber o que portar hoje.
# adaptador = o SKILL.md menciona MCP, plugin ou subagente
cd ~/.claude/skills
for d in */; do
s="${d%/}"
if grep -qE 'mcp__|AskUserQuestion|subagent_type|superpowers:|context-mode:' "$s/SKILL.md" 2>/dev/null; then
echo "ADAPTADOR $s"
else
echo "portavel $s"
fi
done | sort | tee ~/classificacao-skills.txt | awk '{print $1}' | uniq -c
# ver só as travadas, e por qual dependência
grep '^ADAPTADOR' ~/classificacao-skills.txt | awk '{print $2}' | while read s; do
echo "== $s"; grep -ohE 'mcp__[a-z0-9_]+' "$s/SKILL.md" | sort -u
done
Como verificar: a contagem deve bater com a ordem de grandeza do diagnóstico — dezenas de portáveis contra cerca de 15 adaptadores. Se der 80 adaptadores, seu grep está pegando menção em exemplo; ajuste para olhar só as linhas de instrução.
Dica de sequenciamento: depois de registrar magnific e metricool no tópico 2, volte a esta lista e mova para "portável" só as skills cuja única dependência era um desses dois. As de heygen e comfy continuam travadas até você registrar os MCP correspondentes — e isso é uma tarefa de outra sessão, não uma exceção a abrir agora.
Conceitos-chave
Skill cujo valor depende de uma ferramenta externa registrada.
Pior que não ter: a skill é escolhida e quebra depois da promessa.
A ordem que evita instalar algo quebrado no Codex.
8 variantes do printing-press destravam com um MCP só.
🪝 Hooks: o mapeamento real entre os dois
Aqui a notícia é mista. O Claude tem dois hooks de SessionStart — context-mode e fable-mindset — e é deles que vem boa parte do comportamento que você considera "o jeito do Claude trabalhar". O Codex tem hooks também, mas de outros momentos: o ~/.codex/hooks.json desta máquina registra um PostToolUse (matcher Edit|Write|apply_patch, timeout 5s) e um Stop (timeout 30s), os dois chamando o mesmo hook.mjs do impeccable. O que não existe é o gancho de abertura: SessionStart não tem equivalente no Codex.
A linha é o ciclo de vida de uma sessão. Os dois pontos ciano (PostToolUse e Stop) já existem nos dois runtimes e não dão trabalho. O ponto roxo (SessionStart) só existe no Claude — e a seta tracejada para baixo é a única resposta possível: trocar o evento automático por leitura obrigatória no começo da sessão.
🗺️ A tabela de mapeamento
| Evento | Claude | Codex | O que fazer |
|---|---|---|---|
SessionStart | ✓ 2 hooks | ✗ não existe | Virar texto no AGENTS.md + skill de prime |
PostToolUse | ✓ | ✓ impeccable | Nada; conferir o matcher |
Stop | ✓ | ✓ impeccable | Nada; conferir o timeout de 30s |
| Plugins | ✓ 7 | ✗ 1 (github) | Resíduo Claude; não migra |
Objetivo: ler o que está de fato registrado nos dois lados, em vez de supor.
# quais eventos o Codex tem registrados nesta máquina
python3 -c "import json;print(list(json.load(open('$HOME/.codex/hooks.json'))['hooks']))"
# esperado: ['PostToolUse', 'Stop']
# o matcher e o timeout de cada um
grep -E '"matcher"|"timeout"|"statusMessage"' ~/.codex/hooks.json
# o alvo dos dois hooks existe? (o hook é escrito para falhar em silêncio se não existir)
ls -l ~/.agents/skills/impeccable/scripts/hook.mjs
# o que o Claude dispara no SessionStart — este é o que NÃO tem par
grep -A4 '"SessionStart"' ~/.claude/settings.json
Como verificar: a lista do Codex sai com dois nomes e nenhum deles é SessionStart. Se o ls do hook.mjs falhar, os hooks do Codex estão registrados mas inertes — o [ ! -f ... ] || no começo do comando faz eles saírem calados.
Por que o hook falha em silêncio de propósito: repare no formato [ ! -f "…/hook.mjs" ] || node "…/hook.mjs". Se o arquivo sumir, o comando devolve sucesso e a sessão segue. Isso é desejável para um hook cosmético como o do impeccable, e péssimo para um hook que carrega contexto: você acharia que leu o AGENTS.md e não leu. É mais um argumento para não depender de evento em coisa que precisa ser garantida.
Conceitos-chave
Gancho de abertura; existe só no Claude, e é o que mais dói perder.
Filtro de quais ferramentas disparam o PostToolUse.
Hook escrito para não quebrar a sessão quando o alvo some.
A única tradução possível quando o gancho não existe do outro lado.
📝 fable-mindset vira seção de texto no AGENTS.md
O fable-mindset é uma das duas skills classificadas como nativas: ele existe como hook de SessionStart, que injeta um playbook de comportamento no começo de toda sessão do Claude. Como o Codex não tem SessionStart, não há para onde portar o mecanismo. Mas o conteúdo do playbook é só texto — e texto é a coisa mais portátil que existe. A conversão é direta: o que era injetado por evento passa a ser uma seção do ~/.codex/AGENTS.md, lida porque o arquivo é lido.
O playbook destilado dessa análise cabe em poucas linhas, e o núcleo dele é o que dá para chamar de regra de ritmo: pense antes de agir, feche o loop verificando. Duas metades que se seguram. A primeira evita a sessão que sai editando arquivos antes de entender o problema; a segunda evita a sessão que declara "pronto" sem rodar nada. Escrito assim, sem jargão de harness, funciona em qualquer runtime — inclusive no dsh do próximo projeto, que não tem hook nenhum.
Objetivo: acrescentar a regra de ritmo ao ~/.codex/AGENTS.md, substituindo o hook por leitura.
# backup antes de tocar na base global (Projeto 1 criou este arquivo)
cp ~/.codex/AGENTS.md ~/.codex/AGENTS.md.bak-$(date +%Y%m%d)
cat >> ~/.codex/AGENTS.md <<'MD'
## Regra de ritmo (era o hook fable-mindset no Claude)
- **Pense antes de agir.** Antes da primeira edição, diga em uma frase
qual é o problema e qual é a menor mudança que o resolve. Se não
souber, leia mais; não comece a editar para descobrir.
- **Feche o loop verificando.** Toda mudança termina com um comando que
prova o resultado (teste, `grep`, `status`, readback) e com a saída
colada na resposta. "Deve funcionar" não fecha o loop.
- **Uma correção por vez.** Se a resposta foi reescrever tudo,
provavelmente faltava uma proteção — registre isso no FALHAS.md.
MD
# conferir que entrou e que o arquivo continua curto
tail -14 ~/.codex/AGENTS.md
wc -l ~/.codex/AGENTS.md
Como verificar: rode codex exec "Antes de editar qualquer arquivo, o que você deve dizer primeiro? Cite a fonte." a partir de ~. A resposta tem que mencionar a frase sobre o problema e a menor mudança, citando o AGENTS.md. Se ele responder bem sem citar a fonte, é coincidência do modelo, não leitura — e não conta como aceite.
✓ Vira texto bem
- ✓Playbook de comportamento: ritmo, ordem de trabalho, o que fazer antes de declarar pronto.
- ✓Proibições duras e preferências de estilo.
- ✓Ordem de leitura de arquivos no começo da sessão.
- ✓Critérios de aceite e formato de handoff.
✗ Não vira texto
- ✗O que o hook calcula: minerar 2,3 GB de JSONL para gerar o playbook.
- ✗Bloqueio real de ação — texto pede, hook impede.
- ✗Injeção garantida: texto pode ser podado do contexto numa sessão longa.
- ✗Roteamento automático de chamadas para um subagente.
O custo honesto da conversão: hook é garantia, texto é pedido. Ao trocar um pelo outro você perde determinismo — e é exatamente por isso que a regra de ritmo tem que ser curta. Três bullets que o modelo lê todo começo de sessão valem mais do que quarenta linhas que ele vai atravessar sem ler. A mesma lógica se aplica ao silver-platter, a outra skill nativa.
Conceitos-chave
Depende de um recurso do harness; só o conteúdo migra.
Pense antes de agir; feche o loop verificando.
Hook executa sempre; texto depende de ser lido e obedecido.
Instrução longa não é mais forte, é mais ignorada.
🎭 Os 7 subagentes viram skills de papel
O Claude tem 7 subagentes em ~/.claude/agents: advogado-do-diabo, analista-neutro, estrategista-otimista, mestre-do-conselho, diretor-ecossistema, web-research-assistant e triple-x-responder. O Codex não tem equivalente — o diagnóstico é categórico, subagentes ficam como resíduo Claude. Mas cada um desses arquivos é, no fundo, um papel descrito em prosa: o que o agente assume, o que ele procura, o formato da saída. Isso vira skill.
O destino é .agents/skills/ — a mesma pasta que o Codex já varre e que o sync-skills.sh espelha na instalação. O que se perde é o paralelismo: no Claude, três membros do conselho rodam ao mesmo tempo em contextos separados. Com skill de papel, o mesmo agente assume os papéis em sequência, no mesmo contexto — mais barato, mais lento e com contaminação entre as vozes. É uma perda real, e vale dizer isso na descrição da skill em vez de fingir equivalência.
Objetivo: converter os 7 subagentes em skills de papel, preservando o corpo do prompt e trocando só o cabeçalho.
mkdir -p ~/.agents/skills
for a in advogado-do-diabo analista-neutro estrategista-otimista \
mestre-do-conselho diretor-ecossistema web-research-assistant \
triple-x-responder; do
src=~/.claude/agents/$a.md
[ -f "$src" ] || { echo "faltou: $a"; continue; }
mkdir -p ~/.agents/skills/papel-$a
{
echo "---"
echo "name: papel-$a"
echo "description: Assume o papel do $a. Use quando a tarefa pedir essa voz explicitamente."
echo "---"
echo
echo "> Papel derivado do subagente \`$a\` do Claude Code."
echo "> Aqui NÃO há execução paralela: assuma o papel no contexto atual e"
echo "> deixe claro na resposta quando estiver falando por ele."
echo
sed '1{/^---$/!q}; 1,/^---$/d' "$src" # tira só o front-matter antigo
} > ~/.agents/skills/papel-$a/SKILL.md
echo "papel-$a"
done
Como verificar: ls ~/.agents/skills | grep -c '^papel-' devolve 7. Depois, codex exec "Use o papel-advogado-do-diabo para atacar esta decisão: migrar tudo de uma vez." — a resposta tem que citar o arquivo da skill e sustentar a voz do contraditório do começo ao fim.
✅ Critérios de aceite (marque com evidência)
- ☐
codex mcp listmostra magnific e metricool. Evidência: saída do comando. - ☐
grep -rIl -e 'sk-' -e 'API_KEY=' ~/.codexnão devolve nada. Evidência: saída vazia colada no handoff. - ☐Uma skill de adaptador que dependia só de magnific roda no Codex de ponta a ponta. Evidência: o artefato gerado.
- ☐A regra de ritmo está no
~/.codex/AGENTS.mde é citada numcodex exec. Evidência: a resposta com a citação. - ☐7 skills
papel-*em~/.agents/skills, e uma delas foi exercitada. Evidência:ls+ a resposta do papel. - ☐Nada quebrou no Claude:
claude mcp liste os hooks de SessionStart continuam iguais. Evidência: comparação com a linha de base do tópico 1.
⚠️ Riscos deste projeto
- •Key copiada para dentro de
~/.codexpor pressa — o risco mais caro da página. - •MCP registrado global quando devia ser por projeto: ruído de contexto em toda sessão.
- •Skill de adaptador portada antes do MCP: falha no meio da execução.
- •Achar que skill de papel é igual a subagente: perde o paralelismo e o isolamento de contexto.
- •Servidor MCP baixado por
npxsem versão fixa mudando debaixo de você.
↩️ Rollback em um comando
- ✓MCP:
codex mcp remove magnific(e metricool) devolve a lista vazia. - ✓Wrappers:
rm ~/.local/bin/mcp-*.sh; o.envnunca foi tocado. - ✓AGENTS.md:
mv ~/.codex/AGENTS.md.bak-AAAAMMDD ~/.codex/AGENTS.md. - ✓Papéis:
rm -rf ~/.agents/skills/papel-*; os originais em~/.claude/agentsficam intactos. - ✓Se uma key vazou, rollback não basta: rotacione a key antes de qualquer outra coisa.
Conceitos-chave
O prompt do subagente virando instrução que o agente assume.
Papéis em sequência no mesmo contexto, não em contextos separados.
.agents/skills/Pasta que o Codex varre e o sync-skills espelha.
Documentar o que se perde vale mais que fingir paridade.
Auto-checagem (opcional): você quer que o Codex registre o MCP magnific, que precisa de uma API key guardada em ~/projetos/openpcbotv2/.env. Qual é o caminho certo?
🎯 Resumo do projeto
set -a; source .env; set +a; a configuração guarda caminho, nunca key.Próximo projeto:
3.3 — Memória curada: o agente propõe, você aprova