Application A1 (03: Architecture): a
Tauri shell over kult-ffi's embedded node runtime,
the exact library surface the mobile shells consume, dogfooded on the
desktop. The shell adds no protocol logic: delivery states, errors, and
security indicators are the node's own, verbatim.
- Reduce screen-capture and recent-preview exposure before unlock. The
window requests Tauri native content protection, an opaque shield covers the
webview on focus loss, and
Ctrl/Cmd+Shift+Limmediately runs the complete lock path. Capture protection remains honestly best effort because desktop OS, window-server, compositor, privileged-software, and external-camera behavior cannot be controlled universally. - Reduce input retention on every inventoried editable text control. Those controls are semantically classified and receive disabled autocomplete, autocorrect, autocapitalization, and spellcheck at startup and after modal cloning. Passphrases and recovery mnemonics are password inputs. The unlock screen states honestly that the webview, OS, input method, or writing tools may ignore hints.
- Create / unlock / restore an encrypted store at the gate; restoring
current root-free
KKR10or compatible root-freeKKR8/KKR9takes the backup and its phrase plus the separately held authority and phrase. A visibly separate legacyKKR1–KKR7path prepares a fresh address, requires identity-change confirmation, and imports only the former-identity local archive. - Make first contact with the ordinary
kc2Connect QR/code. It uses a rotatable capability while thekk1account fingerprint and safety number stay stable. The share panel exposes explicit rotation and legacy mailbox-only retirement with warnings; existing relationships receive updates over authenticated sessions. - Pair out-of-band: share your post-quantum prekey bundle as a short
animated sequence of versioned Base45 QR frames or as pasteable hex
(interoperable with
kult bundle/kult add). Komms scanners assemble the bounded frames in any order; legacy one-code Base45 and hex QRs remain accepted. New DHT lookup uses the Connect code; a legacy kult address is accepted only through the visible Alpha compatibility path. - Link and manage owned devices without a cloud account. The keyboard and screen-reader-accessible manager lists exact physical devices, supports signed rename and permanently confirmed revoke, and drives both sides of the time-bounded QR/paste ceremony with matching comparison codes and selective transfer. Explicit encrypted sync export/import carries only the C2 allowlist; per-device cryptography and delivery state remain independent.
- Rename a contact's private local petname from the active chat. The shell
targets the exact peer key, previews shared NFC normalization and duplicate/
confusable/bidi/invisible warnings, and requires explicit confirmation before
accepting a warned name. Duplicate names remain separate; rename survives
restart/
KKR10and creates no network, notification, queue, or transport work. - Message with honest delivery states:
queued→sent(handed to a link) →delivered(end-to-end encrypted receipt came back). Sealed ciphertext retries passively after recent failures so fresh taps remain responsive; after 30 days without a receipt, history saysdelivery failed after 30 days. Airtime-budgeted mesh links also expose the "held, will send when a faster link exists" verdict. - Make Beta live-audio calls to paired contacts only while a fresh direct QUIC route is observed. The accessible call bar provides ring, answer, decline, cancel, and hangup state plus an explicit direct-QUIC/no-history explanation. Capture and playback use bounded 48 kHz mono 20 ms Opus packets; hiding or locking Komms tears the call down and clears media state. TCP, relay-only, mailbox, sneakernet, and mesh routes never enable or queue a call.
- Manage signed group authority with visible owner/admin/member roles, capability-gated legacy upgrade, owner/admin rename and membership controls, owner-only role grants and ownership transfer, and signed poll moderation. The members dialog shows generation and signed/legacy state, prevents the owner from leaving, and reports terminal admin-request results without parsing protocol bytes in the webview.
- Send disappearing pairwise/group text and view-once attachments through explicit lifetime selectors. History shows the device-local deadline. View-once rows never preview, autoplay, open, or export through ordinary actions; Reveal once uses the terminal protected-output path and refreshes the row after consumption. Copy states that recipients/other devices may retain copies and never promises screenshot prevention or remote erasure.
- Edit authored canonical Text in pairwise and group history through an incognito modal. Edit is offered only on exact outbound text, uses the shared capability/authorship checks, refreshes on typed target events, shows an edited revision marker, and exposes the original plus every valid version in an accessible disclosure. Editing never erases a prior version.
- Render safe source formatting in pairwise, group, note-to-self, and scheduled bubbles through the shared bounded formatter. The webview creates only fixed inert DOM/text nodes, composes mention highlighting, and copies the readable plain-text projection; message source can never create HTML, links, images, URL navigation, or fetches.
- Schedule pairwise or group text in local time: sealed scheduled rows remain visibly separate from ordinary history and can be edited or cancelled until the core activates them at the stored absolute UTC instant.
- Send and receive pairwise or group attachments through native path pickers with consent, exact progress, lifecycle controls, and protected export. Generic files show a fresh F4 carrier explanation and explicit send/discard. JPEG/PNG selections enter the shared bounded Rust editor for orientation normalization, free/preset crop, 90-degree rotation, and user-positioned blur or pixelation; the keyboard/screen-reader-accessible dialog reviews the exact final PNG re-encoded without source metadata, and only that asset enters F3. Protected originals and intermediates are cleared on send, discard, failure, hide/lock, shutdown, and restart. Completed edited images render only through validated protected transients. Transfers continue while Komms is open or minimized and resume from verified progress after restart.
- Record pairwise or group audio messages only while Komms is visible, stop into a no-autoplay review with duration/waveform and the current F4 carrier explanation, then explicitly send or discard. The shell rewrites every clip to the shared source-metadata-omitting mono 16-bit PCM WAV / 16 kHz / 60-second profile before the existing F3 import. Hiding, locking, interruption, failure, or shutdown stops capture and clears review/plaintext transients; received audio is validated and materialized only for explicit protected local playback.
- Use sender-key groups: create and list groups, read history, send, add/remove members, and leave. Outbound bubbles show a separate honest delivery state for every recipient, so partial delivery stays visible. A visible security banner blocks new content while current devices exchange recipient-specific origin capabilities, then identifies new rows as recipient-authenticated and keeps released legacy history accurately labelled.
- Create and vote in encrypted group polls using dedicated accessible cards rather than chat bubbles. The current roster is fixed at creation, votes and voter identities are visible to members (not anonymous), choices can change before closure, and only the creator can freeze the final visible snapshot. Exact Unicode and protocol byte limits are preserved.
- Mention current group members through an explicit roster picker with Arrow/Enter/Escape keyboard operation, screen-reader announcements, duplicate- petname disambiguation, and non-color-only highlighted history. Mention tokens remain ordinary readable text for selection, copy, and search. Send rechecks the exact roster and authenticated capabilities; when semantic Mention is not safe, an explicit confirmation can send the exact text without semantics or a notification.
- Manage private local conversation folders for pairwise contacts, groups, and note-to-self. All and Unfiled navigation, exact duplicate-capable Unicode names, durable keyboard reorder, explicit single-folder moves, deletion review, stale cleanup, and folder-first composition with label filters remain sealed local presentation and create no delivery or transport work.
- Manage private contact and conversation labels for pairwise contacts,
groups, and note-to-self. The accessible manager supports exact Unicode names,
duplicate-name disambiguation by translated color name plus stable order,
keyboard create/edit/cancel/confirm/delete review, per-conversation assignment,
non-color badges, stale-record cleanup, and match-any/match-all navigation
filters. Limits are 128 definitions, 8,192 assignments, 32 labels per
conversation, and 256 UTF-8 bytes per name; colors persist only as
neutral,red,orange,yellow,green,teal,blue,purple, orpink. - Pin private local conversations across pairwise contacts, groups, and
note-to-self in one leading accessible block. Keyboard buttons provide exact
complete-set reorder and unpin; unavailable records remain visible for exact
cleanup. Folder selection and label filtering run before pin/activity order.
The 8,192-pin bound, stable typed identity, restart/
KKR10restoration, and zero-network behavior come from the shared core rather than display names. - Choose System, Light, or Dark appearance at the gate or in the unlocked
app. A non-sensitive local cache applies before first paint; after unlock the
sealed F5
appearance.themevalue is authoritative and travels inKKR10. System follows live OS changes, semantic CSS roles meet the shared contrast targets,prefers-contrastandprefers-reduced-motionremain native, and delivery/security meaning always retains text, glyph, or accessible labels. - Manage private custom icons for contacts, groups, folders, and note-to-self.
Every row renders the sealed icon or generated initials; the accessible manager
offers eight bundled glyphs, local JPEG/PNG selection with centered-square crop,
clear-to-fallback, and quota usage. The shared core emits only 256×256 RGBA
PNGs re-encoded without source metadata, enforces
512 KiB/1,024-record/64 MiB limits, and safely falls
back after corrupt bytes. Icons travel only in
KKR10or authenticated own-device C2 sync, never URLs, peer sync, envelopes, capabilities, queues, notifications, or transports. - Verify contacts by safety number: identical digits and QR on both ends, compared out-of-band, with a visible verified badge.
- Transport indicators: NAT verdict, LAN peers discovered over mDNS, scheduled, queued, and bridged-in-transit counts, live listen addresses.
- Backup to a single encrypted file; the sealing mnemonic is shown exactly once and stored nowhere.
- Network settings (listen addresses, bootstrap peers, relays,
mailboxes, sneakernet spool, Meshtastic radio, bridging) persist as
settings.jsonin the data directory: the same knobs askultd's flags, and no secrets.
apps/desktop/
├── ui/ # dependency-free HTML/CSS/JS, no bundler, no npm
└── src-tauri/
├── src/session.rs # everything the app can do, webview-agnostic (tested)
├── src/commands.rs # Tauri IPC: one-line async wrappers, spawn_blocking
├── src/qr.rs # SVG QR rendering (bundles, addresses, safety numbers)
└── tests/desktop_e2e.rs# two app backends: pair, message, verify, backup/restore
This is deliberately its own cargo workspace: the Tauri/GTK dependency tree
stays out of the core crates' lockfile and cargo-deny surface (the app has
its own deny.toml, same posture). The core is reached only through the
path dependency on kult-ffi.
Custom-icon acceptance consumes the shared B13 fixture through the same session
surface the Tauri commands wrap: canonical local data URLs whose PNG omits
source metadata, exact
folder/note targets, bundled and selected-image paths, quota accounting,
restart/KKR10, safe fallback, local events, and zero delivery work. Rust node
acceptance independently covers contact and group identities plus corrupt sealed
legacy bytes.
The public 0.4.2 Beta is an explicitly unsigned, pre-production test release.
Download the package for your disposable test system from the
v0.4.2 release page:
- Windows 10/11 x64: MSI or NSIS setup EXE;
- macOS Intel or Apple silicon: universal DMG (or app archive); and
- Linux x86-64: AppImage, DEB, or RPM.
The Windows installers are unsigned, the macOS DMG is unsigned and not
notarized, and the Linux packages are unsigned. Verify the exact package
against UNSIGNED-TEST-SHA256SUMS before accepting an operating-system
warning. Follow the
Beta testing guide for migration,
installation, and acceptance steps. The
0.4.2 release record binds the
public files to the green validation run and lists the production/stable gates
that remain open.
Linux needs the WebKitGTK stack (Debian/Ubuntu):
sudo apt-get install libwebkit2gtk-4.1-dev libgtk-3-dev \
libayatana-appindicator3-dev librsvg2-devThen, from apps/desktop/src-tauri:
cargo run # debug build, launches the app
cargo test # unit + two-node end-to-end tests (no webview needed)
cargo run --features meshtastic # with USB Meshtastic radio supportInstallable bundles need the Tauri CLI once: cargo install tauri-cli --locked, then cargo tauri build from this directory. The configured
targets cover every desktop platform (.deb, .rpm, AppImage, .app,
.dmg, .msi, NSIS); Tauri builds only the targets native to the host OS
and skips the rest.
The historical v0.3.0 prerelease was built in those formats on native Linux,
macOS, and Windows runners with checksums. It predates the current evidence
design. The v0.4.2 tag push created read-only validation artifacts, public
builder records, a second controlled Linux measurement, an SBOM, and hosted
attestations without accessing a signing credential. The exact files were then
published under an explicit unsigned test-only exception. Follow the
release runbook; a successful build alone
is not a production-signing or stable-qualification claim, and the 0.4.2
exception is not reusable for another version.
The package identifier is is.andri.komms and the current version is 0.4.2,
aligned with the Rust, Android, and iOS surfaces.
The public 0.4.2 test packages and historical 0.3 Alpha desktop packages are not release-signed or notarized: macOS and Windows are unsigned, and the Linux package artifacts have no release-manifest signature. No production certificate or key enters the tree. Local Tauri packaging can read credentials from the environment when a maintainer deliberately exercises a test identity:
- macOS:
APPLE_CERTIFICATE/APPLE_CERTIFICATE_PASSWORD(base64 Developer ID .p12) orAPPLE_SIGNING_IDENTITY, plusAPPLE_ID/APPLE_PASSWORD/APPLE_TEAM_IDfor notarization. - Windows: Authenticode signing via
bundle.windows.certificateThumbprintor an externalsignCommandintauri.conf.json(e.g. Azure Trusted Signing) — configure only when a certificate exists. - Linux:
.deb/.rpm/AppImage are distributed unsigned for now; repository-level signing (apt/rpm repo, AppImage GPG-embed) is part of the M6 distribution work.
The icon set in icons/ is generated from icons/icon.png with
cargo tauri icon icons/icon.png (or npx @tauri-apps/cli icon). The
current source is 512×512; regenerate from a 1024×1024 master when one
exists — macOS upscales the 512 source for its largest slot.
Production use requires the separate macOS, Windows, Linux-manifest, and release-manifest roles in release security and recovery. The hardware-backed Windows provider and Apple notarization role are not enrolled. Named-system signed install, upgrade, failed-upgrade recovery, rollback, and compatibility rows remain open.
An in-app updater is intentionally absent. Direct desktop distribution uses the bounded manual signature-and-digest procedure until a safer authenticated channel is implemented and qualified; store or package-manager channels may be added only with separately scoped signing and rollback evidence.
- The webview is locked down: strict CSP, no Tauri plugins, no filesystem /
shell / network capabilities: the frontend reaches the world only
through the bounded command surface in
commands.rs. - The store passphrase exists in the webview only inside the unlock form and crosses IPC once per unlock; it is never persisted by the shell.
- QR codes render black-on-white on their own card regardless of theme; phone cameras need the contrast.
- The pre-unlock theme cache contains only
system,light, ordark; it is not the backup/source of truth and is reconciled with the sealed record after unlock or restore. - Mention target ids, ranges, and text stay inside the encrypted content body. Desktop notification handling receives only an endpoint-local render-safe signal; it does not promise server push or online delivery.
- Ephemeral exact deadlines, lifecycle state, deletion, and tombstones live in the shared core. The webview receives only typed expiry/terminal events and cannot bypass view-once through its ordinary preview/export/audio actions. KKR6 excludes live ephemeral plaintext/media and includes terminal tombstones. See C4 semantics and qualification.
- Call control and media are transient shared-core state. The webview receives only render-safe status and bounded authenticated Opus packets; it never sees ratchet or call keys. Calls create no history, backup, C2 sync, mailbox, or mesh work. See C7 semantics and qualification.
- Folder, pin, and label ids, names, order, membership, filters/selections, and stale
diagnostics stay in the existing sealed local store or process-local UI
state. They never enter envelopes, DHT records, capabilities, analytics,
notifications, or logs; navigation/filtering changes presentation only.
Custom icons are likewise exact typed sealed local records, rendered only from
verified bounded data URLs.
KKR10preserves them exactly and C2 can converge them only between authorized owned devices; message pins and message labels are not implemented.