Koder Kruze — `products/horizontal/kruze/app/desktop`

  • Area: Workspace
  • Path: products/horizontal/kruze/app
  • Version: 1.0.7
  • Status: Active beta
  • Kind: Flutter desktop browser app

Role in the stack

Koder Kruze is the Workspace browser: a Flutter desktop app that combines a tabbed webview surface with Koder ID account access and a Koder AI assistant panel. It is the user-facing place where internal koder:// pages, web content, account management, downloads, bookmarks, and AI help meet inside one desktop shell.

The current implementation targets Linux through webview_cef, with Android project files present and broader platform work tracked in the module backlog. Kruze is also a Koder app consumer of the shared Flutter SDK surface: KoderApp wraps the root app, engines/sdk/store provides update checks, and the app is moving remaining local cross-cutting behavior toward koder_kit.

Core capabilities

  • Tabbed browsing — multiple tabs, close/reopen, duplicate, reorder, pin,

    and keyboard shortcuts

  • Address bar — URL normalization, search fallback, and preserved internal

    schemes such as koder://settings

  • Internal pages — settings, downloads, extensions, and history (koder://history) rendered in-app
  • Privacy controls — incognito history suppression, tracker-blocked

    navigation screen, and best-effort cookiesite-datacache cleanup on incognito exit

  • Downloads — direct-download detection, persisted history, destination

    preferences, progress state, and humanized HTTP failure handling

  • Bookmarks — persisted bookmarks, folders, and a toggleable bookmark bar
  • AI panel — Koder AI chat panel with file attachments and persisted panel

    placement, model, temperature, and page-context settings; opt-in OpenAI-native contract (preview, flag ai.openai_native_contract) that routes chat directly to ai-gateway via OpenAI-compat /v1/chat/completions and supports the MCP tool-use loop against user-configured MCP servers (KMCP-001 / KMCP-001.2)

  • Extensions — WebExtension-style content-script matching and injection
  • Account sidebar — Koder ID login state and account-management entry point
  • Error registryKRUZE-* user-facing error IDs with copyable technical

    details for AI, download, and auth failures

  • Page zoom — per-tab zoom (Ctrl++/−/0, range 25%–300%) via CSS; address bar zoom badge
  • Theme toggle — Dark / Light / System from Settings → Appearance, persisted via SharedPreferences
  • Browsing historykoder://history with search and clear, date-grouped sections, opened via Ctrl+H
  • AI retry backoff — chat requests retried up to 3× (0 s → 1 s → 3 s) before surfacing error
  • Self-update check — Koder Hub update prompt on startup
  • Sidebar nav shortcuts — Downloads, Extensions, History buttons in sidebar with active-page highlight and download badge
  • Favicon display — tab bar and bookmark bar show each site's favicon via JS extraction + host cache (max 100 entries)
  • Tab session restore — open tabs persisted to SharedPreferences and restored on next launch
  • Bookmark bar context menu — right-click on bookmarks (EditDeleteOpen in new tab) and folders (Open allRenameDelete)
  • Extension script cache — in-memory cache (path → source) with eviction on toggle/uninstall
  • Extension install UI — "Install" button in Extensions screen opens folder picker
  • AI chat persistence — last 200 chat messages survive restarts (incognito-aware, purged on account boundary)
  • Telemetry eventsKoderTrack emits tabnavigateaiauthdownload events to the koder_kit telemetry pipeline; host suppressed in incognito
  • Address-bar autocomplete — overlay with up to 8 ranked matches (bookmarks first, then history) with full keyboard navigation
  • Extension consent dialog — folder install prompts with humanized permission list and "Broad access" badge before any files are copied
  • Tab audio mute — context menu + clickable inline icon; JS-based mute (no native API in webview_cef 0.2.2) re-applied after navigations
  • Print / Save as PDFCtrl+P and tab-context entry trigger the OS print dialog (Save as PDF available there)
  • Install as app (PWA) — detects a visited site's web app manifest and offers an install button that creates an OS app-shortcut; launching it reopens the site in app-mode. Desktop: Linux .desktop / macOS .app / Windows .lnk + chrome-less --pwa-url window (KRUZE-191 infra + KRUZE-239 wiring). Android: home-screen launcher shortcut via ShortcutManagerCompat (KRUZE-240). The detection provider is engine-agnostic (shared across CEF/inappwebview). iOS "Add to Home Screen" is system-only and out of scope
  • Full-page PDF export — address-bar button (also Ctrl+Alt+P) renders the entire scrollable content of the active tab to a PDF in ~/Documentos/ via the vendored webviewcef plugin's new printToPdf method (CefBrowserHost::PrintToPDF); `prefercsspagesizetrue, print_backgroundtrue`, A4 fallback, tagged-PDF + document outline enabled (KRUZE-160)
  • Debug Mode — address-bar bug-report toggle starts a session under ~/Documentos/Kruze Debug/<timestamp>/{images,videos,logs,replay}/ that records video of the tab content area; captures viewport screenshots on every onLoadEnd and on every click (cursor + element rectangle + selector label drawn onto click screenshots); tails every browser console message into logs/console.jsonl with source-map-resolved stack frames for minified bundles; tails every CDP Network.* event into logs/network.jsonl and Network.webSocket* into logs/websocket.jsonl; snapshots cookies + localStorage + sessionStorage at startstop into `logsstorage-{start,stop}.json; runs MTR network-path traces against the active host + 8.8.8.8/1.1.1.1/google.com baselines into logsnetwork-path.jsonl`; records tab title timeline + focusblur + active-tab-switch into logs/tab-timeline.jsonl; generates per-pixel visual diffs between repeat navigations to the same URL; emits a chromedp Go replay script that reproduces the captured action sequence; assembles a self-contained index.html report with video player + interactive timeline + screenshot gallery; every screenshot ships with a white URL header strip at the top (KRUZE-161163164); on stop, asks whether to open the folder in the file manager
  • History store — sqflite-backed (10k cap, indexed, keyset-paginated), one-shot migration from the legacy SharedPreferences blob
  • Address-bar autocomplete consults the full sqflite history (not just the in-memory mirror), with a stale-result guard for in-flight queries
  • Async error reportingrunZonedGuarded routes unhandled async errors through KoderTrack alongside the synchronous errors caught by KoderErrorBoundary
  • Settings → Restore defaults — flatten preferences (homepage / engine / theme / privacy) without touching data
  • User-defined search engines — OpenSearch-style templates (%s placeholder) in addition to the built-in Koder / Google / Bing / DuckDuckGo
  • Tab hover preview — 500 ms hover on a tab reveals a card with favicon + full title + URL (no real screenshot — webview_cef 0.2.2 has no snapshot API)
  • Close-many-tabs confirmation — "Close other tabs" / "Close tabs to the right" prompt with Close N tabs? when the action would close ≥ 3 tabs
  • Settings export/import — versioned JSON document (homepage, engines, theme, blocked domains, AI panel layout); partial JSON applies only present sections; bookmarkshistoryauth deliberately excluded
  • Bookmark searchkoder://bookmarks page with a single search box and a flat list across all folders; bookmark bar gains a "Manage all bookmarks" entry-point
  • Chromium DevToolsF12 and a tab-context entry call webview_cef.openDevTools()
  • Koder native inspector — a docked, Verge-styled inspector built on the in-process CDP (Debug Mode v2), independent of Chromium DevTools, with 7 panels: Console (REPL + live logs), Elements (DOM tree + matched styles), Sources (loaded resources), Network (live request log + bodies), Performance, Memory and Application (cookies + localsession storage). Performance has a Metrics view (Performance.getMetrics) and a Timeline view that records a Tracing trace and renders a main-thread flame chart — a CustomPaint with a time ruler that zooms (mouse wheel around the cursor), pans (drag) and resets (double-click) over a model-held view-window — plus a summary that toggles between the flat self-time table and the bottom-up call tree (callee→caller aggregation of self time). Memory takes a v8 heap snapshot showing totals + top constructors by self size; selecting a constructor opens the retainer view — its heaviest instance's "retained by" path (reverse-edge BFS to the GC root) and retained size (dominator tree), parsed from the snapshot's edge graph. The whole inspector is decoupled from the live CEF browser behind a CdpClient seam, so every panel is exercised headless under flutter test with no browser and no display (RFC-005 Camada A). KRUZE-186 (8-panel epic) → 230 (Timeline v1 + Memory v1) → 231 (flame zoompan + ruler, bottom-up tree, heap retainer graph)
  • Address-bar clear button — small ✕ on the right when the field has focus and content
  • Per-host zoom memory — host → zoom map (FIFO 200 entries, persisted) auto-applied on navigation; reset forgets the host
  • Find-bar case-sensitivityAa toggle threaded through both window.find() and the match counter so the displayed count agrees with the highlight
  • Paste-and-goCtrl+Shift+V reads the clipboard and navigates after the address-bar normalization pipeline
  • Bookmark export/import — versioned JSON document on koder://bookmarks; additive merge, dedup by URL/folder id
  • PDF inline preview — Settings → Downloads toggle (default on); .pdf URLs render in-tab via webview_cef's Chromium PDF viewer
  • "+" tab respects home page — parity with Ctrl+T
  • All-tabs dropdown — chevron between "+" and window controls lists every tab (favicon + title) for quick jumps once the strip overflows
  • History page pagination — scroll past the 200-entry in-memory cache loads more from sqflite in pages of 100
  • F11 fullscreen — toggles windowManager.setFullScreen; Esc exits when no find bar is open
  • Link-hover status pill — bottom-left pill shows the resolved URL of any link under the cursor (delegated JS listener over a kruzeLinkHover channel)
  • Site-info popover — clicking the address-bar padlock opens a connection summary with a "Open DevTools" action
  • Page-load timing telemetrypage.load event with elapsed ms and host (host suppressed in incognito)
  • Remote tracker blocklisthttps://cdn.koder.dev/kruze/blocklist.json (24h TTL); merged on top of the built-in default; falls back to cached/default when the CDN is unavailable
  • AI streaming responses/api/chat/stream SSE; placeholder message fills in token-by-token; falls back to legacy POST on 404
  • Extension signature verification — manifest koder_signature field; consent dialog and tile show verified / invalid / unsigned; no install path is blocked (CA still pending)
  • Bookmark sync via Koder IDhttps://api.koder.dev/kruze/bookmarks with local-wins merge and a sync indicator in the bookmark bar (idle / syncing / error / offline); falls back to local-only when the endpoint is unavailable
  • Quick switcher (Ctrl+K) — fuzzy palette over open tabs + bookmarks, fully keyboard-driven
  • Reading list — read-later queue at koder://reading-list with sidebar entry (unread badge) and an address-bar toggle book icon
  • Force dark on light pages — Settings → Appearance toggle injects an inversion CSS filter; respects user's light theme choice
  • Symmetric tab close + reload-all — "Close tabs to the left", "Close tabs to the right", "Reload all tabs" in the tab context menu
  • Bookmark sorting — Newest / Oldest / Alphabetical dropdown on koder://bookmarks

Primary couplings

Dependency Relationship
engines/sdk/koder_kit App shell through KoderApp; supplies shared Koder app behaviors such as theme, telemetry, error boundary, deep-link subscription, and IPC bootstrap
engines/sdk/store Startup update check through KoderHubUpdater.check(slug: appSlug, currentVersion: appVersion)
foundation/id OIDC authorizetokenuserinfo endpoints used by Kruze account login
ai/gateway AI chat provider posts browser-assistant messages to https://ai.koder.dev/api/chat

Interfaces

  • koder://settings — in-app settings page
  • koder://downloads — in-app downloads page
  • koder://extensions — in-app extension manager
  • koder://history — in-app browsing history
  • koder-kruze / Flutter package koder_kruze
  • Android package name: dev.koder.koder_kruze

Status

v1.0.43 (2026-05-26) — released. tenth /k-evolve pass added five product features (KRUZE-95–KRUZE-99): a quick switcher palette over Ctrl+K, a read-later queue at koder://reading-list with sidebar badge, a force-dark CSS filter toggle, symmetric close-tabs-to-the-left + reload-all-tabs, and sort-by NewestOldestAlphabetical on the bookmarks page. Local backlog is empty; the only remaining items are the corresponding backend tickets tracked in foundationid, aivoice, ai/gateway, infra/cdn.

2026-05-16 robustness + architecture wave (/k-go kruze):

  • KRUZE-143 — desktop CEF stale-Singleton* symlinks (left by any

    non-clean exit at ~/.config/cef_user_data/) no longer block the next launch. A Linux-only pre-flight removes the trio when the SingletonLock target points at a dead PID, and SIGTERM/SIGINT handlers wipe them on the way out. Per-app root_cache_path isolation tracked separately in KRUZE-145.

  • KRUZE-139 — shared providers (BookmarkProvider,

    ReadingListProvider) now persist through a KruzeStore interface with SharedPreferencesStore (production) and InMemoryStore (tests) backends. Theme tokens were already unified via koderTheme() in koder_kit. Extending the abstraction to the remaining shared providers is KRUZE-146.

  • KRUZE-140 — mobile InAppWebView honors two new global Privacy

    toggles ("Block notifications" / "Block geolocation requests", default OFF). When ON, the engine's onPermissionRequest returns DENY without showing the OS dialog; when OFF, returns PROMPT so the OS dialog asks normally. Desktop CEF parity is KRUZE-147.

  • KRUZE-144 i18n full coverage (closed 2026-05-16) — every

    user-facing string in the desktop variant goes through KoderL10n.t(key, fallback: ...) with en-US + pt-BR coverage registered at boot. ~290 keys across 6 waves: sidebar + settings primary (Phase 1), AI panel + bookmark bar + reading list + findaddress bars (Phase 2), 5 internal `koder:/ pages including history/bookmarks/sessions/recently-closed/extensions plus downloads + settings core (Phase 3), search-engine modal + reporter + account flow + quick switcher + settings sub-dialog tail (Phase 4). KoderL10n.t doesn't yet support ICU params; placeholder strings use {name}/{n}/{file} patterns + inline .replaceAll()`. Mobile variant still uses fallback strings (full mobile i18n is variant-level follow-up).

Test totals after the wave: 246 desktop + 35 mobile + 38 shared = 319, all green.

2026-05-16 privacy + parity wave (/k-go kruze):

  • KRUZE-146KruzeStore now backs PrivacyProvider +

    BrowserSettingsProvider. The abstraction picked up setDouble / getDouble for defaultZoomLevel. AuthProvider left unchanged — documented inline as having no local persistence (delegated to koder_kit's KoderAuth).

  • KRUZE-147 — desktop notification + geolocation gates now respect

    the KRUZE-140 globals. New BrowserProvider.blockNotificationsGlobal / blockGeolocationGlobal mirror fields, plus pure-decision helpers shouldDenyNotificationsFor(host) / shouldDenyGeolocationFor(host) for testable two-stage policy (global wins over per-host allow).

  • KRUZE-148 mobile parity audit closed. #148.5 (recently-closed)

    shipped inline: app/mobile/lib/recently_closed.dart ring buffer + long-press on bottom-nav + opens reopen bottom-sheet. #148.1 AI chat, #148.2 downloads (Android system DM + iOS in-app split), #148.3 extensions (content-script subset), #148.4 sessions spawned to pending/.

  • KRUZE-145 — vendor webview_cef for CefSettings.root_cache_path

    remains deferred. Detailed pre-vendoring checklist added to the ticket; needs cross-platform native rebuild (LinuxmacOSWindows CEF).

Test totals after the wave: 269 desktop + 42 mobile + 45 shared = 356, all green.

2026-05-16 mobile parity wave 2 (/k-go kruze):

  • KRUZE-148.4SessionsProvider lifted to koder_kruze_shared

    (KruzeStore-backed). Desktop keeps the old import path via a one-liner re-export shim. Mobile gains a SessionsScreen (drawer entry) for listrestoredelete plus a long-press-tab-card flow that prompts for a name and saves the current tab set.

  • KRUZE-148.1AiChatProvider lifted to koder_kruze_shared

    (KruzeStore-backed). Desktop re-export shim preserves all 8 existing AI chat tests. Mobile gains a minimal AiChatScreen (drawer entry) with user/assistant bubbles + TextField + send + clear-with-confirm. Attachments, model picker, temperature slider, and tablet bottom- sheet variant deferred — v1 just unblocks parity.

Test totals after the wave: 269 desktop + 48 mobile + 48 shared = 365, all green.

2026-05-16 web companion wave (/k-go kruze):

  • KRUZE-135 — new app/web/ Flutter Web variant. PWA companion that

    surfaces bookmarks, reading list, and a subset of settings (theme, homepage read-only, default search engine read-only) without embedding a webview. 4 tabs (Home / Bookmarks / Reading list / Settings), responsive nav (NavigationRail ≥720px, bottom NavigationBar otherwise), Koder ID sign-in via KoderApp. Storage routes through KruzeStoreSharedPreferencesStore → browser localStorage. flutter build web --release ~34s, 4 widget tests. Vhost on kruze.koder.dev/companion is infra/net/jet#154. Cross- device sync depends on the as-yet-unbuilt cross-cutting sync SDK — companion is local-to-tab until then.

  • AuthProvider_auth switched from late final to nullable so

    widget tests can construct it without paying the network init. Production unchanged (init runs at boot).

Test totals after the wave: 269 desktop + 48 mobile + 48 shared + 4 web = 369, all green.

2026-05-17 mobile downloads (/k-go kruze):

  • KRUZE-148.2 v1 — onDownloadStartRequest wired with

    useOnDownloadStart: true in the InAppWebView settings. The new pure helper handleDownloadRequest launches the URL via url_launcher in LaunchMode.externalApplication. Android hands off to Chrome (system DownloadManager native); iOS hands off to Safari (iOS download UI). No native code in v1. Tighter in-app experience (Android direct DM enqueue + iOS download bottom-sheet) tracked under #148.2.1. 4 mobile tests for the helper.

Test totals after the wave: 269 desktop + 52 mobile + 48 shared + 4 web = 373, all green.

2026-05-17 TV scaffold (/k-go kruze):

  • KRUZE-137 v1 — app/tv/ TSReactVite scaffold mirroring Tune's

    stack. 5 screens (HomeBookmarksReading listHistorySettings) read-only because cross-device sync hasn't shipped. D-pad nav via @noriginmedia/norigin-spatial-navigation. Forced dark theme. npm run build ~205 KB JS / ~67 KB gzip. 4 vitest tests. Tizen/WebOS packaging + real webview engine deferred to #137.1.

2026-05-17 Universal Links server-side (/k-go kruze):

  • KRUZE-141 server-side shipped in services/foundation/id. Two

    new .well-known/ handlers (apple-app-site-association for iOS Universal Links, assetlinks.json for Android App Links) live at id.koder.dev. Both env-var configurable, return 404 when unset (no app to claim deep-link ownership of yet). Multi-app support, content-type pinned to application/json, cache TTL 1h. 7 tests in the id repo. Client iOS (Associated Domains capability) + Android release key fingerprint tracked under #141.1, Mac-runner blocked. CHANGELOG entry in the id module.