MÓDULO 1.3

🔄 Domínios e fluxo de dados

O core por dentro: dezenas de domínios, agente, pipeline de memória, channels/threads, event bus tipado e o padrão de controllers que une CLI e JSON-RPC.

6
Tópicos
45
Minutos
Básico
Nível
Teoria
Tipo

Conteúdo detalhado

1

🗺️ Mapa dos domínios

O diretório src/openhuman/ abriga dezenas de domínios, cada um em sua pasta. Conhecer os principais é o atalho para se localizar em qualquer issue.

📦 Domínios principais

agent orquestrador
memory memória persistente
channels entrada multi-canal
threads conversas
skills metadata
cron scheduler
webhooks eventos externos
providers LLM providers
tools tool surface
meet meet integration
voice áudio
billing cota / wallet
credentials segredos cifrados
subconscious consolidação
tree_summarizer resumos

📐 Layout interno do domínio

  • mod.rs — exports apenas (leve)
  • types.rs — structs do domínio
  • store.rs — persistência
  • ops.rs — lógica de negócio
  • rpc.rs — handlers que respondem a RPC
  • schemas.rs — registry de controllers
  • bus.rs — subscribers do event bus (quando aplicável)

⚠️ Regra de pasta

Novos arquivos vão em subdiretório dedicado. Não criar src/openhuman/<coisa>.rs solto. util.rs e dev_paths.rs são grandfathered, não template.

PASTA
Domínio = dir
FRONTEIRA
mod.rs leve
CONTRATO
schemas.rs
HÁBITOS
≤500 linhas/arquivo
2

🤖 Agent harness

O src/openhuman/agent/ é onde o LLM ganha mãos e olhos. Ele monta o contexto, expõe ferramentas, controla aprovações e respeita timeouts.

🧠 Componentes do harness

  • Prompts bundled em src/openhuman/agent/prompts/ — também empacotados via tauri.conf.json resources.
  • Tool surface — quais ferramentas o modelo vê (memory, channels, skills, …).
  • Approval gates (approval/) — ações sensíveis pedem confirmação.
  • Tool timeout — execuções longas não travam o agente.
  • Autocomplete — sugestões durante input do usuário.

💡 Skills runtime foi removido

O QuickJS / rquickjs que executava skills foi retirado. src/openhuman/skills/ hoje é só metadata: discover/install/parse/inject. Não tente "rodar skill" em produção — esse caminho não existe mais.

PROMPT
prompts/ bundled
TOOLS
Surface tipada
APROVAÇÃO
approval/
TIMEOUT
tool_timeout
3

🧠 Pipeline de memória

Sem memória, OpenHuman seria mais um wrapper. Com ela, é assistente. A pipeline tem três peças que trabalham assíncronas: memory (store), subconscious (consolidação) e tree_summarizer (resumos hierárquicos).

1

memory — armazena

Embeddings, items, recuperação por similaridade

Recebe novos fatos (mensagens, decisões, fatos sobre pessoas). Indexa via embeddings para busca semântica. Source of truth da memória do agente.

2

subconscious — consolida

Workers assíncronos em background

Faz pós-processamento: dedup, refinamento, vinculação a entidades, decay. Roda fora do caminho crítico para não engasgar respostas.

3

tree_summarizer — resume

Hierarquia de sumários

Threads grandes viram resumos de N níveis. O agente carrega o resumo certo para o tamanho de janela disponível, em vez de tudo.

🔍 Por que três peças

Síncrono = lento. Tudo no caminho do request quebraria UX. Separação permite que cada peça evolua e falhe isoladamente (memória continua funcionando se o sumarizador atrasar).

STORE
memory
BACKGROUND
subconscious
RESUMO
tree_summarizer
CONTEXTO
Sem estourar janela
4

📨 Channels e threads

Não confunda: channels são as origens (Slack, Gmail, WhatsApp); threads são as conversas que agrupam mensagens com contexto compartilhado, podendo cruzar canais.

📡 channels

  • Abstração da origem (uma por provedor)
  • Recebe via webhook, scraping CDP, polling
  • ChannelInboundSubscriber escuta o bus
  • Normaliza para evento interno comum

💬 threads

  • Agrupamento por contexto, não por canal
  • Mantém histórico para o agente
  • Pode ter mensagens de múltiplos channels
  • Surface em /chat da UI

🗺️ Fluxo típico de mensagem

Mensagem chega no Slack → scanner CDP captura → publica evento no bus → ChannelInboundSubscriber normaliza → cria/atualiza thread → agente decide se responde → memória atualiza.

CHANNEL
Origem
THREAD
Conversa
FAN-IN
Múltiplas fontes
SURFACE
/chat unificado
5

📡 Event bus tipado

Em src/core/event_bus/ mora a espinha dorsal de coordenação entre domínios. Tem dois modos: broadcast pub/sub e request/response 1:1 nativo (zero serialização).

📣 Modo 1 — Broadcast tipado

// publisher publish_global(DomainEvent::ChannelMessageReceived { ... }); // subscriber (impl EventHandler) struct CronDeliverySubscriber; impl EventHandler for CronDeliverySubscriber { fn name(&self) -> &str { "cron::delivery" } async fn handle(&self, event: &DomainEvent) { ... } } subscribe_global(Arc::new(CronDeliverySubscriber));

🎯 Modo 2 — Native request/response

// 1:1 por método, sem serialização — Arc, mpsc, oneshot passam direto register_native_global("memory.search", Arc::new(handler)); let resp = request_native_global::<SearchReq, SearchResp>( "memory.search", req ).await?;

🎚️ Domínios do bus

agent, memory, channel, cron, skill, tool, webhook, system. Subscribers ficam em <domain>/bus.rs com convenção <Purpose>Subscriber + name() = "<domain>::<purpose>".

💡 Quando usar cada modo

Broadcast para "aconteceu X, quem quiser ouvir reage". Native r/r para "preciso do resultado de Y agora, sem JSON, sem latência de fan-out". Native é interno — RPC público vai por src/core/all.rs.

PUB/SUB
publish_global
REQ/RESP
native_global
EVENT
DomainEvent enum
RAII
SubscriptionHandle
6

🎛️ Controller pattern

Como uma função do core fica disponível para CLI e JSON-RPC ao mesmo tempo, sem duplicação? Via controller registry.

📋 Checklist de migração para controller

// 1. Domínio expõe módulo schemas // src/openhuman/<dominio>/mod.rs mod schemas; pub use schemas::{ all_controller_schemas as all_<dominio>_controller_schemas, all_registered_controllers as all_<dominio>_registered_controllers, }; // 2. schemas.rs define schemas + handle_* // que delegam para rpc.rs // 3. Wire em src/core/all.rs // 4. Remover branches em src/core/dispatch.rs

✓ Fazer

  • Definir ControllerSchema + FieldSchema
  • Retornar RpcOutcome<T> (ver AGENTS.md)
  • Registrar via all_registered_controllers
  • Adicionar teste em tests/json_rpc_e2e.rs

✗ Evitar

  • Adicionar branch em src/core/cli.rs
  • Adicionar branch em src/core/jsonrpc.rs
  • Duplicar tipos entre CLI e RPC
  • Lógica gorda em mod.rs do domínio

📖 Leitura obrigatória

O contrato detalhado vive em AGENTS.md (raiz do repo) — RpcOutcome<T>, naming, retornos. Antes de qualquer PR que toque RPC, ler.

REGISTRY
Controllers
SCHEMA
ControllerSchema
RETORNO
RpcOutcome<T>
EXPOSIÇÃO
CLI + RPC unif.

🌱 Resumo do Módulo

Domínio = pasta — src/openhuman/<dominio>/ com mod.rs leve
Agent harness — prompts, tools, approval, timeouts
Memória em 3 peças — memory + subconscious + tree_summarizer
Channels ≠ threads — origem vs conversa contextual
Event bus — broadcast + native request/response tipado
Controller registry — CLI e JSON-RPC compartilham o mesmo contrato

Próxima trilha:

Trilha 2 — 📦 Instalação (setup local, dev e build de produção)