Privacy & security
Keys in secure device storage, conversations local-only, prompts only to your chosen provider, no telemetry, and one-tap erase of every local boundary.
Cordy for Mobile is designed so that your keys and conversations stay yours. There is no Cordy backend: the app talks directly from your device to the provider you choose. This page is the complete data-handling story, including an honest note on platform status.
Principles
- No backend. Cordy operates no server. Nothing you type is sent to, stored by, or routed through Cordy.
- Local-first. Conversations and settings live on the device; API keys live in the platform secure store.
- Direct to the provider. Prompts go only to the provider you selected, over HTTPS, carrying your key as the request's
Authorizationheader. - No account, no sync, no telemetry. You never sign in, nothing is mirrored to a server, and there is no analytics or payload capture.
- Erasable. One action wipes every local boundary the app owns.
The data flow
When you send a message:
You → CordyAI (on device) → the provider you selected
That's the entire path. The provider receives your prompt (and processes it under their privacy policy and data-retention terms — worth reading for whichever provider you use). Cordy is not a party to the request.
Where your data lives
| Data | Location | Notes |
|---|---|---|
| API keys | Android Keystore / iOS Keychain | Encrypted, device-bound, per provider. Never in the DB or logs. |
| Conversations & messages | On-device SQLDelight (SQLite) database | Never leave the device except as prompt content you send. |
| Attachments (images) | On-device file storage, referenced by messages | Released when their message/conversation is deleted. |
| Settings & preferences | On-device app preferences | Non-sensitive (active provider/model, temperature, etc.). |
| Model catalog & pricing cache | On-device database | Fetched per provider; safe to clear/refresh. |
Key storage, in detail
API keys get the strongest local protection each platform offers:
- Android — a key held in the Android Keystore performs AES-256-GCM encryption of each value, stored as Base64(IV ‖ ciphertext ‖ GCM tag) in a private preferences file. If the Keystore key is permanently invalidated (for example by a device restore or lock-screen reset), the affected value is dropped rather than returned corrupt. Values written by the older
EncryptedSharedPreferencesare transparently migrated to this scheme on first read. - iOS — the Keychain, stored with
AfterFirstUnlockThisDeviceOnlyaccessibility. This makes each key device-bound and non-syncable: it is kept out of iCloud Keychain and out of encrypted backups, and is available only after the first unlock.
Keys are scoped per provider, so each provider has an independent entry. Saving a blank key is treated as deletion.
What leaves the device — and what doesn't
- Leaves: the prompt content of messages you send, to the provider you chose, plus your key in that request's auth header.
- Does not leave: your conversation history, your key at rest, your settings, your usage analytics. There is no account, no cloud sync, and no server-side copy of anything.
Logging
Cordy does not capture analytics or telemetry. In release builds, logging severity is capped so that verbose/debug/info logs — which can carry prompt or request detail — never reach the device console. Error messages shown in the UI are deliberately safe: raw provider response bodies, API keys, and auth headers are never displayed.
One-tap erase
Settings → Erase all local data wipes every local boundary the app owns. The confirm dialog is explicit: "This permanently deletes every local conversation, every preference, and every API key on this device. This cannot be undone."
Erase clears, in order:
| Boundary | What's removed |
|---|---|
| Database | Conversations, messages, and generation runs (plus user-defined providers and the model catalog) |
| Preferences | The whole preferences store |
| Secure storage | All stored API keys |
| Attachments | Image attachment files |
| Image caches | Platform image memory + disk caches |
| Temp files | Camera / capture temporary files |
Erase attempts every boundary even if one fails (so a locked keychain can't leave the database full of conversations), collects any failures, and then verifies the app is actually empty. It reports honestly if any part could not be cleared.
What erase does not touch: the app binary, OS-level backups, and anything outside CordyAI's own storage. It only removes data the app itself persisted.
In-app disclosures
Cordy states its data flow inside the app, not just in these docs. Settings includes a Privacy and data flow section: "Conversations stay on this device. API keys use secure storage. This version has no cloud sync, account, or analytics." When a provider is selected, it also shows "Your prompts go to (provider) when you send them. CordyAI doesn't send them anywhere else."
Honest platform note
Android is the fully verified platform. The security model above is implemented and tested on Android.
iOS is in progress. The Keychain-backed key store and the privacy design are implemented in the shared/iOS code and compile against the iOS target, but they have not yet been smoke-tested on a device, and mobile capture (image / camera / voice) is not yet wired on iOS. Until iOS device verification is complete, treat the iOS build as preview-quality and rely on Android for the fully verified experience.