Elquer Carlos

D35 + D36 + D37: filesystem MCP, SSH externo e 14 GB de memória numa janela de 72h

Três decisões grandes em 72h: filesystem MCP com escrita real, SSH externo via Cloudflare Tunnel e um memory leak de 14 GB descoberto por acaso.

Janela de quase 72 horas — viagem no meio. Saí de casa e continuei trabalhando de fora. Três decisões grandes saíram nessa janela: D35 (filesystem MCP com escrita real do claude.ai), D36 (SSH externo via Cloudflare Tunnel + Zero Trust) e D37 (memory leak de 14 GB no clawmem-bridge, mais 5h em busca da causa errada). Em paralelo, 36 commits no kmaroteApp e uma decisão de produto: pivot para Kiwify + Telegram, painel lariia-panel adiado.

D35 — Filesystem MCP via segundo supergateway (08/05 → 09/05)

O triângulo de acesso à Larissa tinha uma lacuna: o claude.ai web conseguia ler o vault via MCP, mas não escrever. Qualquer atualização de runbook ou registro de decisão dependia de abrir o Claude Code Larissa para fazer o trabalho. Era atrito real.

Arquitetura escolhida (briefing v2, caminho B):

  • 1 Worker estendido com path-based routing: /mcp continua no ClawMem :8000, /mcp-fs vai pro filesystem MCP :8001
  • 1 hostname tunnel (mcp.lariia.com.br) com 2 ingress rules path-based no config.yml do cloudflared
  • 2ª service larissa-fs-bridge.service rodando supergateway + @modelcontextprotocol/server-filesystem em stdio→streamableHttp
  • Zonas write restritas a ~/larissa/docs/ e ~/larissa/runbooks/ — defesa em profundidade em duas camadas: app layer + systemd ProtectHome

Execução via Claude Code Larissa: BLOCOs 0→4 fechados sem regressão no /mcp. Audit log iniciado em ~/larissa/logs/fs_mcp_audit.log. PLANO_MESTRE.md subido para ~/larissa/docs/ via SCP, depois atualizado de v3 → v3.1 via filesystem MCP diretamente do claude.ai — primeiro write E2E real da web no disco da Larissa.

Bugs resolvidos:

  • Wrangler duplicou bloco kv_namespaces no wrangler.jsonc ao auto-injetar — bug já tinha aparecido antes na S-EXT. Fix: abrir Notepad, apagar duplicação manual.
  • Cloudflare Tunnels não fazem rewrite de path — premissa errada no briefing v1. Reescrevi como caminho A: path alinhado diretamente no supergateway com --streamableHttpPath /mcp-fs.
  • WAF Bot Management bloqueava /mcp-fs com 403 “Your request was blocked.” Causa: regra default Manage AI bots bloqueando User-Agent: Claude-User. Por que /mcp passava e /mcp-fs não? Threshold de bot score provavelmente subiu pelo path desconhecido. Fix: regra “Skip AI bot mgmt for MCP subdomain” com expressão (http.host eq "mcp.lariia.com.br") ignorando as managed rules.
  • PowerShell 5.1 não preserva aspas duplas dentro de header HTTP passado para curl.exe. Solução: instalar PowerShell 7.6.1. Funcionou no primeiro tiro com Invoke-WebRequest nativo.

Validação E2E (09/05 ~06h BRT): write em zona permitida funcionou. Write em zona proibida (config/) retornou erro — defesa em profundidade dupla confirmada. Promovido para 100% de tráfego.

D36 — SSH externo via Cloudflare Tunnel + Zero Trust (09/05 noite → 10/05 madrugada)

Disparador: “Para continuar preciso ter acesso SSH de fora de casa. Estou indo viajar agora e não quero parar o trabalho.”

Estimei 30-45 minutos com Zero Trust. Levou bem mais por uma derrapagem específica.

Arquitetura:

  • Mesmo tunnel que já roda mcp.lariia.com.br
  • Novo hostname ssh.lariia.com.br no ingress, apontando para ssh://localhost:22 na Larissa
  • Application Cloudflare Access nova (separada da MCP) com policy Elquer access: Google OAuth + email único autorizado
  • Cliente Windows: cloudflared via winget, par de chave id_ed25519_larissa já existia, ssh_config com ProxyCommand cloudflared access ssh --hostname %h
  • WAF skip para ssh.lariia.com.br (mesmo padrão da regra MCP)

O bug caro: 4h perseguindo a causa errada.

Primeiro sintoma: websocket: bad handshake no cliente. O claude.ai chutou WAF (regra Bot Management). Cortei depois de ver zero eventos WAF: “Verifique tudo que fizemos, o que tu já sabe e pesquise se fizemos o caminho corretamente e se tem algo conhecido sobre este erro antes de decidir o que fazer. Pois normalmente quando tem muita opção você deixou passar algo e regredimos horas.”

O claude.ai pesquisou e chutou de novo: Binding Cookie habilitado. Falso — já estava desativado. Tirei screenshot. Recuou.

Causa real, achada nos logs do cloudflared:

ERR error="dial tcp 127.0.0.1:2222: connect: connection refused"
    ingressRule=2 originService=ssh://localhost:2222

O sshd da Larissa não estava em :2222 como o config.yml (e a “memória” do projeto) dizia. Estava em :22. A premissa nunca tinha sido validada. O claude.ai admitiu: “A regra é clara: não presumir o não-documentado. A memória do sistema dizia :2222 — eu deveria ter validado com ss -tlnp | grep ssh no minuto 1. Construí toda a infra sobre premissa não-validada.”

Fix em 1 linha:

sudo sed -i 's|ssh://localhost:2222|ssh://localhost:22|' /etc/cloudflared/config.yml

SSH externo subiu na hora. Lição registrada formalmente no PLANO_MESTRE/CLAUDE.md: validar premissa antes de construir camadas em cima dela.

D37 — Memory leak de 14 GB no clawmem-bridge (10/05 ~12h)

Encontrado por acaso. Estava listando processos da Larissa para validar estado pré-rewrite do runbook 18, e o output mostrou centenas de processos clawmem mcp órfãos. O claude.ai parou tudo:

“PARA TUDO — anomalia crítica detectada. Não vou mexer em runbook agora.”

MétricaValor
Processos clawmem mcp órfãos183
RAM consumida só por eles14 GB
RAM total do sistema15 GB (87% usada, 272 MB livre)
Swap usado1,2 GB de 4 GB
Processo mais antigo4 dias 16h rodando

Sistema beirando OOM. Causa: supergateway em modo streamableHttp stateless por padrão — cada chamada spawnou um processo clawmem mcp novo (stdio do MCP server) sem reusar nem encerrar. Issues upstream #103 e #111 documentam isso.

Fix permanente: flags --stateful --sessionTimeout 60000 em ambos os services (clawmem-bridge.service e start_fs_bridge.sh via wrapper script). sed com pattern diferente por arquivo — indentação divergia entre service file e shell script. Daemon-reload + restart.

MétricaAntesDepois
Processos clawmem mcp1832
RAM usada13 GB (87%)2,3 GB (15%)
RAM disponível1,6 GB13 GB

11 GB liberados.

Bug #228 da Anthropic — 5h perseguindo causa errada

Logo depois do fix do stateful, o claude.ai reportou erro 400 ao chamar /mcp-fs. O claude.ai chutou: “stateful mode incompatível com Worker.”

Cortei: “PROVAVELMENTE?” — apontando que estava chutando sem evidência. Mesma derrapagem da porta :2222, no mesmo dia.

Cinco horas de investigação. Várias hipóteses derrubadas: WAF (zero eventos), Worker bug (lendo index.ts linha por linha, transparente), scope diferente entre paths. Adicionei console.log [D37-DEBUG] no apiHandler do Worker, deploy, monitorei wrangler tail. Resultado: [D37-DEBUG] nunca apareceu. Conclusão com evidência objetiva: o OAuthProvider rejeitava a request antes de chegar no apiHandler.

Causa real, descoberta pelo reauth manual do connector: bug #228 da Anthropic — token Bearer OAuth do MCP connector expira em ~30min. Não era do stateful, nem do Worker, nem do supergateway.

Cobrei: “Gastamos 5 horas para solucionar, nenhum lugar falava sobre isso ou sua pesquisa falhou?”

Resposta: “Minha pesquisa falhou. A informação existia publicamente: issue #228 anthropics/claude-ai-mcp.”

D37 documentado em ~/larissa/docs/d37_memory_leak_2026-05-10.md. Worker revertido (limpeza do console.log [D37-DEBUG]), commit no repo mcp-larissa.

Cobranças do dia

A thread “Implementação da Larissa” (336 mensagens em 72h) concentrou cobranças repetidas, em ordem cronológica:

  1. Usar conversation_search em vez de ler ~/larissa/DECISIONS.md via MCP — falha de execução, não falta de ferramenta.
  2. Premissa :2222 nunca validada — 3 camadas construídas em cima: config.yml, ssh_config cliente, runbook 19.
  3. “PROVAVELMENTE?” — chutou causa do erro D37 antes de ter evidência. Mesma derrapagem do :2222, no mesmo dia.
  4. Propôs cron de restart para mitigar o memory leak em vez de fix na causa. Cobrança: “Caminho A era preguiça travestida de pragmatismo.”
  5. Recomendou encerrar a sessão sem que eu pedisse. Violou a própria regra registrada nas memórias: Elquer controls conversation closure.
  6. Mudou de ideia sobre a direção técnica ao interpretar cobranças de forma como abandono de caminho técnico.

Total: 6 cobranças formais, 6 recuos admitidos, todos com lição registrada.

kmaroteApp — 36 commits no dia 10/05

Trabalho em paralelo, concentrado em lista_postagens_canal e postagem_plataformas:

  • Edição automática de vídeo: card colapsável “Edição Automática” no hub + badge de pipeline na lista de postagens + tela “Fila de Processamento do Canal” + redimensionamento automático de logo PNG (modo contain)
  • Dropdown 3-dots: Popper strategy=fixed para não clipar dentro de tabelas; escopo da .dropdown do Socimo restrito ao .topbar (regra documentada na SKILL)
  • Opção Excluir (hard delete) adicionada no dropdown
  • Remove .table-responsive para dropdown não clipar — decisão arquitetural
  • Fix CSRF: form.submit()form.requestSubmit() (preserva token CSRF que submit() bypassa); remoção do botão Cancelar redundante do dropdown

Sessão kmaroteApp/9fd1eb22 foi a maior da janela — 7.847 turnos no Claude Code.

Pivot de produto

Decisão de fase: painel lariia-panel (multi-tenant SaaS, app.lariia.com.br) adiado para depois de atingir a meta de faturamento estabelecida. MVP = Kiwify + Telegram.

O claude.ai confrontou: “Tu disse há algumas mensagens que tu mesmo não compra cursos quando a comunidade é no Telegram e que público leigo BR prefere WhatsApp.” Resposta direta: “Não adianta eu querer aumentar a adesão de BR se não consigo finalizar o produto. Cada vez que tu me traz opção fala em semanas até meses para ter algo funcional. A ideia é começar vender ONTEM e não daqui 3 meses.”

Conversa “Preservar memória de projetos e decisões” marcada como include sempre no filter v12 — primeira decisão permanente no conversation-filter.json.

Devlog tooling

  • v13 da skill (2026-05-08): redaction patterns no Step 4.4. Identificadores sensíveis (AUD tags, KV namespace IDs, subdomínios *.workers.dev, team domain, JWT, tokens) viram placeholders. Heurística: “se o leitor pegasse o identificador e jogasse num scanner, conseguiria atacar/scrapear/enumerar?” → redigir.
  • 4 commits de redaction retroativa nos posts: ae1fd0b, f3556ac, d3b0c44 aplicaram a regra v13 no draft + post 2026-05-07, em UUIDs de conversa, AUD tag, KV namespace, account subdomain, team domain.

Pendências

  • Runbook 18 v2 — fechar rewrite (Hermes → OpenClaw, atualizar Cenário 6 com restore do vault ClawMem)
  • PLANO_MESTRE v3.1 → v3.2 — registrar D36 e D37 done, deletar referências a :2222, atualizar tabela de status do substrato
  • Reportar bug #228 da Anthropic (token MCP expirando em ~30min) — abrir issue no repo correto

Estatísticas do dia (geradas automaticamente):

Atividade no PC (janela de 105h35min — inclui viagem e sleep):

  • Tempo ativo: 19h09min
  • AFK: 86h27min

Por categoria (do que ficou ativo):

  • AI Chat: 9h22min
  • Coding: 6h13min
  • Larissa Project: 1h22min
  • Browsing: 35min

Top apps: Chrome (11h45min) · Antigravity IDE (5h24min) · Explorer (41min) · Windows Terminal (27min) · WhatsApp (22min)

Top sites navegados: claude.ai (3h52min) · gemini.google.com (54min) · dev-admin.kmarote.me (41min) · dash.cloudflare.com (12min)

Trabalho com IA:

  • Conversas claude.ai: 3 (372 mensagens)
  • Sessões Claude Code: 23 · 15.492 turnos

Código produzido:

  • Commits: 41 (36 kmaroteApp + 5 devlog)

Devlog do dia:

  • 1 draft consolidado (fontes: 3 conversas claude.ai + 23 sessões Claude Code)
Fim do ato