* deps: bump simplexmq for ConnectTarget * chat: migration adds simplex_name to contacts, groups, connections Nullable TEXT column on all three tables, with partial indexes on contacts(user_id, simplex_name) and groups(user_id, simplex_name) for the upcoming connectPlanName lookup. connections.simplex_name is the transient carrier from APIConnect -> XInfo handler, where the value is copied to contacts.simplex_name at delayed create. No reads or writes yet - column threading lands in subsequent commits. * tests: provide namesConfig = Nothing in smpServerCfg Follow-up to the simplexmq pin bump (ee0a45e9). The new namesConfig :: Maybe NamesConfig field on ServerConfig (introduced in simplexmq's namespace branch) needs to appear in the test fixture's record literal, otherwise the test suite fails to compile under -Werror. Disabled by default (Nothing). * chat: thread simplexName through Contact/GroupInfo/Connection records Adds `simplexName :: Maybe SimplexNameInfo` to the three records and extends every SELECT path that reconstructs them to read the new column. Decoded via eitherToMaybe . strDecode . encodeUtf8 (the codebase's established pattern for Maybe Text -> typed-decode fields), extracted as decodeSimplexName helper since the chain appears in toContact / toContact' / toGroupInfo / toConnection. INSERT paths still write Nothing - the write-side wiring lands in the next commit (Task 7). * deps: bump simplexmq for SimplexNameInfo FromField/ToField * chat: cross-reference groupInfoQueryFields and getGroupAndMember_ Two helpers redundantly maintain the same g.* column list. A future g.* addition must be applied to both sites; the cross-reference comments flag this for maintainers. A proper refactor (reusing groupInfoQueryFields from Connections.hs's inline SELECT) is out of scope for this branch. * chat: persist simplexName on prepare and connect-via-plan write paths createPreparedContact/createPreparedGroup gain a Maybe SimplexNameInfo parameter that they write to contacts.simplex_name / groups.simplex_name directly. createConnection_ writes to connections.simplex_name as a transient carrier for the connect-via-plan path. The XInfo handler in Library/Subscriber.hs reads the connection's simplexName and passes it to createDirectContact so the final contact row captures the name. All current callers pass Nothing; the actual flow lights up when APIConnectPlan accepts ConnectTarget and connectPlanName threads the name through (later commits in this branch). Uses the upstream ToField SimplexNameInfo (simplexmq 0b334b66) for writes; reads continue to go via the soft-degradation helper. * chat: APIConnectPlan accepts ConnectTarget; connectPlanName looks up by name APIConnectPlan/Connect flip from Maybe AConnectionLink to Maybe ConnectTarget. connectPlan dispatches CTLink -> connectPlanLink (the prior body, renamed) and CTName -> connectPlanName (new) which looks the name up against contacts.simplex_name and groups.simplex_name via the new getContactBySimplexName / getGroupInfoBySimplexName store helpers. The hit path returns the contact's / group's stored conn link from preparedContact / preparedGroup; missing prepared state or unknown names return CEInvalidConnReq. RSLV on-chain resolution is out of scope for this branch -- known-name lookup is enough for conversation display, search, and external-link share. connLinkP_ parser is unchanged: APIConnect's preparedLink_ stays ACreatedConnLink-shaped, and the Connect / APIConnectPlan parsers already use inline strP for ConnectTarget without going through the helper. Directory.Service call sites updated to wrap their AConnectionLink in CTLink when invoking APIConnectPlan. * chat: surface simplexName in conversation view + JSON output viewConnectionPlan now shows the simplex name beneath known contacts/groups (ILPKnown, CAPKnown, CAPContactViaAddress, GLPKnown active/prepared/deleted). The TH-derived Contact / GroupInfo JSON instances automatically expose `simplexName` (omitted when Nothing per defaultJSON's omitNothingFields), which unblocks client-side display and search. No JSON test added: there is no Contact-level JSON test module in this codebase; coverage is already provided by defaultJSON's omitNothingFields = True behaviour. Server-side substring search has no existing pattern in this codebase; client renderers index simplexName themselves once it appears in the JSON shape. External-link share (preferring simplex:/name… form over the raw link when the contact has a simplexName) lands in the next commit. * chat: share/copy output prefers simplexName when present When a contact or group has a simplex_name stored, the share-link render path emits the canonical simplex:/name... URI (via strEncode) instead of the underlying connection link. Falls back to the existing link rendering when simplexName is Nothing. Final commit of the ConnectTarget plumbing chain: end-to-end users can now (a) connect via @alice.simplex / #group.simplex with the agent layer carrying the name, (b) see the simplex name on the contact/group records and in viewConnectionPlan, (c) share the contact using the namespace-canonical form rather than the raw URI. * deps: bump simplexmq for boundedNonSpace + drop unused FromField * chat: simplex_name partial indexes are UNIQUE A simplex name is a stable, per-user identity (one name → one contact or group). Without a unique constraint, a later writer that populates the column twice for the same name would silently produce two matching rows, and getContactBySimplexName/getGroupInfoBySimplexName would return whichever the planner picks first. Promote the partial indexes added in M20260603 to UNIQUE before any caller wires the writes. Predicate (WHERE simplex_name IS NOT NULL) already scopes the constraint to rows that opted in. * chat: regen Postgres schema dump for UNIQUE simplex_name indexes Follow-up tof71c579c. The SchemaDump test runs against SQLite only; the parallel PostgresSchemaDump suite gates on -fclient_postgres and a running localhost PG instance, which this environment doesn't have. Updated the Postgres schema dump by hand to mirror the migration change (two lines: CREATE INDEX → CREATE UNIQUE INDEX). * chat: CESimplexNameNotFound for name lookup misses connectPlanName now distinguishes "name not found" from "connection link is invalid". CEInvalidConnReq's message ("Connection link is invalid, possibly it was created in a previous version") was misleading when a user typed @alice.simplex against a database that simply has no contact by that name. The two "missing prepared link" cases stay on CEInvalidConnReq — the lookup found a row but the stored link is unusable, which is closer to the existing semantics. The two truly-missing cases (no contact found / no group found) move to CESimplexNameNotFound, which also surfaces the name back to the client for a precise UX. * chat: exclude soft-deleted contacts from idx_contacts_simplex_name The lookup `getContactBySimplexName` (Store/Direct.hs:781) filters `AND deleted = 0`, but the index predicate `WHERE simplex_name IS NOT NULL` covered tombstoned rows too. Forward-compat trap: once writers land a non-Nothing simplex_name, soft-deleting a contact would block re-claiming its name (UNIQUE conflict) even though the lookup reports the slot as free. Tighten the partial-index predicate to also require deleted = 0 so the constraint scope matches the live-lookup scope. Groups have no soft- delete column, so their index stays as-is. * chat: connectPlanName dispatches on nameType first Previously the function always probed contacts.simplex_name first and fell through to groups for NTPublicGroup misses. But the discriminator (`@`/`#`) is embedded in the stored bytes via strEncode, so an `#group.simplex` lookup can never match a contact row. Reorder to case on nameType up front, saving one DB query and one withFastStore transaction acquire on the group path. * chat: CESimplexNameUnprepared for found-but-no-link cases + member-removed filter connectPlanName previously threw CEInvalidConnReq when a name lookup hit a contact / group row whose preparedContact / preparedGroup was NULL. The error message ("Connection link is invalid, possibly it was created in a previous version") was wrong: the name resolved fine, the device just has no link material to reconnect via (typical for a contact created via the XInfo handler rather than the prepare path). Introduce CESimplexNameUnprepared SimplexNameInfo for this case. Also mirror the link-based path's gPlan (Commands.hs:4133) for groups whose membership state is GSMemRemoved — return CESimplexNameNotFound rather than GLPKnown for a removed-member group, since GLPKnown for removed members would be inconsistent with how /_connect plan over a short link handles the same situation. * chat: fix stale CRITICAL comment in saveConnInfo Comment claimed SEDBException is re-thrown as CRITICAL but only SEDBBusyError is (via the `critical` helper at Subscriber.hs:136 and the showCritical branch at :1695). Updated to describe the actual behaviour. * chat: fix misleading decodeSimplexName docstring The comment described "@alice.simplex" as the column's surface form, but ToField SimplexNameInfo writes the canonical strEncode output ("simplex:/name@alice.simplex"). Aligns the docstring with what the column actually holds. * chat: drop redundant T.unpack in CESimplexName* error rendering plain has a Text instance (verified by sibling simplexNameLine at View.hs:2176 which uses it directly). The T.unpack in the new error renderings was inconsistent with the same-feature helper. Cosmetic cleanup. * deps: bump simplexmq for resolveSimplexName * chat: simplexName field on Profile, GroupProfile, LocalProfile Adds a Maybe SimplexNameInfo field to the wire-level Profile and GroupProfile (and their DB sibling LocalProfile). JSON instances are TH-derived with omitNothingFields = True, so the new optional field is auto-handled and old peers / old JSON without the key decode as Nothing. Existing record-construction sites are set to simplexName = Nothing as a placeholder. Outgoing dissemination (userProfileDirect / userProfileInGroup) and incoming persistence wire-up land in follow-up commits. redactedMemberProfile passes the field through, matching how peerType is preserved. * chat: load LocalProfile.simplexName from simplex_name column Populate the embedded LocalProfile.simplexName field for the user's own profile and for peer Contact / GroupInfo from the existing simplex_name columns on contacts and groups. Previously every DB read set this field to Nothing (Task 1 placeholder), so downstream consumers that work off LocalProfile / GroupProfile (e.g., userProfileDirect / userProfileInGroup that build outgoing XInfo / XGrpInfo via fromLocalProfile) saw Nothing unconditionally. Scope is limited to the rows where the simplex_name column actually exists: contacts (per-user) and groups (per-user). Sites that only read contact_profiles / group_profiles (toContactRequest, toContactProfile, toGroupProfile, rowToLocalProfile) remain Nothing; Task 3 adds the profile-table columns and wires them up. * chat: test outgoing Profile carries simplexName from User profile userProfileDirect, userProfileInGroup' and redactedMemberProfile already pass simplexName through via fromLocalProfile (Task 1) once the embedded LocalProfile field is populated (previous commit). Lock that behavior in with focused unit tests: - userProfileDirect with Just simplexName -> wire Profile.simplexName Just - userProfileDirect with Nothing -> wire Nothing - userProfileDirect with an incognito Profile overlay -> wire Nothing (incognito identity must not leak the user's registered name) - userProfileInGroup' pass-through - redactedMemberProfile pass-through (forwarded member profiles) * chat: clarify groups.simplex_name stopgap comment Drop the asymmetric toContact comment (the mirror is now obvious post-Task-1) and rewrite the toGroupInfo stopgap comment to reflect the actual semantics: groups.simplex_name is per-user locally-known, mirrored into groupProfile as a stopgap until group_profiles.simplex_name lands. * chat: add simplex_name to contact_profiles and group_profiles Adds nullable simplex_name TEXT column and partial UNIQUE (user_id, simplex_name) index to both contact_profiles and group_profiles tables. Distinct from contacts.simplex_name / groups.simplex_name (M20260603), which carry the user's locally-known label set by the prepare-via-name path; the new columns will carry the peer's broadcast claim received via XInfo / XGrpInfo (wired up in following commits). * chat: persist peer-claimed simplexName from incoming profiles Write paths: - updateContactProfile_' / updateGroupProfile_ now set the new contact_profiles.simplex_name / group_profiles.simplex_name columns from Profile.simplexName / GroupProfile.simplexName respectively. - createContact_ INSERT writes Profile.simplexName to the new contact_profiles column (separate from the existing simplexName arg, which still writes contacts.simplex_name — the user's locally-known label). Read paths (closing Task 2's deferred sites): - toContact splits simplex_name reads: Contact.simplexName from contacts.simplex_name (existing); LocalProfile.simplexName from contact_profiles.simplex_name (new column). - toGroupInfo similarly splits: GroupInfo.simplexName from groups.simplex_name; groupProfile.simplexName from group_profiles.simplex_name. - ProfileRow / rowToLocalProfile, toContactRequest, getUserContactProfiles, toGroupProfile, getProfileById, groupMemberQuery, getGroupAndMember_, saveRcvChatItem-related quotes — all extended to read p.simplex_name and decode it into LocalProfile.simplexName / GroupProfile.simplexName. Conflict handling (Decision B): - clearConflictingContactProfileSimplexName_ / *Group* helpers do an atomic UPDATE-with-RETURNING that NULLs simplex_name on any other row in the same user that would collide on the partial UNIQUE index, returning the displaced row's display_name. - updateContactProfileWithConflict / updateGroupProfileWithConflict bundle clear+update in one transaction. - processContactProfileUpdate / xGrpInfo invoke the *WithConflict variants and emit CEvtSimplexNameConflict when a displacement happened (with the claiming and displaced display names). Adds ChatEvent CEvtSimplexNameConflict and SimplexNameConflictEntity (SNCEContact / SNCEGroup) with JSON instances and View.hs rendering. * chat: fix review findings on simplex_name persistence - updateUserProfile no longer writes contact_profiles.simplex_name on the user's own row (the column is reserved for peer claims; the user's broadcastable name lives on contacts.simplex_name via uct.simplex_name). - updateMemberContactProfile_'/Reset_' now write simplex_name; new updateMemberProfileWithConflict / updateContactMemberProfileWithConflict variants run conflict-clear and return the displaced name, with processMemberProfileUpdate emitting CEvtSimplexNameConflict. - createContact_ runs conflict-clear before INSERT to avoid UNIQUE constraint violations on first-write peer collisions, returning the displaced name; createPreparedContact / createDirectContact thread it through to APIPrepareContact and saveConnInfo XInfo for event emission. - groups conflict-clear takes ProfileId directly (avoids the NOT IN (NULL) silent-noop edge case when groups.group_profile_id is ON DELETE SET NULL). - Moves clearConflictingContactProfileSimplexName_ to Shared.hs so createContact_ can call it without inducing a circular import. * chat: resolveOnUserServers iterates user SMP servers for RSLV * chat: connectPlanName falls back to RSLV when local lookup misses * chat: RSLV-resolved NameRecord dispatched through prepared row dispatchResolvedRecord now picks the first nrContactLinks (NTContact) or nrChannelLinks (NTPublicGroup) entry from the resolved record, decodes it as AConnShortLink, fetches the short-link data, and eagerly calls createPreparedContact / createPreparedGroup with the simplex_name set. Returning CPContactAddress (CAPKnown ct) / CPGroupLink (GLPKnown g ...) mirrors the local-store-hit branch of connectPlanName: hit and miss converge on the same plan shape, so the connectWithPlan caller cannot distinguish where the prepared row came from. Threading uses the existing Maybe SimplexNameInfo parameter added in c6f26150 for the local-prepare path -- no new write path or transient carrier. Pure helper firstNameLink is extracted and exported so the link-picker contract is testable without a DB / agent. ResolveNameTests gains five cases covering the per-type selection, the first-link policy, and the empty-list to CESimplexNameNotFound collapse. * chat: regen query plans after simplex_name plumbing * chat: register ConnectTarget + CEvtSimplexNameConflict in bot docs Bot API docs generator failed with "Undefined type: ConnectTarget" sincef2394d121(prior plan) flipped APIConnectPlan/Connect from Maybe AConnectionLink to Maybe ConnectTarget without updating bots/src/API/Docs/*. Also adds SimplexNameConflictEntity (new incd0de9659) and documents the CEvtSimplexNameConflict event for peer-name displacement notifications. Regenerates the affected markdown / TypeScript / Python artefacts. * deps: bump simplexmq for NameRecord reshape; update consumers simplexmq 5ee014dd reshaped NameRecord to align with the Python resolver JSON: nrChannelLinks/nrContactLinks (lists of NameLink) became nrSimplexChannel/nrSimplexContact (Maybe Text); nrDisplayName became nrName; nrResolver was added; the NameLink wrapper type and nrIsTest/ nrExpiry/nrAdminAddress/nrAdminEmail fields were dropped. Update dispatchResolvedRecord destructure and firstNameLink signature to the new Maybe Text shape, and refresh the ResolveNameTests fixtures and assertions accordingly. * chat: resolveOnUserServers iterates only on transport errors Privacy: every miss previously broadcast the candidate name to every enabled SMP server. Now only NETWORK / TIMEOUT failures fall through to the next server; definite resolver answers (NAME / AUTH / CMD PROHIBITED / other ERR) stop iteration. * chat: document why groups simplex_name index has no soft-delete filter The contacts simplex_name index filters on (deleted = 0); the groups index has no analogous filter because the groups table has no `deleted` column. Groups are hard-deleted by deleteGroup, so the asymmetry is intentional. The remaining "removed member, row retained" edge case is flagged in the lookup comment for follow-up. * chat: document connections.simplex_name as transient carrier Audit flagged the column as "INSERTed but never UPDATEd". This is by design per the prior plan's connect-via-plan flow: the column is a transient carrier between connection-creation and contact-creation. After the Contact row is created via XInfo handling, contacts.simplex_name is the source of truth and the connections value is a historical snapshot. Documents the intent so future readers don't reflag it. * chat: extract surfaceSimplexNameConflict helper Six call sites duplicated the same forM_ ((,) <$> claim <*> displaced) shape emitting CEvtSimplexNameConflict. Extract to a single helper so future call sites don't drift on whether to emit, and so the conflict event shape change (post-Task-3 SimplexNameConflictEntity split into SNCEContact / SNCEGroup) propagates through one site. * chat: APIVerifySimplexName command + CEvtSimplexNameUnverified warning Addresses the TOFU vulnerability where peer-claimed simplex_name was accepted unverified. Adds: - contacts.simplex_name_verified_at + groups.simplex_name_verified_at (M20260606_simplex_name_verified) - APIVerifySimplexName ChatRef command: RSLV-resolves the claimed name and compares the resolved link to the peer's stored connection link; on match writes verified_at and emits CEvtSimplexNameVerified; on mismatch emits CEvtSimplexNameVerifyFailed - CEvtSimplexNameUnverified passive warning emitted on incoming XInfo / XGrpInfo when a name claim arrives without a current verification - updateContactProfileWithConflict / updateGroupProfileWithConflict clear simplex_name_verified_at whenever the peer's claim transitions (any value change including Nothing<->Just): the prior verification was bound to the prior claim. UI can surface the unverified indicator next to a contact / group's name, and prompt the user to invoke the verify command. This shifts the security model from "TOFU + last-writer-wins" to "TOFU + on-demand RSLV verification". * chat: register APIVerifySimplexName + verify events in bot docsebe90f716added the verify command + events + SimplexNameVerifyFailReason type without touching bots/src/API/Docs/. Mirrors commit0d7ea8061which addressed the same gap for ConnectTarget. Regenerates the affected markdown / TypeScript / Python artefacts. * chat: bump simplexmq pin + document cross-table simplex_name discriminator Pin bump 5ee014dd -> c9c2d19 picks up the 8 simplexmq commits since the last bump (parseBare lowercase fix, forwarded-param cleanup, ServerTests + agent end-to-end tests, TldRegistries removal, SNRC ABI decoder, NameRecord/NameOwner module extraction). Adds a brief comment on clearConflictingContactProfileSimplexName_ explaining why the audit's flagged cross-table collision (between contact_profiles.simplex_name and group_profiles.simplex_name) is structurally impossible: SimplexNameInfo's strEncode prefixes contact names with '@' and group names with '#', so the stored bytes never overlap between the two tables. Query-plan regen deferred (the test is non-deterministic in CI / dev sandbox — see prior6c990696c). * deps: bump simplexmq for HTTP resolver; adapt NameRecord consumers simplexmq 92b3d049 reshaped NameRecord text fields from Maybe Text to Text (empty string sentinel). Adapt firstNameLink to take Text directly and treat T.null as "absent". dispatchResolvedRecord destructure unchanged; passes the text values straight through. apiVerifySimplexName switches from Just/Nothing pattern to a T.null guard with the same UX. Test fixtures updated. * deps: bump simplexmq for multi-link NameRecord; adapt consumers * core: treat RSLV CMD UNKNOWN as no name-resolution support * core: fix contact-by-connection query missing simplex_name_verified_at * deps: update sha256map for simplexmq f555e9af pin * core: iterate past RSLV-unsupported name servers * core: filter RSLV servers by operator enablement * core: align resolver docs/tests with RSLV errors * deps: bump simplexmq to df1aa24c * refactor(names): agent resolution + one error type Adopt the simplexmq names rework (PR #7045): name resolution is now owned by the agent (resolveSimplexName picks a names-role server), so the chat-side iteration is removed - delete ResolveError, iterateResolvers, resolveOnUserServers, enabledSMPServersForUser and resolveErrorToChatError. One error type: resolver/agent failures flow through ChatErrorAgent; remove the CEvtSimplexName* events, SimplexNameVerifyFailReason, SimplexNameConflictEntity and CESimplexNameResolverUnavailable. APIVerifySimplexName returns CRSimplexNameVerified (verified::Bool), mirroring CRConnectionVerified. connectPlan handles the name target directly; updateProfile WithConflict aliases collapsed into the plain functions. Add the per-operator "names" SMP server role (migration 20260612_smp_role_names, official operator on by default) feeding ServerRoles.names -> UserServers.nameSrvs. Bump simplexmq pin to ce69adfd and regenerate sha256map.nix. * fix(store): match chat_schema.sql to sqlite 3.46+ indent The schema-dump test renders the partial-index WHERE via the sqlite3 CLI; sqlite >=3.46 wraps a multi-condition WHERE onto two lines ("IS NOT NULL" + indented "AND ...") where 3.45 kept it on one. The committed schema was generated with 3.45, so CI (newer sqlite) failed the comparison on idx_contacts_simplex_name. Regenerated with the newer formatter; only that one WHERE clause changes. * feat(operators): warn when no server resolves names Mirror USWNoChatRelays: validateUserServers emits USWNoNamesServers when no enabled server of an enabled operator carries the SMP names role. noNamesServersWarns is self-contained with local predicates, matching the sibling noChatRelaysWarns; noServersErrs is untouched. * test(operators): expect USWNoNamesServers warning in no-servers cases * fix(store): single-line simplex_name WHERE to match CI sqlite (<=3.45) * chore: bump simplexmq pin to 6843b14c * refactor(store): consolidate names migrations into one Unshipped feature - merge the four incremental simplex_name migrations (0603/0604/0606/0612) into a single M20260603_simplex_name. The combined UP applies the ALTERs/indexes in the same order, so the resulting schema is byte-identical (verified by SchemaDump on SQLite and pg_dump on Postgres). * update simplexmq * plan for name resolution * update types and schema * simpler resolution, name proofs * simplexmq * generate bot types, schema, unStrJSON, fix tests * ad hoc link comparison, create short link * update simplexmq * remove same link, use simplexmq instead * split verify API for contacts and public groups * remove comment * simplify warnings * test: remove unused * remove cute language * type name * remove spurious comments * refactor setting user name * refactor setting user name * remove trivial tests * refactor * remove tests using pre-short-link addresses * rename * move names * bots api * refactor more * refactor * refactor to another type * load own names * read short links when looking up by name * renames * refactor verification * mapM_ * update api types * change field for name * rename columns * api types, schema * renames * fix links * simplify * remove comments * rename fields * simplify * remove proof from channel addres * refactor * name resolution test * change tests * fix tests * fix tests * fix plan for names * test * test verification status * bot api * fix tests * update bot api types * query plan * add api for setting public group access * android, desktop, ios: connect via SimpleX name (#7068) * android, desktop, ios: connect via SimpleX name * android, desktop, ios: open known contact on name lookup; surface prepared contact Name search opens the contact (not list-filter); resolved/prepared contacts and groups are added to the chat list so they're visible and openable. Kotlin compile-verified; iOS edits pattern-matched, pending Xcode build. * feat(names): UI names role + agent NAME error Parity with the core names rework (#7045): - Add `names` to ServerRoles (Android + iOS) and a per-operator "To resolve names" toggle under the SMP section (xftp has no names role; the shared ServerRoles field stays false there). - Mirror the new agent error: NameErrorType + a NAME case on both AgentErrorType and ProtocolErrorType (the SMP ErrorType mirror), so the new SMP/agent NAME errors decode instead of crashing the decoder. - Remove ChatErrorType.SimplexNameResolverUnavailable (deleted in core) and repoint its "name resolution unavailable" alert to the agent NAME NO_SERVERS error, reusing the existing strings. Android (multiplatform) compiles clean; iOS mirrors the same changes (builds in Xcode). * feat(names): UI warning when no server resolves names Mirror core USWNoNamesServers: add the NoNamesServers variant to UserServersWarning (Kotlin sealed class + Swift enum) and its globalWarning / globalServersWarning branch, rendered by the existing ServersWarningFooter / ServersWarningView. Matches the noChatRelays warning exactly. * fix(servers): show all validation errors and warnings, not just the first globalServersError/Warning returned only the first entry, so a second warning (e.g. no names servers behind no chat relays) or a second error (e.g. no XFTP servers behind no SMP servers) was never displayed. Make them return all entries (globalServersErrors/Warnings) and render one footer row each, across the three combined-footer views. Per-protocol SMP/XFTP footers are unchanged. * docs(names): add SimpleX name UI plan * feat(names): add name model fields + SimplexName helpers * feat(names): verify + set-name API & responses * docs(names): bump core sync to5008b4e62* feat(names): show name + verification on chat info * feat(names): add Verify SimpleX names privacy toggle * feat(names): add set-name screens (user + channel) * update ui * fix kotlin * fix codable * fix ios * fix errors * api in UI * send name as string in protocol * update simplexmq, capitalize * verify that name is in profile for own and known contacts and channels as condition of name resolution * update simplexmq --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com> Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com> * add log * bot types * finalize renames, ui alerts * more renames * kotlin alerts * show set name * alerts * texts, icons, footers * move JSON parsing to a persistent thread with large stack * simplexmq * use uikit alerts * remove comment * move name verification to more privacy * change icon on verify names setting * verify name proof * nix shas * show verified names * better alert when saving names * revert breaking field name change * simplexmq * clean up * remove unused * remove empty line * fix error * simplify * use domain without prefix in profiles and in database, rename fields and types * rename types * fix JSON name * pass verified domain to prepare API * fix prepare api * fix ios encoding * enable name resolution via Flux servers * fix test --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com> Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
| 30/03/2023 | EN, FR, CZ, PL |
Invest in SimpleX Chat. Register now.
SimpleX - the first messaging platform that has no user identifiers of any kind - 100% private by design!
Why we are building SimpleX Network
Welcome to SimpleX Chat!
- 📲 Install the app.
- ↔️ Connect to the team, join user groups and follow our updates.
- 🤝 Make a private connection with a friend.
- 🔤 Help translating SimpleX Chat.
- ⚡️ Contribute and support us with donations.
Learn more about SimpleX Chat.
Install the app
- 🖲 Protects your messages and metadata - who you talk to and when.
- 🔐 Double ratchet end-to-end encryption, with additional encryption layer.
- 📱 Mobile apps for Android (Google Play, APK) and iOS.
- 🚀 TestFlight preview for iOS with the new features 1-2 weeks earlier - limited to 10,000 users!
- 🖥 Available as a terminal (console) app / CLI on Linux, MacOS, Windows.
Connect to the team
You can connect to the team via the app using "chat with the developers button" available when you have no conversations in the profile, "Send questions and ideas" in the app settings or via our SimpleX address. Please connect to:
- to ask any questions
- to suggest any improvements
- to share anything relevant
We are replying the questions manually, so it is not instant – it can take up to 24 hours.
If you are interested in helping us to integrate open-source language models, and in joining our team, please get in touch.
Join user groups
You can find the groups created by users in SimpleX Directory. It is also available as SimpleX bot that allows to add your own groups and communities to the directory. We are not responsible for the content shared in these groups.
Please note: The groups below are created for the users to be able to ask questions, make suggestions and ask questions about SimpleX Chat only.
You can join an English-speaking users group if you want to ask any questions: #SimpleX users group
There is also a group #simplex-devs for developers who build on SimpleX platform:
- chat bots and automations
- integrations with other apps
- social apps and services
- etc.
You can join these and other groups by opening these links in the app or by opening them in a desktop browser and scanning the QR code.
Follow our updates
We publish our updates and releases via:
- Reddit, Twitter, Lemmy, Mastodon and Nostr.
- SimpleX Chat team profile.
- blog and RSS feed.
- mailing list, very rarely.
Make a private connection
You need to share a link with your friend or scan a QR code from their phone, in person or during a video call, to make a connection and start messaging.
The channel through which you share the link does not have to be secure - it is enough that you can confirm who sent you the message and that your SimpleX connection is established.
After you connect, you can verify connection security code.
User guide (NEW)
Read about the app features and settings in the new User guide.
Contribute
We would love to have you join the development! You can help us with:
- develop a chat bot for SimpleX Chat!
- writing a tutorial or recipes about hosting servers, chat bots, etc.
- developing features - please connect to us via chat so we can help you get started.
Help translating SimpleX Chat
Thanks to our users and Weblate, SimpleX Chat apps, website and documents are translated to many other languages.
Join our translators to help SimpleX grow!
| locale | language | contributor | Android and iOS | website | Github docs |
|---|---|---|---|---|---|
| 🇬🇧 en | English | ✓ | ✓ | ✓ | |
| ar | العربية | jermanuts | - |
||
| 🇧🇬 bg | Български | ||||
| 🇨🇿 cs | Čeština | zen0bit | ✓ | ||
| 🇩🇪 de | Deutsch | mlanp | |||
| 🇪🇸 es | Español | Mateyhv | |||
| 🇫🇮 fi | Suomi | ||||
| 🇫🇷 fr | Français | ishi_sama | ✓ | ||
| 🇮🇱 he | עִברִית | - |
|||
| 🇭🇺 hu | Magyar | - |
|||
| 🇮🇹 it | Italiano | unbranched | |||
| 🇯🇵 ja | 日本語 | ||||
| 🇳🇱 nl | Nederlands | mika-nl | |||
| 🇵🇱 pl | Polski | BxOxSxS | |||
| 🇧🇷 pt-BR | Português | - |
|||
| 🇷🇺 ru | Русский | ||||
| 🇹🇭 th | ภาษาไทย | titapa-punpun | |||
| 🇹🇷 tr | Türkçe | ||||
| 🇺🇦 uk | Українська | ||||
| 🇨🇳 zh-CHS | 简体中文 | sith-on-mars Float-hu |
Languages in progress: Arabic, Japanese, Korean, Portuguese and others. We will be adding more languages as some of the already added are completed – please suggest new languages, review the translation guide and get in touch with us!
Please support us with your donations
Huge thank you to everybody who donated to SimpleX Chat!
We are prioritizing users privacy and security - it would be impossible without your support.
Our pledge to our users is that SimpleX protocols are and will remain open, and in public domain, - so anybody can build the future implementations of the clients and the servers. We are building SimpleX platform based on the same principles as email and web, but much more private and secure.
Your donations help us raise more funds - any amount, even the price of the cup of coffee, would make a big difference for us.
It is possible to donate via:
- GitHub (commission-free) or OpenCollective (~10% commission).
- BTC: bc1q2gy6f02nn6vvcxs0pnu29tpnpyz0qf66505d4u
- XMR: 8A3ZWAXrrQddvnT1fPrtbK86ZAoM4nai3Gjg1LEow3JWcryJtovMnHYZnxTJpCLmAbfWbnPMeTzPmMBjAhyd4xoM89hYq1c
- BCH: bitcoincash:qq6c8vfvxqrk6rhdysgvkhqc24sggkfsx5nqvdlqcg
- ETH/USDT (Ethereum, Arbitrum One): 0xD7047Fe3Eecb2f2FF78d839dD927Be27Bc12c86a (donate.simplexchat.eth)
- ZEC: t1fwjQW5gpFhDqXNhxqDWyF9j9WeKvVS5Jg
- ZEC shielded: u16rnvkflumf5uw9frngc2lymvmzgdr2mmc9unyu0l44unwfmdcpfm0axujd2w34ct3ye709azxsqge45705lpvvqu264ltzvfay55ygyq
- DOGE: D99pV4n9TrPxBPCkQGx4w4SMSa6QjRBxPf
- SOL: 7JCf5m3TiHmYKZVr6jCu1KeZVtb9Y1jRMQDU69p5ARnu
- please ask if you want to donate any other coins.
Thank you,
Evgeny
SimpleX Chat founder
Contents
- Why privacy matters
- SimpleX approach to privacy and security
- Frequently asked questions
- News and updates
- Quick installation of a terminal app
- SimpleX Platform design
- Privacy and security: technical details and limitations
- For developers
- Develop a chat bot
- Roadmap
- Disclaimers, Security contact, License
Why privacy matters
Everyone should care about privacy and security of their communications - innocuous conversations can put you in danger even if there is nothing to hide.
One of the most shocking stories is the experience of Mohamedou Ould Salahi that he wrote about in his memoir and that is shown in The Mauritanian movie. He was put into Guantanamo camp, without trial, and was tortured there for 15 years after a phone call to his relative in Afghanistan, under suspicion of being involved in 9/11 attacks, even though he lived in Germany for the 10 years prior to the attacks.
It is not enough to use an end-to-end encrypted messenger, we all should use the messengers that protect the privacy of our personal networks - who we are connected with.
SimpleX approach to privacy and security
Complete privacy of your identity, profile, contacts and metadata
Unlike any other existing messaging platform, SimpleX has no identifiers assigned to the users - not even random numbers. This protects the privacy of who are you communicating with, hiding it from SimpleX platform servers and from any observers. Read more.
The best protection against spam and abuse
As you have no identifier on SimpleX platform, you cannot be contacted unless you share a one-time invitation link or an optional temporary user address. Read more.
Complete ownership, control and security of your data
SimpleX stores all user data on client devices, the messages are only held temporarily on SimpleX relay servers until they are received. Read more.
Users own SimpleX network
You can use SimpleX with your own servers and still communicate with people using the servers that are pre-configured in the apps or any other SimpleX servers. Read more.
Frequently asked questions
-
How SimpleX can deliver messages without any user identifiers? See v2 release announcement explaining how SimpleX works.
-
Why should I not just use Signal? Signal is a centralized platform that uses phone numbers to identify its users and their contacts. It means that while the content of your messages on Signal is protected with robust end-to-end encryption, there is a large amount of meta-data visible to Signal - who you talk with and when.
-
How is it different from Matrix, Session, Ricochet, Cwtch, etc., that also don't require user identities? Although these platforms do not require a real identity, they do rely on anonymous user identities to deliver messages – it can be, for example, an identity key or a random number. Using a persistent user identity, even anonymous, creates a risk that user's connection graph becomes known to the observers and/or service providers, and it can lead to de-anonymizing some users. If the same user profile is used to connect to two different people via any messenger other than SimpleX, these two people can confirm if they are connected to the same person - they would use the same user identifier in the messages. With SimpleX there is no meta-data in common between your conversations with different contacts - the quality that no other messaging platform has.
News and updates
Recent and important updates:
Jul 29, 2025 SimpleX Chat v6.4.1: welcome your contacts, review members to protect groups, and more.
Mar 8, 2025. SimpleX Chat v6.3: new user experience and safety in public groups
Jan 14, 2025. SimpleX network: large groups and privacy-preserving content moderation
Mar 14, 2024. SimpleX Chat v5.6 beta: adding quantum resistance to Signal double ratchet algorithm.
Apr 22, 2023. SimpleX Chat: vision and funding, v5.0 released with videos and files up to 1gb.
Nov 8, 2022. Security audit by Trail of Bits, the new website and v4.2 released.
⚡ Quick installation of a terminal app
curl -o- https://raw.githubusercontent.com/simplex-chat/simplex-chat/stable/install.sh | bash
Once the chat client is installed, simply run simplex-chat from your terminal.
Read more about installing and using the terminal app.
SimpleX Platform design
SimpleX is a client-server network with a unique network topology that uses redundant, disposable message relay nodes to asynchronously pass messages via unidirectional (simplex) message queues, providing recipient and sender anonymity.
Unlike P2P networks, all messages are passed through one or several server nodes, that do not even need to have persistence. In fact, the current SMP server implementation uses in-memory message storage, persisting only the queue records. SimpleX provides better metadata protection than P2P designs, as no global participant identifiers are used to deliver messages, and avoids the problems of P2P networks.
Unlike federated networks, the server nodes do not have records of the users, do not communicate with each other and do not store messages after they are delivered to the recipients. There is no way to discover the full list of servers participating in SimpleX network. This design avoids the problem of metadata visibility that all federated networks have and better protects from the network-wide attacks.
Only the client devices have information about users, their contacts and groups.
See SimpleX whitepaper for more information on platform objectives and technical design.
See SimpleX Chat Protocol for the format of messages sent between chat clients over SimpleX Messaging Protocol.
Privacy and security: technical details and limitations
SimpleX Chat is a work in progress – we are releasing improvements as they are ready. You have to decide if the current state is good enough for your usage scenario.
We compiled a glossary of terms used to describe communication systems to help understand some terms below and to help compare advantages and disadvantages of various communication systems.
What is already implemented:
- Instead of user profile identifiers used by all other platforms, even the most private ones, SimpleX uses pairwise per-queue identifiers (2 addresses for each unidirectional message queue, with an optional 3rd address for push notifications on iOS, 2 queues in each connection between the users). It makes observing the network graph on the application level more difficult, as for
nusers there can be up ton * (n-1)message queues. - End-to-end encryption in each message queue using NaCl cryptobox. This is added to allow redundancy in the future (passing each message via several servers), to avoid having the same ciphertext in different queues (that would only be visible to the attacker if TLS is compromised). The encryption keys used for this encryption are not rotated, instead we are planning to rotate the queues. Curve25519 keys are used for key negotiation.
- Double ratchet end-to-end encryption in each conversation between two users (or group members). This is the same algorithm that is used in Signal and many other messaging apps; it provides OTR messaging with forward secrecy (each message is encrypted by its own ephemeral key) and break-in recovery (the keys are frequently re-negotiated as part of the message exchange). Two pairs of Curve448 keys are used for the initial key agreement, initiating party passes these keys via the connection link, accepting side - in the header of the confirmation message.
- Post-quantum resistant key exchange in double ratchet protocol on every ratchet step. Read more in this post and also see this publication by Apple explaining the need for post-quantum key rotation.
- Additional layer of encryption using NaCL cryptobox for the messages delivered from the server to the recipient. This layer avoids having any ciphertext in common between sent and received traffic of the server inside TLS (and there are no identifiers in common as well).
- Several levels of content padding to frustrate message size attacks.
- All message metadata, including the time when the message was received by the server (rounded to a second) is sent to the recipients inside an encrypted envelope, so even if TLS is compromised it cannot be observed.
- Only TLS 1.2/1.3 are allowed for client-server connections, limited to cryptographic algorithms: CHACHA20POLY1305_SHA256, Ed25519/Ed448, Curve25519/Curve448.
- To protect against replay attacks SimpleX servers require tlsunique channel binding as session ID in each client command signed with per-queue ephemeral key.
- To protect your IP address from unknown messaging relays, and for per-message transport anonymity (compared with Tor/VPN per-connection anonymity), from v6.0 all SimpleX Chat clients use private message routing by default. Read more in this post.
- To protect your IP address from unknown file relays, when SOCKS proxy is not enabled SimpleX Chat clients ask for a confirmation before downloading the files from unknown servers.
- To protect your IP address from known servers all SimpleX Chat clients support accessing messaging servers via Tor - see v3.1 release announcement for more details.
- Local database encryption with passphrase - your contacts, groups and all sent and received messages are stored encrypted. If you used SimpleX Chat before v4.0 you need to enable the encryption via the app settings.
- Transport isolation - different TCP connections and Tor circuits are used for traffic of different user profiles, optionally - for different contacts and group member connections.
- Manual messaging queue rotations to move conversation to another SMP relay.
- Sending end-to-end encrypted files using XFTP protocol.
- Local files encryption.
- Reproducible server builds.
We plan to add:
- Automatic message queue rotation and redundancy. Currently the queues created between two users are used until the queue is manually changed by the user or contact is deleted. We are planning to add automatic queue rotation to make these identifiers temporary and rotate based on some schedule TBC (e.g., every X messages, or every X hours/days).
- Message "mixing" - adding latency to message delivery, to protect against traffic correlation by message time.
- Reproducible clients builds – this is a complex problem, but we are aiming to have it in 2025 at least partially.
- Recipients' XFTP relays to reduce traffic and conceal IP addresses from the relays chosen, and potentially controlled, by another party.
For developers
You can:
- create chat bots and services.
- run simplex-chat terminal CLI to execute individual chat commands, e.g. to send messages as part of shell script execution.
- use SimpleX Chat library to integrate chat functionality into your mobile apps.
- create chat bots and services in Haskell - see simple and more advanced chat bot example.
If you are considering developing with SimpleX platform please get in touch for any advice and support.
Please also join #simplex-devs group to ask any questions and share your success stories.
Develop a chat bot
You can create a chat bot or any chat-based service in any language running SimpleX Chat terminal CLI as a local WebSocket server.
See our new bot API reference. Most of it is automatically generated from core library types, so it stays up to date.
Also see TypeScript SimpleX Chat client and JavaScript chat bot example.
Roadmap
- ✅ Easy to deploy SimpleX server with in-memory message storage, without any dependencies.
- ✅ Terminal (console) client with groups and files support.
- ✅ One-click SimpleX server deployment on Linode.
- ✅ End-to-end encryption using double-ratchet protocol with additional encryption layer.
- ✅ Mobile apps v1 for Android and iOS.
- ✅ Private instant notifications for Android using background service.
- ✅ Haskell chat bot templates.
- ✅ v2.0 - supporting images and files in mobile apps.
- ✅ Manual chat history deletion.
- ✅ End-to-end encrypted WebRTC audio and video calls via the mobile apps.
- ✅ Privacy preserving instant notifications for iOS using Apple Push Notification service.
- ✅ Chat database export and import.
- ✅ Chat groups in mobile apps.
- ✅ Connecting to messaging servers via Tor.
- ✅ Dual server addresses to access messaging servers as v3 hidden services.
- ✅ Chat server and TypeScript client SDK to develop chat interfaces, integrations and chat bots (ready for announcement).
- ✅ Incognito mode to share a new random name with each contact.
- ✅ Chat database encryption.
- ✅ Automatic chat history deletion.
- ✅ Links to join groups and improve groups stability.
- ✅ Voice messages (with recipient opt-out per contact).
- ✅ Basic authentication for SMP servers (to authorize creating new queues).
- ✅ View deleted messages, full message deletion by sender (with recipient opt-in per contact).
- ✅ Block screenshots and view in recent apps.
- ✅ Advanced server configuration.
- ✅ Disappearing messages (with recipient opt-in per-contact).
- ✅ "Live" messages.
- ✅ Contact verification via a separate out-of-band channel.
- ✅ Multiple user profiles in the same chat database.
- ✅ Optionally avoid re-using the same TCP session for multiple connections.
- ✅ Preserve message drafts.
- ✅ File server to optimize for efficient and private sending of large files.
- ✅ Improved audio & video calls.
- ✅ Support older Android OS and 32-bit CPUs.
- ✅ Hidden chat profiles.
- ✅ Sending and receiving large files via XFTP protocol.
- ✅ Video messages.
- ✅ App access passcode.
- ✅ Improved Android app UI design.
- ✅ Optional alternative access password.
- ✅ Message reactions
- ✅ Message editing history
- ✅ Reduced battery and traffic usage in large groups.
- ✅ Message delivery confirmation (with sender opt-out per contact).
- ✅ Desktop client.
- ✅ Encryption of local files stored in the app.
- ✅ Using mobile profiles from the desktop app.
- ✅ Private notes.
- ✅ Improve sending videos (including encryption of locally stored videos).
- ✅ Post-quantum resistant key exchange in double ratchet protocol.
- ✅ Message delivery relay for senders (to conceal IP address from the recipients' servers and to reduce the traffic).
- ✅ Support multiple network operators in the app.
- 🏗 Large groups, communities and public channels.
- 🏗 Short links to connect and join groups.
- 🏗 Improve stability and reduce battery usage.
- 🏗 Improve experience for the new users.
- Privacy & security slider - a simple way to set all settings at once.
- SMP queue redundancy and rotation (manual is supported).
- Include optional message into connection request sent via contact address.
- Improved navigation and search in the conversation (expand and scroll to quoted message, scroll to search results, etc.).
- Feeds/broadcasts.
- Ephemeral/disappearing/OTR conversations with the existing contacts.
- Privately share your location.
- Web widgets for custom interactivity in the chats.
- Programmable chat automations / rules (automatic replies/forward/deletion/sending, reminders, etc.).
- Privacy-preserving identity server for optional DNS-based contact/group addresses to simplify connection and discovery, but not used to deliver messages:
- keep all your contacts and groups even if you lose the domain.
- the server doesn't have information about your contacts and groups.
- High capacity multi-node SMP relays.
Disclaimers
SimpleX protocols and security model was reviewed, and had many breaking changes and improvements in v1.0.0.
The implementation security assessment of SimpleX cryptography and networking was done in October 2022 by Trail of Bits – see the announcement.
The cryptographic review of SimpleX protocols was done in July 2024 by Trail of Bits – see the announcement.
SimpleX Chat is still a relatively early stage platform (the mobile apps were released in March 2022), so you may discover some bugs and missing features. We would really appreciate if you let us know anything that needs to be fixed or improved.
The default servers configured in the app are provided on the best effort basis. We are currently not guaranteeing any SLAs, although historically our servers had over 99.9% uptime each.
We have never provided or have been requested access to our servers or any information from our servers by any third parties. If we are ever requested to provide such access or information, we will be following due legal process.
We do not log IP addresses of the users and we do not perform any traffic correlation on our servers. If transport level security is critical you must use Tor or some other similar network to access messaging servers. We will be improving the client applications to reduce the opportunities for traffic correlation.
Please read more in Privacy Policy.
Security contact
Please see our Security Policy on how to report security vulnerabilities to us. We will coordinate the fix and disclosure.
Please do NOT report security vulnerabilities via GitHub issues.
License
This software is licensed under the GNU Affero General Public License version 3 (AGPLv3). See the LICENSE file for details. The SimpleX and SimpleX Chat name, logo, associated branding materials, and application and website graphic assets (illustrations, images, visual designs, etc.) are not covered by this license and are subject to the terms outlined in the TRADEMARK and ASSETS_LICENSE files respectively.
If you want to use any graphic assets in your publications, please ask for permission. Texts can be used as direct quotes, referencing the source.








