Mapa da trilha
Conteúdo detalhado
🐛 Erros comuns
CEF lib panic, sidecar legado, token bearer, deep links macOS e pre-push. O bestiário do OpenHuman.
Panic no boot do app: o runtime CEF tenta carregar Chromium e não acha — porque o bundle está incompleto.
É o erro nº1 de quem usa o @tauri-apps/cli stock. O fix é simples mas pouco óbvio: usar o CLI vendored.
CLI vendored em app/src-tauri/vendor/tauri-cef; pnpm tauri:ensure; reinstalar com cargo install --locked --path.
Em PR #1061 o sidecar foi removido. O core agora roda in-process como tokio task dentro do Tauri.
Docs antigos mandam rodar pnpm core:stage — hoje é apenas um echo. Procurar por sidecar quebra a cabeça à toa.
CoreProcessHandle, lifecycle atrelado ao Cmd+Q, RPC HTTP local em 127.0.0.1:<port>/rpc.
O core autentica chamadas com um bearer hex gerado a cada launch. Sem ele no header, tudo retorna 401.
Quando o core é externo (debug), o token vive em {workspace}/core.token. Não copiar = sign-in pendurado.
OPENHUMAN_CORE_REUSE_EXISTING=1; per-launch token; bearer em Authorization: Bearer ....
A propriedade window.__TAURI__ não existe no module load — checar direto resulta em false espúrio.
Bypass do wrapper contractual quebra detecção de ambiente. Sempre use isTauri() de webviewAccountService.
Wrapper canônico; try/catch ao redor de invoke(); nunca acessar globals Tauri direto.
Chamar o core RPC via fetch() dispara OPTIONS preflight do navegador — e falha por falta de CORS.
O caminho correto é invoke('core_rpc_relay', ...) que vai por IPC nativo, sem CORS.
Tauri IPC vs fetch; coreRpcClient abstrai isso; nunca chamar HTTP local direto da UI.
Deep links openhuman://... em macOS geralmente só funcionam quando o app está rodando como .app assinado, não em tauri dev.
Testar OAuth callback no dev e jurar que "está quebrado" é perda de hora. Faça build do bundle antes.
Launch Services; URL scheme registrado pelo Info.plist do bundle; pnpm test:e2e:build.
O Husky pre-push roda pnpm rust:check. Às vezes o main tem breakage não relacionado ao seu PR.
A regra: se a falha é em código que você NÃO tocou, --no-verify é OK — declare no PR. Se é seu, fix antes.
Husky; CI vai re-rodar de qualquer jeito; só nunca skip hooks em commits/sign que você assinou.
📜 Debug logging
Verbose por padrão, prefixos grep-friendly, correlation IDs, scripts/debug com tee, mock API admin.
CLAUDE.md exige: novos fluxos sempre com logs ricos — entry/exit, branches, external calls, retries, estados.
Mudança sem log de diagnose é considerada incompleta. PR vai voltar.
Logs como contrato de manutenção; "diagnose now, optimize later"; nunca logar secrets/PII.
Padronizar prefixos no início da mensagem permite filtrar com grep "\[memory\]" em segundos.
Sem prefixo, log fica indistinguível. Com prefixo + correlation ID, você reconstrói qualquer fluxo.
Prefixos por domínio; correlation IDs (request_id, entity_id); método sempre presente.
No core, use tracing::debug! ou log::debug! com campos estruturados. trace! para muito ruído.
Tracing permite spans correlacionados — uma request inteira tem o mesmo ID em todos os módulos.
#[instrument]; RUST_LOG=openhuman=debug; spans aninhados; campos estruturados.
No app, use a lib debug com namespaces (openhuman:chat, openhuman:rpc) — ativável seletivamente.
Console limpo em prod, verbose seletivo em dev (localStorage.debug = 'openhuman:*').
Wildcards; só dev-only detail; nunca console.log nu em produção.
pnpm debug {unit|e2e|rust} roda os tests com output truncado e tee para target/debug-logs/.
Salva contexto de agente E preserva log completo no disco para inspeção depois.
pnpm debug logs last; --tail N; --verbose para stream raw.
O mock backend expõe endpoints admin para inspecionar requisições recebidas, resetar estado e injetar behaviors.
Em vez de print/log, consulte GET /__admin/requests e veja exatamente o que o app mandou.
POST /__admin/reset; POST /__admin/behavior; pnpm mock:api.
O event bus do core já vem com TracingSubscriber que loga todo DomainEvent publicado.
Para entender ordem de eventos cross-domain, basta ligar o subscriber e ler — não precisa instrumentar manual.
subscribe_global; filtro por domains(); debug de subscribers próprios via name().
💎 Dicas avançadas
i18n strict, sem dynamic import, file size, controllers, light mod.rs, event bus owned, webview zero-injection.
Toda string UI passa por useT(). Adicionar uma chave exige atualizar en.ts + chunk en-N.ts + mesma chunk em TODOS os locales.
CI enforça via pnpm i18n:check. Faltar chave em qualquer locale falha o gate.
12 locales (ar, bn, de, es, fr, hi, id, it, ko, pt, ru, zh-CN); English como placeholder; chunks 1-5.
No app, import(), React.lazy(() => import(...)) e await import(...) são banidos em produção.
Static import + try/catch ou runtime guard. Exceções: tests, .d.ts, config files.
Bundle previsível; sem chunk loading runtime; import type sempre OK.
Preferência: arquivos com até ~500 linhas. Acima disso, dividir em sub-módulos.
Módulos grandes acumulam responsabilidade e ficam ilegíveis. Filosofia Unix.
Sharp-responsibility; ops.rs/store.rs/types.rs; export-focused mod.rs.
Para expor RPC/CLI, registre o domínio na controller registry. NUNCA adicione branches em dispatch.rs.
Branches manuais em core/ reintroduzem o acoplamento que controllers vieram remover.
all_controller_schemas; all_registered_controllers; wire em src/core/all.rs.
mod.rs só declara módulos e re-exports. Lógica vai em ops.rs, store.rs, types.rs.
Mantém o "índice" do domínio claro. mod.rs gordo esconde responsabilidades.
Subdir por domínio; novo código em arquivos siblings; dev_paths.rs/util.rs são exceções grandfathered.
Tipos passados no event bus precisam ser owned (Arc, channels, fields), Send + 'static — não Serialize, não borrows.
É request/response tipado in-process, não JSON-RPC. Lifetime de borrows não vive no canal.
register_native_global; oneshot::Sender para reply; método "domain.verb".
Webviews de provider (whatsapp, slack, telegram, discord) NÃO recebem JS injetado. Tudo via CDP nativo.
JS injetado em origem de terceiro = surface de ataque + scraping frágil. Migração explicitamente proibe novos scripts.
Network.*/Emulation.*/Input.* CDP; LoadHandler; cuidado com plugins (ex.: tauri-plugin-opener).