Koder App Behaviors
koder-app specs/koder-app/behaviors.kmd
Comportamentos obrigatórios para todo app Koder (qualquer linguagem/ plataforma/canal): auth (Koder ID), branding, telemetria, auto-update, IPC, error reporting, i18n. Apps não-conformes não podem usar marca Koder, listar na Store ou integrar ao ecossistema. SDKs (koder_kit, engines/sdk/go, etc.) implementam o "how"; este spec é o "what".
Quando esta spec se aplica
Triggers primários
- Criar qualquer novo app Koder ou binding de SDK
- Implementar auth/telemetria/updates/IPC/branding em qualquer UI Koder
- Implementar login / sign-in / user badge em qualquer app Koder (§1)
- Implementar auto-update, verificação de versão ou tela de atualizações em qualquer app Koder (§4)
- Implementar strings de UI em qualquer app Koder ou adicionar suporte a i18n (§9)
Todos os triggers
- Criar qualquer novo app Koder ou binding de SDK
- Implementar auth/telemetria/updates/IPC/branding em qualquer UI Koder
- Verificar conformidade de app Koder com a Stack
- Implementar login / sign-in / user badge em qualquer app Koder (§1)
- Implementar auto-update, verificação de versão ou tela de atualizações em qualquer app Koder (§4)
- Implementar strings de UI em qualquer app Koder ou adicionar suporte a i18n (§9)
Corpo da especificação
Koder App Behaviors — Spec v0.1
Overview
Every Koder app — regardless of language, platform, or distribution channel — must implement the behaviors defined in this spec. Language/platform SDKs (koder_kit for Flutter, engines/sdk/go, engines/sdk/rust, std.koder.app for Koder Koda, etc.) are the how; this spec is the what.
An app that does not implement all MUST behaviors is not a compliant Koder app and may not use the Koder brand, be listed in the Koder Hub, or integrate with the Koder ecosystem.
1 — Authentication (Koder ID)
1.1 — MUST: authenticate via Koder ID
Every app that has a user-facing UI must support sign-in via Koder ID (OIDC). No proprietary auth system, no separate credentials.
- The app requests the
openid profile emailscopes minimum - The app stores the access token securely (Keychain on iOS/macOS, Keystore on Android, libsecret / Credential Manager on Linux/Windows)
- The app refreshes the token automatically using the refresh token before expiry
1.2 — MUST: propagate auth token via IPC
When another Koder app requests the auth token via the auth_token IPC method, the app must return the current user's access token if the caller is a Koder app (verified by signature).
1.3 — SHOULD: support single sign-on across apps
If another Koder app on the same device is already authenticated, the app should reuse the existing session rather than prompting the user to sign in again. Implementation: call auth_token via KoderIPC to the first available Koder app before opening the sign-in flow.
2 — Telemetry
2.1 — MUST: emit structured logs
All log output must be structured (JSON) and sent to the Koder observability stack via the SDK (Go: client.Log, Dart: KoderTelemetry, etc.). Plain print/console.log to stdout is acceptable only during development.
Log levels: debug, info, warn, error, fatal.
2.2 — MUST: trace user-visible operations
Every operation that is user-visible and takes >100ms must be wrapped in a trace span. Examples: app startup, file open, network request, IPC call.
2.3 — SHOULD: emit business metrics
Domain-specific metrics (e.g., files opened, messages sent, playback sessions started) should be sent as gauge/counter metrics. This feeds billing and product analytics.
2.4 — MUST NOT: log PII
Logs and traces must not contain personal data: names, emails, phone numbers, document numbers, file contents, message bodies. Use opaque IDs instead.
3 — Error Handling
3.1 — MUST: comply with error message spec
Every error shown to a user must comply with specs/errors/user-facing-messages.kmd:
- Humanized text in pt-BR (or en-US for international builds)
- "Ver detalhes" / "See details" expandable section with the raw technical error
- Unique error ID in format
<PRODUCT>-<CAT>-<CODE>-<SEQ>for support correlation
3.2 — MUST: never show raw stack traces to users
Stack traces, internal file paths, and database error messages must be hidden behind the "Ver detalhes" toggle. The user-facing message must always be a human sentence.
3.3 — MUST: log all errors
Every caught error must be logged via the telemetry SDK with the error ID, the raw error, and the context (screen, operation, user ID hash).
4 — Updates
4.1 — MUST: expose an "Automatic updates" toggle in Settings
Every Koder app that has a user-facing Settings screen must expose an "Automatic updates" / "Atualizações automáticas" toggle. This applies to all UI types: Flutter mobile, Flutter desktop, TV apps (JS/React), and web apps with a persistent settings surface.
Default ON: the toggle must be active by default on every fresh install.
The implementation must treat the absence of a stored preference as true
(enabled) — the key is only written when the user explicitly toggles it off:
// Dart / Flutter
final prefs = await SharedPreferences.getInstance();
final enabled = prefs.getBool('auto_update') ?? true; // absent == on
// Web / TV (JS)
const enabled = localStorage.getItem('auto_update') !== 'false'; // absent == on
The toggle lives in Settings under a "General" or top-level "Updates" group.
Label and placement must follow specs/koder-app/behaviors.kmd §9 (i18n:
en-US default + follow device locale when implemented).
4.2 — MUST: check for updates on startup when auto-update is enabled
When auto-update is enabled (or absent, per §4.1), the app must query the
Koder Hub update endpoint on each launch, throttled to at most once per 24 h
using a stored last_update_check timestamp.
Endpoint: GET https://hub.koder.dev/api/v1/apps/<slug>/latest
Response:
{ "version": "1.5.0", "min_supported": "1.2.0", "changelog_url": "..." }
When auto-update is explicitly disabled by the user, skip the check entirely — do not even make the network request.
4.3 — MUST: prompt for mandatory updates (regardless of toggle)
If the running version is below min_supported, the app must block usage
and show an update prompt. The user may not dismiss this prompt. This rule is
not gated on the auto-update toggle — mandatory updates always apply.
4.4 — MUST: download and apply optional updates automatically when enabled
When auto-update is enabled and a newer non-mandatory version is available:
- Download silently in the background (use
dio+CancelTokenon Flutter;fetch+AbortControlleron web/TV). - Verify checksum before applying (SHA-256 from the Store API response).
- Prompt for confirmation — trigger the platform installer with the
downloaded artifact; the OS enforces explicit user consent (e.g. Android
PackageInstaller, macOS Gatekeeper, Linuxdpkg). Never apply silently. - Show subtle progress in Settings while the download is in progress ("Downloading update…" / "Baixando atualização…").
- Cancel on toggle-off — if the user disables the toggle while a download
is in progress, cancel it via the
CancelToken/AbortController.
When auto-update is disabled, only show a dismissible banner (§4.5) — no background download.
4.5 — SHOULD: show optional update banner when auto-update is disabled
When auto-update is disabled and a newer version is available (checked only on manual "Check for updates" action in Settings), show a dismissible banner or in-app notification with a link to the Koder Hub page for the app.
4.6 — SDK-first check for update logic
Before implementing update logic locally, check engines/sdk/koder_kit for a
KoderUpdater widget/service that exposes an enabled parameter. If the SDK
covers the pattern, wire through it. If enabled is missing, extend the SDK
rather than duplicating the logic in the app.
4.7 — Deterministic audit checks
/k-housekeep audit verifies per app:
- Settings screen contains a widget/key referencing
auto_updatepreference. prefs.getBool('auto_update') ?? true(or equivalent absent-means-on pattern) is the sole read point — no hard-codedfalsedefault.- Update check is gated on the preference value before the network call.
- Mandatory-update path (
min_supported) is NOT gated on the preference.
5 — Deep Linking
5.1 — MUST: register the koder-<slug>:// URL scheme
Every app must register its URL scheme on all platforms it targets:
- Android:
<intent-filter>in AndroidManifest.xml - iOS:
CFBundleURLSchemesin Info.plist - Desktop:
.desktopfile URI handler (Linux),LSApplicationQueriesSchemes(macOS), registry key (Windows)
5.2 — MUST: handle the open deep link
koder-<slug>://open?uri=<encoded-uri> must open the specified resource in the app. Unrecognized URIs return error -32601.
5.3 — SHOULD: handle inter-app deep links
Apps should be able to produce deep links to other Koder apps. Example: Drive producing koder-dek://open?uri=<audio-uri> to open a file in Dek.
6 — IPC
6.1 — MUST: implement the KoderIPC protocol
Every app must implement the KoderIPC protocol as specified in specs/ipc/protocol.kmd:
- Start an IPC server at the platform-appropriate transport address on launch
- Respond to
capabilitiesandping - Stop the server on clean shutdown
6.2 — MUST: declare capabilities at startup
The app must publish its capability list immediately when a client calls capabilities. The list must be static (not change at runtime without restarting the IPC server).
6.3 — MUST NOT: accept undeclared methods
Any method not in the declared capability list must return error -32601.
7 — Branding
7.1 — MUST: use the Koder design system
Apps must use the Koder color tokens, typography, and spacing system as defined in the brand assets. No custom primary colors or fonts without explicit design review.
7.2 — MUST: support light and dark themes
All Koder UIs — web apps, landing pages, Flutter mobile, Flutter desktop, TV apps — must comply
with specs/themes/light-dark.kmd in full. Key requirements:
- First launch / no saved preference: open in the theme that matches the OS setting. Never hard-code dark or light as a fixed default.
- User choice persistence: save to
localStorage(web) orSharedPreferences(Flutter) under key"theme"("light"/"dark"). Saved choice overrides OS preference on subsequent launches/visits. - OS preference propagation: when no preference is saved, follow live OS changes
(
matchMediaon web,WidgetsBindingObserver.didChangePlatformBrightnesson Flutter). - Anti-flash: apply the theme synchronously before the first render (inline
<head>script on web; read preference inmain()beforerunApp()on Flutter).
SDK: KoderTheme widget from engines/sdk/koder_kit (planned v0.6.0); engines/sdk/koder_web_kit for web.
Full implementation patterns in specs/themes/light-dark.kmd.
7.3 — MUST: display product name in title bar
Per specs/desktop-apps/title-bar.kmd: desktop apps display the product name (not "Koder") in the window title bar.
8 — Identifiers
8.1 — MUST: use the canonical slug
Every app has a canonical slug (e.g., dek, drive, kmail, pass). This slug is used:
- As the IPC address: socket/pipe name, D-Bus name (
dev.koder.<slug>) - As the deep link scheme:
koder-<slug>:// - As the binary name:
k<slug>(perspecs/binaries-and-cli/naming.kmd) - As the Store ID and telemetry
servicefield
9 — Localisation (i18n)
9.1 — Default language is en-US
All Koder apps ship with English (en-US) as the default and baseline language. All source
strings are written in en-US. See policies/language.kmd for full policy.
9.2 — MUST: follow device/browser locale when i18n is implemented
Once multi-language support is formally added to a product, the displayed language must follow the device or browser locale automatically — never require the user to configure it manually on first launch.
- Flutter: use
flutter_localizations+intl;MaterialApp(localizationsDelegates: ..., supportedLocales: ...)resolves the locale from the OS automatically. - Web (app/landing): use
navigator.language(browser) orAccept-Languageheader (server-rendered) as the initial locale. - TV (JS/React): same as Web —
navigator.language. - Fallback: always fall back to en-US when the device locale has no translation.
9.3 — MUST: use the SDK localisation helper
Use KoderL10n from engines/sdk/koder_kit (Flutter, shipped v0.16.0+),
KoderL10n from engines/sdk/koder_web_kit (JS/Web, shipped v0.3.0+), or
the per-surface equivalent (engines/sdk/go/l10n for Go services / CLIs).
Centralise all user-visible strings in the canonical files per surface
(ARB for Flutter, JSON for Web/TV, Go map literals for server / CLI / TUI).
Inline string literals in widget / template code are forbidden — see
T1 in specs/i18n/contract.kmd.
9.4 — MUST NOT: mix locale-selection and locale-display concerns
The locale selector lives in Settings, not in the onboarding flow. On first
launch, the app silently follows the device locale — no locale-picker
dialog is shown. The canonical UI for the selector is KoderLanguagePicker
(Flutter) / <koder-language-picker> (Web) — see
specs/i18n/contract.kmd §R3 for per-surface placement (Settings tile,
landing-page footer, CLI flag, TUI shortcut, etc.).
Cross-reference:
specs/i18n/contract.kmdis the canonical cross-surface i18n spec — covers persistence (R2), switcher position (R3), key naming (R6), supported locales (R7), per-surface string-file paths (R8), and the TDD test contract (T1-T6). This §9 is intentionally a summary; new behaviour or per-surface details land inspecs/i18n/.
File: meta/docs/stack/specs/koder-app/behaviors.kmd
Trigger: read this spec before creating any new Koder app or SDK, or before auditing an existing app for ecosystem compliance.
CLAUDE.md trigger entry to add:
| Criar qualquer novo app Koder ou binding SDK | specs/koder-app/behaviors.kmd |
Referências
engines/sdk/koder_kitpolicies/sdk-first.kmdpolicies/language.kmdspecs/errors/reporting.kmd