Skip to main content
Two ports keep conversations and credentials apart on purpose.

Quick Start

1

Read and write a chat

Every write is namespaced by construction; a bare string key is unrepresentable.
2

Store an API key

A secret never passes through StoragePort.

StoragePort

Persistence is opaque strings; serialisation lives in core/src/chat/repository.ts, not in the adapter. Namespaces are a closed set: chats, settings, drafts, cache.
Writes are atomic because iOS can kill a suspended app mid-write. A halfway write is a normal occurrence on mobile, not a crash scenario.

SecretsPort

API keys go to the iOS keychain or Android keystore, never to StoragePort. The slot is a closed union — openai, anthropic, google, openrouter, custom — so a bug cannot write an attacker-influenced string into the keychain namespace.
When isHardwareBacked is false, the settings view shows an explicit warning. A silent downgrade is how a user comes to believe a key is protected when it is not.

How Session Persistence Works

A completed turn is recorded through the session, which owns the join between the assistant-only run state and the two-sided stored chat. end.userIndex is produced by whatever actually did the write — null when the write failed. An unreadable chat is skipped rather than crashing the list, and the webview isolates storage to its own origin.
The last-used engine is stored under the engineId key in the settings namespace and honoured on next launch, so the app reopens on the engine the user chose rather than a compiled-in default.

Best Practices

settings.set() refuses a secret-flagged key; setSecret is the only way in, and there is deliberately no getter in the UI facade. Persistence also strips any secret-flagged key from what it writes — plainOnly drops every def marked secret: true before the settings map reaches storage — so a bug that assigns a raw API key to a settings slot cannot end up on disk.
Adapters store opaque strings, so swapping the backing store — Tauri store, SQLite, OPFS — changes no format and loses no data.
Surface isHardwareBacked in settings so users know whether a key is keychain-protected or in memory.

UI Shell Port

The adapters that back these ports.

Approvals & Cancellation

Human-in-the-loop on the device.