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 toai-gatewayvia OpenAI-compat/v1/chat/completionsand 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 registry —
KRUZE-*user-facing error IDs with copyable technicaldetails 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 history —
koder://historywith search and clear, date-grouped sections, opened viaCtrl+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 events —
KoderTrackemits 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 PDF —
Ctrl+Pand 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-urlwindow (KRUZE-191 infra + KRUZE-239 wiring). Android: home-screen launcher shortcut viaShortcutManagerCompat(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 newprintToPdfmethod (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 everyonLoadEndand on every click (cursor + element rectangle + selector label drawn onto click screenshots); tails every browser console message intologs/console.jsonlwith source-map-resolved stack frames for minified bundles; tails every CDP Network.* event intologs/network.jsonland Network.webSocket* intologs/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 intologsnetwork-path.jsonl`; records tab title timeline + focusblur + active-tab-switch intologs/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-containedindex.htmlreport 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 reporting —
runZonedGuardedroutes unhandled async errors throughKoderTrackalongside the synchronous errors caught byKoderErrorBoundary - Settings → Restore defaults — flatten preferences (homepage / engine / theme / privacy) without touching data
- User-defined search engines — OpenSearch-style templates (
%splaceholder) 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 search —
koder://bookmarkspage with a single search box and a flat list across all folders; bookmark bar gains a "Manage all bookmarks" entry-point - Chromium DevTools —
F12and a tab-context entry callwebview_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
CustomPaintwith 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 aCdpClientseam, so every panel is exercised headless underflutter testwith 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-sensitivity —
Aatoggle threaded through bothwindow.find()and the match counter so the displayed count agrees with the highlight - Paste-and-go —
Ctrl+Shift+Vreads 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);
.pdfURLs 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;Escexits 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
kruzeLinkHoverchannel) - Site-info popover — clicking the address-bar padlock opens a connection summary with a "Open DevTools" action
- Page-load timing telemetry —
page.loadevent with elapsed ms and host (host suppressed in incognito) - Remote tracker blocklist —
https://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/streamSSE; placeholder message fills in token-by-token; falls back to legacy POST on 404 - Extension signature verification — manifest
koder_signaturefield; consent dialog and tile show verified / invalid / unsigned; no install path is blocked (CA still pending) - Bookmark sync via Koder ID —
https://api.koder.dev/kruze/bookmarkswith 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-listwith 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 pagekoder://downloads— in-app downloads pagekoder://extensions— in-app extension managerkoder://history— in-app browsing historykoder-kruze/ Flutter packagekoder_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 anynon-clean exit at
~/.config/cef_user_data/) no longer block the next launch. A Linux-only pre-flight removes the trio when theSingletonLocktarget points at a dead PID, and SIGTERM/SIGINT handlers wipe them on the way out. Per-approot_cache_pathisolation tracked separately in KRUZE-145. - KRUZE-139 — shared providers (
BookmarkProvider,ReadingListProvider) now persist through aKruzeStoreinterface withSharedPreferencesStore(production) andInMemoryStore(tests) backends. Theme tokens were already unified viakoderTheme()inkoder_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
onPermissionRequestreturns 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-146 —
KruzeStorenow backsPrivacyProvider+BrowserSettingsProvider. The abstraction picked upsetDouble/getDoublefordefaultZoomLevel.AuthProviderleft unchanged — documented inline as having no local persistence (delegated tokoder_kit'sKoderAuth). - KRUZE-147 — desktop notification + geolocation gates now respect
the KRUZE-140 globals. New
BrowserProvider.blockNotificationsGlobal/blockGeolocationGlobalmirror fields, plus pure-decision helpersshouldDenyNotificationsFor(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.dartring 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_cefforCefSettings.root_cache_pathremains 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.4 —
SessionsProviderlifted tokoder_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.1 —
AiChatProviderlifted tokoder_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 thatsurfaces 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, bottomNavigationBarotherwise), Koder ID sign-in viaKoderApp. Storage routes throughKruzeStore→SharedPreferencesStore→ browserlocalStorage.flutter build web --release~34s, 4 widget tests. Vhost onkruze.koder.dev/companionisinfra/net/jet#154. Cross- device sync depends on the as-yet-unbuilt cross-cutting sync SDK — companion is local-to-tab until then. - AuthProvider —
_authswitched fromlate finalto nullable sowidget 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 —
onDownloadStartRequestwired withuseOnDownloadStart: truein the InAppWebView settings. The new pure helperhandleDownloadRequestlaunches the URL viaurl_launcherinLaunchMode.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'sstack. 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. Twonew
.well-known/handlers (apple-app-site-associationfor iOS Universal Links,assetlinks.jsonfor Android App Links) live atid.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 toapplication/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.