Binary, CLI and Desktop App Naming
Nomenclatura canônica para executáveis: binário k<slug>, dir /opt/koder/<slug>/, D-Bus ID dev.koder.<slug>, symlink em /usr/local/bin/, .desktop file, aliases de compatibilidade. Cobre Flutter desktop, CLIs, multi-binary tooling, packaging .deb/.rpm/.kpkg. Android applicationId §11: dev.koder.<short_slug>, source-of-truth em koder.toml [android] application_id, exposto via catálogo da Store — clients NUNCA derivam por heurística.
Spec: Binary, CLI and Desktop App Naming
Apply this spec when:
- Creating or renaming a Flutter desktop app binary
- Creating or renaming a Koder CLI tool (single binary, no GUI)
- Building a multi
binary tooling family (e.g., `dev/kodertools`) - Packaging a product as a
.deb,.rpm,.AppImage, or.kpkg - Setting the D-Bus application ID for a Linux desktop app
- Creating a
.desktopfile or systemd service unit for a Koder product - Deciding the CLI command name a user types to launch a product
1. Core rule: binary = aliases[0] || canonical slug
*pdated 2026
0511*to consumemeta/docs/stack/registries/component-names.mdas the source of truth, perspecs/naming/forms.kmd. The previous rule ("slug = binary = install") used a compact slug (kterm); the new model separates the *anonical slug*(koder-term, kebab-case, registered) from the *inary name*(kterm, taken fromaliases[0]of the registry entry, if present). Existing binaries keep their current names — no migration required.
Every Koder product or CLI has a row in meta/docs/stack/registries/component-names.md with these forms:
slug— canonical kebabcase identifier (e.g. `koderterm`)aliases— optional compact forms (e.g.[kterm])
The *inary name*and *pkg install argument*derive as:
binary_name = aliases[0] || slug
install_arg = binary_name (identical)Worked examples:
| Component | Registry slug | aliases[0] | Binary name | Install command |
|---|---|---|---|---|
| Koder Term | koder-term |
kterm |
kterm |
kpkg install kterm |
| Koder Hub | koder-hub |
khub |
khub |
kpkg install khub |
| Koder Koda | koda |
— | koda |
kpkg install koda |
| Koder Tools | koder-tools |
ktools |
ktools |
kpkg install ktools |
| Koder Kdedup | kdedup |
— | kdedup |
kpkg install kdedup |
The binary name is *ever transformed*at packaging time — what the registry says is what ships. New products choose their registry row at creation (see specs/naming/forms.kmd §2 Rules); everything else derives.
Slug naming convention (deprecated in favor of registry)
The previous convention "start the slug with k" is superseded. New products register a canonical kebab slug per specs/naming/forms.kmd R4 (with or without koder- prefix, per type and bare initial) and add a k-prefixed alias only when justified by policies/naming-aliases.kmd. The k-prefix appears in the binary via aliases[0], not in the slug.
1.0 Display name parity rule
The slug is also the source of truth for the *isplay name*— the human-readable label that appears on the launcher tile, the OS window title, the Settings menu entry, the README H1, and the Hub package listing. Mechanical rule:
DisplayName = TitleCase(slug)Worked examples:
| Slug | DisplayName |
|---|---|
kruze |
Kruze |
kterm |
KTerm |
kmail |
KMail |
kdek |
KDek |
dek |
Dek |
mosaic |
Mosaic |
hub |
Hub |
kode |
Kode |
koder-tools |
Koder Tools |
The "Koder " prefix that used to live in launcher tiles ("Koder Term", "Koder Mail") moves to *Comment=** of the .desktop` file and to marketing/long-form copy. The launcher tile shows the short DisplayName; GNOME / KDE search still match "koder" via Comment + Keywords (§5).
Rationale:
- One source of truth — rename the folder, rename the slug, the brand
follows automatically.
- Removes the brand-family redundancy when the user already sees a
cluster of K-prefixed icons in their launcher.
- New products only choose the slug; everything else derives.
Override (rare)
A product whose marketing brand is intentionally not TitleCase(slug) (B2B partner brand, whitelabel, legalmandated naming) sets the override in its koder.toml:
[package]
slug = "raven"
display_name = "Raven Mail" # default would be "Raven"kicon validate-metadata reads this field and uses it for Name= in the generated .desktop file. The override must be documented in the product's README (one-liner explaining why it diverges) and is the only place the override may live — never inline-edited in build scripts or .desktop files.
1.1 Flutter desktop apps (full GUI products)
These follow §2–§7 in full: D-Bus ID, .desktop file, /opt/koder/<slug>/ install layout, optional koder-<slug>.service for background daemons.
| Product | Monorepo path | Slug | Binary / CLI command |
|---|---|---|---|
| Koder Hub | products/dev/hub/ |
khub |
khub |
| Koder Mail | products/horizontal/kmail/ |
kmail |
kmail |
| Koder Jet | infra/jet/ |
kjet |
kjet |
| Koder Drive | products/horizontal/drive/ |
kdrive |
kdrive |
| Koder Dek | products/horizontal/dek/ |
kdek |
kdek |
| Koder Term | products/dev/kterm/ |
kterm |
kterm |
1.2 Pure CLI tools (no GUI)
These follow §9 — single binary in /usr/local/bin/<slug>, no D-Bus, no .desktop file, no /opt/koder/<slug>/ bundle.
| CLI | Monorepo path | Slug | Binary | Install |
|---|---|---|---|---|
| Koder Icon | products/dev/kicon/ |
kicon |
kicon |
kpkg install kicon |
| Koder Dedup | dev/kdedup/ |
kdedup |
kdedup |
kpkg install kdedup |
| Koder Shell | linux/shell/ |
kosh |
kosh |
kpkg install kosh |
1.3 Multi-binary tooling families
Umbrella modules that ship several related binaries together follow §10 — prefix koder-<verb> for each binary, single kpkg install for the family.
| Family | Monorepo path | Binaries | Install |
|---|---|---|---|
| Koder Tools | dev/koder-tools/ |
koder-lock, koder-stackdoc, koder-pathspec-commit, koder-backlog-grep, koder-hub-check |
kpkg install koder-tools |
2. Flutter Linux — CMakeLists.txt
# linux/CMakeLists.txt
set(BINARY_NAME "khub") # ← equals the slug, not the Dart package nameThis makes the build output build/linux/x64/release/bundle/khub.
The Dart package name in pubspec.yaml (name: koder_hub) is irrelevant to the binary name; Flutter uses BINARY_NAME for the native executable only.
3. Installation layout
*pdated 2026
0511*<binary>below is the registry-derivedaliases[0] || slug(per §1).<slug>(kebab canonical) is only used in path segments inside/opt/koder/, mirroring the registry slug.
/opt/koder/<binary>/ ← product bundle root (binary name)
<binary> ← main executable (name = aliases[0] || slug)
lib/ ← shared libraries (.so)
data/ ← Flutter assets, fonts, ICU
/usr/local/bin/<binary> ← symlink → /opt/koder/<binary>/<binary>The symlink in /usr/local/bin/ is the user-facing CLI command.
*egacy cleanup:*if a previous version installed under /opt/koder-<binary>/, the .deb prerm script must remove that directory on upgrade:
# DEBIAN/prerm
#!/bin/sh
rm -rf /opt/koder-<binary> 2>/dev/null || true4. D-Bus application ID
dev.koder.<slug>Examples: dev.koder.khub, dev.koder.kmail, dev.koder.kjet, dev.koder.kterm
Set in the GTK application registration inside linux/my_application.cc:
gtk_application_new("dev.koder.hub", G_APPLICATION_DEFAULT_FLAGS)This value also becomes the *Lib application ID*and the *esktop file name*(see §5). It must match exactly across all three places.
5. Desktop file
*ilename:*dev.koder.<slug>.desktop *nstall path:*/usr/share/applications/dev.koder.<slug>.desktop
Minimum required fields:
[Desktop Entry]
Name=KHub
GenericName=App Hub
Comment=Koder Hub — universal app store for the Koder ecosystem
Keywords=koder;hub;apps;store;packages;
Exec=/opt/koder/khub/khub %u
Icon=dev.koder.khub
Terminal=false
Type=Application
Categories=Utility;Network;
MimeType=x-scheme-handler/koderhub;
StartupWMClass=khubNameisTitleCase(slug)per §1.0 (display-name parity rule). Theoverride in
koder.toml [package].display_namewins when present.GenericNameis the function in 2–3 words ("App Hub", "Web Browser","Audio Recorder"). Optional but recommended for KDE/GNOME accessibility.
Commentcarries the longform `"Koder DisplayName — <oneliner>"`so launcher search keeps matching "koder" without showing redundant text on the tile.
Keywordsalways includeskoder;<slug>;followed by 2–4 functionalterms, semicolon-terminated.
Iconuses the reverse-domain ID so icon themes can scope icons per product.StartupWMClassmust match the binary name so the taskbar groups windows correctly.%upasses a URL argument (for deeplink / URIscheme handling).
*con install path:*
/usr/share/icons/hicolor/512x512/apps/dev.koder.<slug>.png6. Systemd user service (daemons and background agents)
Products that run background agents (e.g., update checker, sync daemon) use:
koder-<slug>.service ← unit file name
koder-<slug> ← ExecStart binaryThe koder- prefix disambiguates Koder services from OS system services and third-party packages that may also use short names.
7. Compatibility aliases (one-version grace period)
When renaming an existing binary (e.g., koder-hub → khub), the .deb *ust*ship a compatibility symlink for exactly one release cycle:
# DEBIAN/postinst — create backward-compat alias
ln -sf /usr/local/bin/khub /usr/local/bin/koder-hubRemove the alias in the *ext*release's prerm:
# DEBIAN/prerm — remove old alias
rm -f /usr/local/bin/koder-hub8. Flutter desktop apps — quick checklist
When packaging a new or renamed Flutter desktop product (covers §2–§7):
- [ ]
linux/CMakeLists.txt→BINARY_NAME "<slug>" - [ ]
linux/CMakeLists.txt→APPLICATION_ID "dev.koder.<slug>" - [ ] Install dir:
/opt/koder/<slug>/ - [ ] Symlink:
/usr/local/bin/<slug>→/opt/koder/<slug>/<slug> - [ ] Desktop file named
dev.koder.<slug>.desktop - [ ] Icon at
/usr/share/icons/hicolor/512x512/apps/dev.koder.<slug>.png - [ ]
StartupWMClass=<slug>in desktop file - [ ]
kpkg.tomlwith[platforms],[install], and[install.desktop](includingstartup_wm_classandcategories) - [ ] Compatibility alias if renaming (
/usr/local/bin/<old-name>for one release) - [ ]
prermcleans/opt/koder-<slug>/if upgrading from legacy layout
8.1 Installer responsibility
*he installers (khub and kpkg) are responsible for creating all desktop integration artifacts*— .desktop file, icon, and /usr/local/bin/ symlink — on behalf of the package.
The source of truth for all installation metadata is the *kpkg.toml` embedded in the bundle* not the Koder Hub API. This means:
kpkg install <file.kpkg>readskpkg.tomlfrom the ZIP, resolves install paths, creates the.desktopfile, and installs the icon — no API call needed.khub install <slug>downloads the.kpkgfrom the Store, then delegates to the sameinstaller.Install()library path — identical behavior.- Metadata like
StartupWMClassand XDGCategoriescome from[install.desktop]inkpkg.toml, ensuring they are consistent regardless of which tool performs the install.
Apps must *ot*bundle their own installer scripts for desktop integration; the kpkg installer library handles it for all platforms.
9. Pure CLI tools (no GUI)
A *ure CLI tool*is a singlebinary Koder utility with no GUI, no DBus service registration, no .desktop file, and no /opt/koder/<slug>/ install bundle. Examples: kicon, kdedup, kosh. Sections §2 (Flutter CMakeLists), §4 (D-Bus ID), §5 (desktop file), and §7 (compatibility aliases) *o not apply*to CLI tools.
9.1 Identity
The §1 identity rule: slug = binary name = kpkg install argument — all the same string, no transformation.
dev/kdedup/ ← module directory
↓
slug = "kdedup" ← in koder.toml
↓
binary = "kdedup" ← in koder.toml + Go's `go build -o`
↓
kpkg install kdedup ← user-facing install command9.2 koder.toml
A pure CLI's koder.toml declares slug and binary as identical strings:
[app]
slug = "kdedup"
binary = "kdedup"
version = "0.1.0"Both fields must be present and identical. koder-stackdoc check flags divergence as KSTORE-TOML-001.
9.3 Installation layout
A single executable in /usr/local/bin/. No /opt/koder/<slug>/ bundle, no lib/, no data/ — Go-built CLI binaries are statically linked.
/usr/local/bin/<slug> ← the binary itself (not a symlink)If the CLI ships any auxiliary data (config defaults, completion scripts), it goes under XDG paths:
/usr/share/<slug>/ ← read-only data (templates, completions)
~/.config/<slug>/ ← user config
~/.cache/<slug>/ ← user cacheNever under /opt/.
9.4 Distribution
Three channels, in order of preference:
- *kpkg install slug`*— universal Koder Hub distribution (preferred
once the module ships a
kpkg.toml) - *re-built binary*—
cp dev/<slug>/<slug> /usr/local/bin/for localbuilds during development
- *uild from source*— `cd dev/slug && GOWORK=off go build -o slug
.cmdslug` for contributors
The koder.toml and the README must show all three; the install command in kpkg install is *lways*the slug verbatim — never an alias, never a shorter form.
9.5 Background daemons
If a CLI tool also exposes a long-running daemon mode (e.g., kicon watch), the systemd user service follows §6 (koder-<slug>.service with ExecStart=/usr/local/bin/<slug> daemon).
9.6 Quick checklist
When creating or renaming a pure CLI tool:
- [ ] Module directory =
dev/<slug>/(or appropriate Area), where<slug>starts with
kif appropriate - [ ]
koder.tomlhasslugandbinaryset to the same string - [ ] Go build produces single binary named
<slug>(`go build -o slug.cmdslug`)
- [ ] Binary lands at
/usr/local/bin/<slug>(no/opt/, no symlink chain) - [ ] README install section shows all three channels (
kpkg, pre-built copy,build from source) with the slug verbatim
- [ ] No
.desktopfile, no D-Bus ID, nogtk_application_new - [ ] If the CLI has a daemon mode: §6 systemd unit named
koder-<slug>.service
10. Multi-binary tooling families
A *ooling family*is an umbrella module that ships several related binaries together — they share a release cadence, a CHANGELOG, and a single kpkg install invocation. Example: dev/koder-tools ships koder-lock, koder-stackdoc, koder-pathspec-commit, koder-backlog-grep, koder-hub-check as one bundle.
Use a tooling family when:
- The binaries share a domain (e.g., monorepo housekeeping helpers)
- They are versioned and released together
- Splitting them into separate
dev/<slug>/modules would create fivenear-empty repos with synchronized release cycles
Otherwise, prefer §9 (one CLI = one module).
10.1 Identity
The umbrella module is named *kodertoolsdomain** (or koder for other
families). Each binary inside is named **koder-verb** — a verb describing
what the tool does, prefixed with koder-` to disambiguate from system tools.
dev/koder-tools/ ← umbrella module directory
cmd/koder-lock/main.go → binary: koder-lock
cmd/koder-stackdoc/main.go → binary: koder-stackdoc
cmd/koder-pathspec-commit/main.go → binary: koder-pathspec-commit
cmd/koder-backlog-grep/main.go → binary: koder-backlog-grep
cmd/koder-hub-check/main.go → binary: koder-hub-checkThe umbrella *ever*exposes a binary named just koder-tools — the family is a delivery vehicle, not a launcher. Each binary stands on its own.
10.2 koder.toml
The umbrella koder.toml declares the family slug and lists all binaries shipped:
[app]
slug = "koder-tools"
version = "0.2.0"
[[binaries]]
name = "koder-lock"
path = "cmd/koder-lock"
[[binaries]]
name = "koder-stackdoc"
path = "cmd/koder-stackdoc"
# ... one [[binaries]] block per binarybinary = "..." (singular) is *mitted*at the top level — the family has no single primary binary.
10.3 Installation layout
Same as §9: each binary lands in /usr/local/bin/<binary-name>, all installed by a single kpkg install call:
/usr/local/bin/koder-lock
/usr/local/bin/koder-stackdoc
/usr/local/bin/koder-pathspec-commit
/usr/local/bin/koder-backlog-grep
/usr/local/bin/koder-hub-check10.4 Distribution
kpkg install koder-tools # installs all binaries in the familyGranular install (kpkg install koder-lock for just one binary) is *ot supported*— families ship as a unit. If a binary needs an independent release cadence, promote it to its own §9 module.
10.5 Why koder-<verb> and not k<verb>
Toolingfamily binaries deliberately use the longer `koder prefix instead of
the short k`. Two reasons:
- *isambiguation from products.*
klockcould plausibly be a future Koderproduct (a password manager?);
koder-lockclearly signals "internal Koder Stack tooling, not an end-user app." - *erb
shaped names.*Toolingfamily binaries are verbs (lock,stackdoc,commit,grep,check); product binaries are nouns (store,mail,dek). Thekoder-<verb>form reads naturally as "koder, do X."
Enduserfacing CLI tools (kicon, kdedup, kosh) use §9's short slug form (kicon, kdedup, kosh) because they are user-facing nouns/products in their own right.
10.6 Quick checklist
When creating or extending a tooling family:
- [ ] Umbrella directory named
dev/koder-<domain>/(e.g.,dev/koder-tools/) - [ ] Each binary under
cmd/koder-<verb>/main.go - [ ] Each binary named
koder-<verb>— no shortk<verb>aliases - [ ] Top-level
koder.tomllists all binaries under[[binaries]] - [ ] No top-level
binary = "..."field - [ ] Single CHANGELOG covers all binaries; one version applies to the family
- [ ]
kpkg install koder-<domain>installs all binaries at once
11. Android applicationId
For Koder products with Android apps (Flutter or native Kotlin/Compose), the Android applicationId follows a canonical rule rooted in the same slug used elsewhere in this spec.
11.1 Rule
*pdated 2026
0511* derives from the registry binary name (aliases[0] || slug, per §1), not from a separately-defined "short slug".
applicationId = dev.koder.<binary>where *binary** is the registry-derived binary name (aliases[0] || slug)
with any - replaced by _`:
| Registry slug | aliases[0] | <binary> |
applicationId |
|---|---|---|---|
koder-eye |
keye |
keye |
dev.koder.keye |
koder-kruze |
— | koder-kruze → koder_kruze |
dev.koder.koder_kruze |
koder-pass |
kpass |
kpass |
dev.koder.kpass |
koder-dek |
— | koder-dek → koder_dek |
dev.koder.koder_dek |
koder-mail (kmail) |
kmail |
kmail |
dev.koder.kmail |
koder-hub |
khub |
khub |
dev.koder.khub |
koder-term |
kterm |
kterm |
dev.koder.kterm |
kode |
— | kode |
dev.koder.kode |
For components without an alias, the kebab slug is used directly (with - → _ for Java package naming). The resulting applicationId is also the package name in the manifest (<manifest package="…"> and the namespace in build.gradle.kts).
11.2 Source of truth
The canonical applicationId for each product *ust be declared*in koder.toml, not derived by heuristic. This is the ground truth that the Store catalog, build pipeline, and clients all consume:
# koder.toml
[app]
slug = "koder-eye"
[android]
application_id = "dev.koder.eye"When [android].application_id is absent, the build tooling *ay*fall back to the §11.1 formula — but only at build time, never at runtime in clients. Production catalog rows MUST have the explicit field populated; clients MUST consume it from the catalog API.
11.3 Catalog API contract
The Koder Hub catalog exposes package_name for every Android- distributing app:
GET https://hub.koder.dev/api/v1/apps/koder-eye{
"slug": "koder-eye",
"name": "Koder Eye",
"version": "0.2.2",
"platforms": ["android"],
"package_name": "dev.koder.eye"
}Clients (Koder Hub mobile, third-party update checkers, IDE integrations) *ust*read package_name from the catalog. The Store mobile app's _expectedPkg heuristic in app_detail_screen.dart is an anti-pattern and is being removed in favor of the catalog field (see commit history of products/dev/hub/app/lib/screens/app_detail_screen.dart).
If the API response omits package_name, the client treats the entry as *ot installable*until the catalog row is backfilled — never fall back to a derived guess. A stale install record is preferable to a destructive operation against the wrong OS package.
11.4 Build-time wiring
In a Flutter Android app:
// android/app/build.gradle.kts
android {
namespace = "dev.koder.eye" // §11.1 applicationId
defaultConfig {
applicationId = "dev.koder.eye"
}
}In a native Android (Kotlin/Compose) app, the same fields apply. The AndroidManifest.xml package attribute is implied by namespace for AGP ≥ 8 and need not be set explicitly.
The Kotlin top-level package directories under app/src/main/kotlin/ mirror the applicationId, e.g., app/src/main/kotlin/dev/koder/eye/MainActivity.kt.
11.5 Legacy exceptions (transition state, 20260428)
Four products in production still use non-canonical applicationIds that predate this spec:
| Product | Slug | Current applicationId | Canonical (§11.1) | Migration |
|---|---|---|---|---|
| Koder Hub | koder-hub |
dev.koder.koder_store |
dev.koder.khub |
TODO |
| Koder Mosaic | koder-mosaic |
dev.koder.koder_mosaic |
dev.koder.kmosaic |
TODO |
| Koder Term | kterm |
dev.koder.ticsign |
dev.koder.kterm |
TODO |
| Koder Mail | koder-mail |
dev.koder.kmail |
dev.koder.mail (or canonicalize slug to kmail) |
TODO |
Each migration requires:
- Update
koder.toml[android].application_id - Update
build.gradle.ktsnamespaceandapplicationId - Move Kotlin source under
app/src/main/kotlin/dev/koder/<new>/ - Backfill the catalog DB row's
package_name - Bump version + ship release with *oth*the old and new
applicationIdfor one cycle (Android does not allow renaming anapplicationIdof an installed app — users must reinstall, so the old package is archived in the catalog and the new one becomes the active product) - Open follow-up ticket per product
Until each migration ships, the catalog row's package_name reflects the *urrent*value (e.g., dev.koder.koder_store), so clients continue to work against installed users.
11.6 Quick checklist
When creating a new Android Koder app or auditing an existing one:
- [ ]
koder.tomlhas[android].application_iddeclared and matches §11.1 - [ ]
android/app/build.gradle.ktsnamespaceandapplicationIdmatch - [ ] KotlinJava source rooted at `appsrcmainlangdevkodershort_slug`
- [ ] Catalog API row has
package_namepopulated and matcheskoder.toml - [ ] Client consumers read
package_namefrom API — no client-sideheuristic on
slug → packageName - [ ] If product is on the §11.5 legacy list, follow-up ticket exists
with concrete migration steps
- [ ] App icon resource path:
android/app/src/main/res/mipmap-*/(drawables are per Android resource convention; the spec at
specs/icons/generation-targets.kmdcovers icon generation)