Kruze Companion — a camada Koder do Kruze como extensão multi-browser

accepted

Status

accepted — ratificada pelo owner em 2026-05-30. Efetivado na ratificação: surface extension + targets chromiumgeckosafari emendados em specs/variants/taxonomy.kmd §3.1/§3.2/§4/§5; variante registrada em registries/component-names.md + target-readiness.md; surface products/horizontal/kruze/extension/ scaffoldada com backlog das ondas (incl. contratos OpenAPI §8.1). As recomendações de §9 (D-open-123) ficam como diretriz de implementação.

1. Motivação

O Koder Kruze é o browser próprio da Stack (CEF/Flutter). Além do motor de browser, ele carrega uma camada Koder que o diferencia de um Chromium qualquer (README ## Koder Integrations):

  • Koder ID — login na conta Koder Stack.
  • Kode — painel do assistente, com MCP (KMCP-001/002: o Kode opera

    o browser e usa ferramentas).

  • Koder Observability — telemetria, error-reporter, breadcrumbs

    (065/094/100/112/117) e o Debug Mode v2 (164.x: captura de networkwebsocketstoragesourcemaptimeline/visual-diff).

  • Koder Pass — autofill, passkeys, vault (187/188/218).
  • Koder Capture — screenshotgravação (`153189`).

A maioria dos usuários, porém, não vai trocar de browser. A tese desta RFC: levar a camada Koder do Kruze para Chrome, Edge, Brave, Firefox e Safari via uma extensão — chamada Kruze Companion — para que qualquer browser ganhe Koder ID + Kode + Observability + Pass + Capture, dentro do que as APIs de extensão permitem.

2. Princípio orientador: extensão ≠ motor de browser

O Kruze tem duas metades. A primeira — abas, address bar, downloads, histórico, privacidade, reader mode, OSR/CEF, hibernação (a maioria dos ~220 tickets do backlog) — não deve ser portada: o browser host *já é* o motor. Reimplementar abas numa extensão é trabalho jogado fora.

A segunda metade — as Koder Integrations — é exatamente o que o usuário de Chrome não tem. O Kruze Companion é essa segunda metade, e só ela, injetada em qualquer browser. Esse recorte é o coração da proposta: a extensão entrega valor Koder, não um clone de browser.

3. Decisão D1 — nova surface canônica extension

specs/variants/taxonomy.kmd §3.1 fecha as surfaces em mobile, desktop, tv, web, cli, tui, backend, engine. Uma extensão de browser não cabe em web:

  • web (target browser) é uma página que roda dentro de uma aba

    PWA/SaaS. Seu ambiente é o documento.

  • Uma extensão roda na chrome do browser host: service worker em

    background, content scripts injetados em páginas de terceiros, side panel/sidebar, APIs privilegiadas (tabs, scripting, debugger, declarativeNetRequest). Seu ambiente é o browser, não a página.

São modelos de execução, empacotamento (manifest MV3 vs build web) e distribuição (Chrome Web Store / AMO / App Store vs deploy de site) distintos. §4 da taxonomia exige RFC explícita para adicionar surface (análogo a RFC-006 §3.4) — esta é essa RFC.

Proposta de emenda (efetivar em taxonomy.kmd + monorepo-RFC-006 na ratificação):

Eixo Adição
Surface extension — L4 origin extension/; "WebExtension MV3 injetada na chrome de um browser host"
Target chromium (active), gecko (active), safari (inactive — no Mac hardware, mesmo motivo de ios/macos)
Combinação válida extension × {chromium, gecko, safari} · form factor: laptop, desktop
Naming kruze-extension-chromium, kruze-extension-gecko, kruze-extension-safari; multi-engine no mesmo código → kruze-extension

Nota: o eixo "target" para a surface extension mapeia ao runtime de extensão / loja (chromium, gecko, safari), não ao SO — análogo a como engine usa o pseudo-target universal. Cada engine tem manifest, set de APIs, pipeline de release e loja distintos, logo merece variante própria para fins de paridade e release.

4. Decisão D2 — surface do sector kruze, não produto novo

O Kruze Companion é modelado como a surface extension do sector products/horizontal/kruze — não como um produto irmão.

Consequência decisiva (e a resposta à pergunta de processo que motivou esta RFC): a paridade Kruze ↔ Companion vira a matriz nativa de variantes do Kruze. O /k-parity kruze já constrói feature × variante a partir das variantes canônicas (precedente real: ticket 148 do Kruze, spawned por /k-parity kruze, auditou desktop × mobile). Com extension sendo variante do mesmo sector, a coluna da extensão entra sozinha na matriz — sem ninguém precisar lembrar de conferir. Se fosse produto separado, a paridade seria cross-component (mais frágil).

"Kruze Companion" é o display name da variante; o nome canônico de variante segue §5 da taxonomia (kruze-extension-*). Registro formal em registries/component-names.md + conformidade com specs/naming/forms.kmd na ratificação (gatilho "referenciar/nomear componente").

5. Decisão D3 — fronteira de reuso

Diretriz do owner (2026-05-30): *reaproveitar código sempre que possível, desde que isso não limite funcionalidades em nenhum dos dois lados.* É o espírito de policies/reuse-first.kmd aplicado — não regra nova.

Restrição dura: Kruze é FlutterDart; a extensão é JSTS (service worker e content scripts rodam no motor do browser host — não há Flutter ali). Logo o reuso não é de UI. A fronteira:

Reusável de fato Não reusável (diverge legitimamente)
Contratos — endpoints/schema do gateway do Kode, formato dos eventos de RUM que o apm espera, fluxo OAuth do Koder ID, protocolo MCP UI (Dart ↔ JS)
Clients tipados desses contratos Lógica de motor de browser (a extensão não precisa — o host já é o motor)
A chromium-extension/ do Koder Pass — já é JS/TS de WebExtension; reusável como código, não só como contrato Recursos de plataforma onde a extensão é mais restrita que o Kruze (ver §6)

Princípio: compartilha-se só o subconjunto comum. Nunca um denominador-comum de UI que force a extensão a não fazer X porque o Kruze não faz, nem vice-versa. Isso satisfaz a diretriz "não limitar nenhum dos dois".

Corolário (paridade de contrato como erro de build): se os contratos vivem num pacote compartilhado e tipado, quando a Observability ou o Kode adicionam um campo/endpoint, o build da extensão acusa "contrato novo não consumido". Paridade de contrato deixa de ser checklist e vira erro de compilação — cobrindo o caso "a mudança veio de outro componente, não do Kruze" que o /k-parity por-módulo sozinho não pega.

6. Matriz de viabilidade (WebExtension MV3)

🟢 viável · 🟡 parcial/com ressalva · 🔴 inviável sem app-wrapper

Camada Koder Chromium Gecko (FF) Safari Mecanismo
Koder ID login 🟢 🟢 🟢 identity/popup OAuth (oauth-flow.kmd)
Kode chat (sidebar + contexto da aba) 🟢 🟢 🟡 sidePanel/sidebar_action + content script
Kode opera a página (MCP browser) 🟡 🟡 🔴 tabs+scripting: navegarlerclicar; sem controle do chrome do host
Observability — RUM (erros/perf → apm) 🟢 🟢 🟢 content script: window.onerror, PerformanceObserver
Observability — Debug Mode v2 (networkWSstorage/sourcemap) 🟢 🟡 🔴 chrome.debugger (CDP); FF parcial; Safari sem CDP
Koder Pass (autofillpasskeysvault) 🟢 🟢 🟡 base já existe em services/foundation/pass/app/chromium-extension/
Koder Capture (screenshot/record) 🟡 🟡 🔴 captureVisibleTab ok; full-page/screen-share limitado

Dois fatos pautam o roadmap:

  1. chrome.debugger (CDP) é o trunfo que porta boa parte do Debug

    Mode v2 — Chromium-first; Gecko parcial; Safari não tem.

  2. Safari é caro: WebExtension convertida + app-wrapper Xcode + conta

    Apple Developer (já temos, ver infrastructure/accounts.md), e hoje sem Mac hardware (target safari = inactive). Fase final, não v1.

7. Mecanismo de paridade (não depende de memória)

Três peças, todas reusando maquinário existente:

  1. extension como variante canônica (D1) → entra sozinha na matriz

    do /k-parity kruze.

  2. /k-parity + /k-manifest rodam no /k-housekeep (diário) e

    pré-release; cada gap vira ticket (decisão de design por feature, como o ticket 148).

  3. Registry registries/kruze-companion-parity.md nos moldes de

    koder-id-auth-coverage.md (que bloqueia release se a linha não estiver verde). Matriz feature × {kruze-desktop, kruze-mobile, ext-chromium, ext-gecko, ext-safari} com 4 estados: 🟢 tem · ⚪ falta · 🟡 parcial · 🔴 impossível-na-plataforma. O 🔴 é decisão registrada — sem ele, o audit gritaria pra sempre sobre features que uma extensão nunca terá (ex.: hibernação de aba).

Mais o corolário de D3: paridade de contrato é erro de build.

8. Escopo do v1 e faseamento

Decisão do owner (2026-05-30): v1 = suite completa (as 5 camadas). Por stack-principles.kmd §2 (Quality > Speed) entregamos a suite completa em um único produto, faseada por viabilidade — não um MVP com limitações a remendar depois:

  • Onda 1 (núcleo de presença): Koder ID login → Kode na sidebar +

    RUM de observability. Tudo 🟢, prova as três capacidades-âncora.

  • Onda 2 (Pass + Observability profunda): Pass autofill (reusa a

    chromium-extension/ do Pass) + Debug Mode v2 via chrome.debugger (Chromium-first).

  • Onda 3 (Kode agente + Capture): MCP browser + captura, no teto do

    que cada engine permite.

  • Onda 4 (Safari): quando houver Mac hardware (flip de

    target safari → active em registries/target-readiness.md).

Cada onda abre tickets no backlog da surface extension do Kruze; a matriz de paridade (§7) governa o que entra e o que é 🔴-por-plataforma.

8.1 — Pré-requisito de alta alavancagem: contratos OpenAPI-first

Antes de qualquer código da extensão, formalizar os três contratos- âncora como OpenAPI (fonte de verdade no dono do serviço):

  1. Gateway do Kode (services/ai/ai/gateway) — chatstreamMCP.
  2. RUMcrash do apm (`infraobserve/apm`) — schema de eventos.
  3. OAuth do Koder ID (services/foundation/id) — já parcialmente em

    specs/auth/oauth-flow.kmd.

É o item de maior alavancagem: destrava o reuso cross-language (D3), torna a paridade de contrato um erro de build dos dois lados, e beneficia todos os consumidores Koder, não só a extensão. Sem ele, a extensão nasce como mais um client artesanal que diverge. Ordem global: contratos OpenAPI → Onda 1 → registry de paridade → ondas 2–4.

9. Decisões abertas → recomendações (2026-05-30)

Recomendações fundamentadas; ainda aguardam ratificação do owner.

  • *-open-1 (consolidação do Pass) → RECOMENDADO: um codebase, dois

    produtos de loja. O Companion é o superset; o Koder Pass standalone vira um build "Pass-only" do mesmo codebase (feature flag), não uma extensão separada. Duas SKUs nas lojas, zero duplicação — o "reusar sem limitar nenhum dos dois" de D3. Cuidado dura:*detecção mútua — com os dois instalados, um desativa seu módulo de autofill (senão dois autofills brigam no mesmo campo).

  • *-open-2 (onde mora o contrato) → RECOMENDADO: nem engines/sdk/

    novo, nem dentro do kruze/ — o contrato vive com o dono do serviço. A formulação original (escolher entre pacote novo vs dentro do kruze) estava errada. O padrão cross-language vem do design-RFC-006 (koder_kit Dart + koder_web_kit JS consomem uma fonte de tokens). Aplicar o mesmo trilho a contratos de API: OpenAPI no dono (gatewayapmid); o client Dart vai em koder_kit (→ Kruze); o client TS vai em @koder/sdk (engines/sdk/js) — o SDK JS real da Stack — não*em koder_web_kit (que é o kit de UI/CSS).

    • Correção de reuso (2026-05-30, walk-codebase): @koder/sdk

      contém boa parte dos clients que a extensão precisa: KoderClient + Span (transporte + tracing), agent-stream (decoder do Koder Agent Stream Protocol, spec specs/ai/agent-stream.kmd), kode-conversation (@koder/kode-conversation — Web Component de transcript do Kode) e instrumentation/ (auto-instrumentação de telemetria). A extensão consome*@koder/sdk + @koder/kode-conversation; não gera client do zero. Pré-requisito: §8.1 (os 3 serviços não expõem OpenAPI hoje).

  • *-open-3 (loja e identidade visual) → RECOMENDADO: menor privilégio +

    permissões on-demand; AMO primeiro.*

    • Ícones via kicon generate (specs/icons/products.kmd +

      generation-targets.kmd, tamanhos 1648128) — nunca PNG à mão.

    • Nome: "Kruze Companion" = display; bare/slug em

      registries/component-names.md por specs/naming/forms.kmd.

    • Permissões MV3: núcleo mínimo (storage, activeTab, identity);

      <all_urls> e chrome.debugger só via optional_permissions, pedidas quando o usuário ativa RUM amplo / Debug Mode (melhor aprovação + privacidade).

    • Lojas: temos Apple Developer (Safari) e Google Play, mas *hrome Web

      Store e AMO são contas de publisher separadas que ainda não temos*(infrastructure/accounts.md só lista Google Play). Começar pela AMO (Firefox; grátis, review mais leve); provisionar Chrome Web Store (US$5 one-time) em paralelo; registrar ambas em accounts.md.

10. Impacto na Stack — efetivado na ratificação (2026-05-30)

  1. specs/variants/taxonomy.kmd emendado (§3.1 surface extension,

    §3.2 targets chromiumgeckosafari, §4 combinação, §5 naming) + referência em monorepo-RFC-006.

  2. registries/target-readiness.md: chromium/gecko active, safari

    inactive (no Mac hardware). component-names.md não recebe linha nova — "Kruze Companion" é a surface extension do componente kruze (variante, não componente); naming kruze-extension-* já coberto pela taxonomia §5. "Kruze Companion" é só o display name de loja da variante (análogo a pass-desktop não ter linha própria).

  3. registries/kruze-companion-parity.md (matriz 4-estados) criado.
  4. ✅ Surface products/horizontal/kruze/extension/ scaffoldada + backlog

    das ondas (incl. contratos OpenAPI §8.1).

  5. Pacote de contratos: sem pacote próprio (D-open-2 corrigida) —

    OpenAPI no dono do serviço; client TS via @koder/sdk (engines/sdk/js) (já tem agent-stream + kode-conversation + instrumentation), client Dart via koder_kit. koder_web_kit = UI/CSS, não clients de API.