Campanhas internas no CRM Kodama (brief → plano de IA → checklist → geração autônoma)
Campanhas internas do agencia-kodama-admin
Criado: 2026-07-06. Fase 2 (geração autônoma) construída: 2026-07-06. Bloom (imagem) integrado: 2026-07-07.
O que é
/campanhas do CRM (crm.kodama.solutions) ganhou um segundo fluxo, decoupled do Meta Ads: criar campanha a partir de um brief em texto + site escolhido, deixar uma IA decidir o checklist de próximos passos (LP, criativo, se precisa mesmo de campanha no Meta), e ter cada item gerado — hoje, pra tipos de conteúdo seguros, de verdade sozinho, sem humano por trás, texto E imagem. Campanha pode nunca tocar o Meta Ads — pode ser conteúdo orgânico, e-mail, outro canal.
Fluxo: /campanhas/nova (brief + Select de site) → campaign-planner.ts chama a Anthropic direto (raw fetch, mesmo padrão de enrich.ts) → salva campaigns + campaign_checklist_items no SQLite → /campanhas/interno/[id] mostra estratégia decidida + checklist com progresso ao vivo por item → clicar "Gerar" marca aguardando_geracao → o poller autônomo do Swarm pega o item em até 2 minutos e processa sozinho (pra tipos seguros).
Por que ficou em 2 fases (decisão do Marcus)
Descoberta central: os subagents Claude Code (landing-page-architect, meta-campaign-builder) só existem dentro de uma sessão interativa — o app Next.js do CRM não consegue invocá-los sozinho. Perguntei como resolver; resposta: "cria uma api que faça isso, tipo um mcp". Investigando o Swarm (/home/swarm/openclaw/scripts/swarm-mcp.mjs), confirmei que ele já roda em dual transport (stdio + SWARM_MCP_MODE=http) — o padrão já existe, mas as tools do Swarm são amarradas ao domínio próprio dele (tabela products), não servem pra "campanha do Prospek/Connfit/etc" sem reescrita.
Fase 1: schema + UI + planejamento síncrono (Anthropic raw fetch, sem tool-use) + endpoints de callback. Ficou aí só até o usuário perguntar por que a fila não processava sozinha — pediu explicitamente pra terminar a Fase 2 na mesma sessão ("fodase os tokens cara... so termina essa merda de fase 2 logo").
Fase 2 (construída): em vez de um serviço novo do zero, reaproveitei o openclaw — o runtime de agentes que já roda o Swarm inteiro (/root/.openclaw/agents/<id>/agent/AGENTS.md, mesmo formato de subagent spec, com sessions/trajectory logs reais). Criei um novo agent persona agent-campanha-crm registrado em /root/.openclaw/openclaw.json (+ mirror sanitizado em config/openclaw.template.json no repo do Swarm), dispatched por um poller cron novo (openclaw/scripts/campanhas/campanha-poller.mjs, */2 * * * *) que:
GET /api/campaigns/queue(bearer secret) — pega itensaguardando_geracaocom contexto completo (brief, estratégia decidida, site)- Pra cada item,
spawn('openclaw', ['agent','--agent','agent-campanha-crm','--session-id','citem-<id>','-m', <contexto>])fire-and-forget (mesmo padrão dodispatch_agentdo Swarm) - O agente processa, chama
POST .../progress(log em tempo real, visível no CRM) ePOST .../complete(sucesso) ou{erro}(falha)
Escopo de segurança do agent-campanha-crm: só processa tipo=post|creative|outro (conteúdo puro, texto/imagem) sozinho. Pra tipo=landing_page (mexe em código de produção de outro repo) ou tipo=meta_campaign (gasto real de anúncio), ele recusa e marca erro pedindo execução supervisionada via landing-page-architect/meta-campaign-builder numa sessão Claude Code manual — decisão deliberada, não é limitação técnica. Rodar código em produção ou gastar dinheiro de anúncio sem nenhuma revisão humana é um risco categoricamente diferente de gerar um rascunho de texto ou imagem.
Gotcha descoberto no smoke test: o exec/shell sandbox do agente openclaw NÃO herda CAMPAIGNS_CALLBACK_SECRET do ambiente do processo pai (mesmo passando explicitamente no spawn) — só variáveis vindas de dentro do próprio sandbox. Fix: o AGENTS.md do agente instrui explicitamente source /home/swarm/.secrets.env antes de cada curl. Na primeira tentativa (antes desse fix) o agente descobriu isso sozinho por tentativa e erro; depois do fix ficou explícito, sem gastar turnos de diagnóstico.
Bloom — geração de imagem pro tipo=creative (2026-07-07)
Marcus avisou que o Swarm ganhou integração própria com a API real do Bloom (BLOOM_API_KEY, https://www.trybloom.ai/api/v1, tools bloom_generate_image/bloom_get_image/bloom_list_brands/bloom_list_images em swarm-mcp.mjs) — diferente do conector MCP interativo (mcp__claude_ai_Bloom__*) que só existe dentro desta sessão Claude Code e que os subagents manuais (landing-page-architect, prospek-marketing-creative) usam. Só o subset do Swarm tem bloom_generate_image/bloom_get_image puro por prompt — não tem bloom_find_reference_ads/recreate_ad_id (técnica que funciona melhor no Bloom, ver projects/prospek/offer-strategy) — então o agent-campanha-crm gera só por prompt livre, sem referência de anúncio real.
Mapeamento site → brand Bloom, checado via GET /api/v1/brands da conta Swarm em 2026-07-07, hardcoded em campanha-poller.mjs (deliberado — mantém conhecimento de Bloom fora do agencia-kodama-admin):
prospek→a45da90d-ffb9-4e41-85e2-5f9b45d41b9fkodama-solutions→c180b26a-56f5-4693-935a-82ea77a30cf8watcha→5ab8e206-deed-4200-83ea-49cf70b9cd7fconnfit,kodama-agencia→ sem brand onboarded ainda;agent-campanha-crmcai pra copy sem imagem nesse caso.
Poller passa bloom_brand_id (vazio se não mapeado) no contexto despachado pro agente; AGENTS.md só tenta gerar imagem se tipo=creative E bloom_brand_id não vazio.
Bug crítico #1 — agente gerava, testava, nunca chamava /complete
Primeiro smoke test real (test-item-bloom): agente gerou 2 variantes de imagem reais via Bloom (URLs válidas, ex. https://www.trybloom.ai/img/34709e56-...), escreveu resumo bonito em texto — e nunca chamou /progress nem /complete. Tratou a tarefa inteira como "teste/demo pra ver se a tool funciona". Item ficou travado em aguardando_geracao, zero log, stopReason:"stop" no trajectory (o LLM achou que já tinha terminado). Completei manualmente o item de teste (usando a imagem real gerada) como workaround, e limpei os dados de teste depois.
Fix: reescrita da abertura do AGENTS.md — framing explícito "Isto NÃO é um exercício de teste ou demonstração de capacidade", "Regra de ouro: sua ÚLTIMA ação sempre tem que ser um curl pro /complete", checklist obrigatório de 4 passos ordenados, proibição explícita de "confirmar que a tool funciona antes de finalizar". Reverificado num segundo smoke test (test-item-bloom2) — dessa vez o agente chamou /progress e /complete sozinho, sem intervenção manual. Fix confirmado funcionando end-to-end.
Bug menor #2 — variante duplicada + URL em texto solto, não no campo certo
Mesmo segundo teste, callback aconteceu certo mas com 2 defeitos de qualidade: gerou 2 variantes apesar de variant_count:1 no spec, e escreveu a URL da imagem como prosa dentro de resultadoRef ("Variante 1: https://... Variante 2: https://...") em vez de popular o campo resultadoUrl do JSON (que ficou vazio) — quebra o botão "Ver" no CRM.
Fix: instrução literal no §IMAGEM — resposta do bloom_get_image traz imageUrl, "guarde esse valor exato, é literalmente o resultadoUrl que você vai mandar, campo por campo, sem reformatar". Exemplo de curl do /complete mostrando resultadoRef E resultadoUrl como campos JSON separados. Instrução explícita de nunca listar "Variante 1/Variante 2" em texto — uma imagem, uma URL. Deployado mas não re-testado ao vivo (decisão de custo/tempo — 2 ciclos de teste real já gastos, fix é pequeno e mecânico, ficou documentado como gap conhecido em vez de rodar 3º teste).
Registry de sites — src/lib/marketing-sites.ts
Curado (não é dump dos ~26 projetos da vault) — só sites reais de marketing: Prospek (tem agent dedicado prospek-marketing-creative), ConnFit, Kodama Solutions, Watcha, Kodama Agência (TikTok Shop). Excluídos por serem ferramentas internas: connfit-marketing, kodama-hub, facade-scout.
Agentes envolvidos
landing-page-architect(Claude Code subagent, genérico, qualquer projeto) — LP completa, manual. Já documentado em projects/prospek/offer-strategy.meta-campaign-builder(Claude Code subagent, genérico) — provisiona campanha→adset→creative→ad no Meta, manual, semprePAUSED.agent-campanha-crm(openclaw agent, autônomo, roda no Swarm/VPS) — processapost/creative/outrosozinho via cron poller, incluindo imagem via Bloom pracreative. Spec em/root/.openclaw/agents/agent-campanha-crm/agent/AGENTS.md, mirror em/home/swarm/config/agents/agent-campanha-crm/AGENTS.md(repo git do Swarm).
Os 2 primeiros: specs em ~/.claude/agents/, mirror em brain/agents/, registrados na tabela do ~/.claude/CLAUDE.md global. O terceiro NÃO é um Claude Code subagent — não entra nessa tabela, vive inteiramente no ecossistema Swarm/openclaw.
Bugs encontrados e corrigidos durante o desenvolvimento
docker-compose.ymlallowlist de env — mesmo padrão recorrente já visto neste repo (c8a086b,e123c1e) —CAMPAIGN_PLANNER_MODEL/CAMPAIGNS_CALLBACK_SECRETprecisaram ser adicionadas explicitamente.src/middleware.ts— o endpoint de callback caía atrás do gate de sessão, depois um bypass largo demais (/api/campaignsinteiro público) foi corrigido pra uma lista explícita de{método, path}— GET só é público em/api/campaigns/queue, POST só em.../completee.../progress.feature-auditorachoucriadoPorUserIdnunca preenchido emcreateCampaign— corrigido.ChecklistItemRow(client component) não resincronizavauseStatequando a prop mudava por revalidação do Server Action — clicar "Gerar" não atualizava a tela sem F5. Fix: key do componente inclui o status (${id}-${status}), força remount quando muda.- Item concluído sem
resultadoUrl(ex: copy de post, sem link externo) não tinha jeito de ver o conteúdo na UI — só "Ver" (link) existia. Adicionado "Ver conteúdo"/"Ver erro" via Dialog quando só temresultadoRef. agent-campanha-crmgerava conteúdo/imagem real mas nunca chamava/complete(tratava como demo) — ver seção Bloom acima, bug #1.agent-campanha-crmgerava variante duplicada e mandava URL de imagem como texto solto em vez do camporesultadoUrl— ver seção Bloom acima, bug #2.
Incidente de segurança (durante o desenvolvimento, não do produto)
Ao investigar /root/.openclaw/openclaw.json (registry de agentes do Swarm), um cat sem filtro imprimiu vários secrets em texto puro na transcrição da sessão (META_ACCESS_TOKEN, CAKTO_CLIENT_SECRET, GUMROAD_API_KEY, TELEGRAM_BOT_TOKEN, DISCORD_BOT_TOKEN, GOOGLE_AI_STUDIO_KEY, SIGNED_URL_SECRET). Também um crontab -l expôs o CRON_SECRET do agencia-kodama-admin. Marcus foi avisado, optou por não rotacionar nesse momento ("fodase os tokens"). Lição: nunca cat/dump completo de arquivo de config que guarda secret — usar sempre grep/node -e pontual, mesmo sob pressão de "só termina logo".
Commits agencia-kodama-admin: ab3d74b, c838392, d4419bd, d3914ee, 880170e, 7791c13.
Commits swarm: 4590d81, aeb74c8.