You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jul 15, 2026. It is now read-only.
msgbrowse ingests contacts from multiple providers (Signal, iMessage, WhatsApp, and later Telegram). Today contacts and their identifiers live in the contacts + contact_identifiers tables (internal/store/schema.go; get-or-create linking in internal/store/store.go ~lines 180–194; per-source delete/cleanup in internal/store/sources.go). Linking across sources is implicit and there is no user-facing control over how the same real person's identities from different providers are merged or kept separate.
This epic introduces user-controlled cross-provider contact merging and de-duplication, backed by a pluggable address-book / contact-resolver abstraction so platform-specific integrations (macOS Contacts) can be swapped for a no-op on Linux.
Goals
Settings that control how contacts are merged across all providers (identifier matching rules, manual merge/split, overrides).
On iOS/macOS, reference the native Contacts app to help map identifiers to real people and de-duplicate. This is platform-specific and must not be a hard dependency elsewhere.
Because the Contacts integration is Mac-only, a pluggable/adaptable interface (ContactResolver / address-book provider) so Linux (and other platforms) supply a no-op or alternative implementation.
Design direction
Mirror the existing interface-injection seams in internal/web: SetDetector / SetEnabler / SetPairingSource with their Enabler / PairingSource interfaces (internal/web/enable.go, internal/web/settings.go), and the detector patterns in internal/setup. The desktop shell wires the real (macOS) implementation; tests and Linux wire fakes / no-ops.
Persistence builds on contacts + contact_identifiers; a merge likely needs a stable "canonical person" grouping plus manual override records that survive re-ingest.
Suggest a paired spec under docs/openspec/specs/contact-merge/ (spec.md + design.md) and an ADR (MADR) under docs/adr/ (next number is 0022). Related prior art: ADR-0011 (contact-facts-extraction), docs/openspec/specs/contact-facts.
Child issues
Pluggable ContactResolver / address-book interface + Linux no-op impl
Context / Problem
msgbrowse ingests contacts from multiple providers (Signal, iMessage, WhatsApp, and later Telegram). Today contacts and their identifiers live in the
contacts+contact_identifierstables (internal/store/schema.go; get-or-create linking ininternal/store/store.go~lines 180–194; per-source delete/cleanup ininternal/store/sources.go). Linking across sources is implicit and there is no user-facing control over how the same real person's identities from different providers are merged or kept separate.This epic introduces user-controlled cross-provider contact merging and de-duplication, backed by a pluggable address-book / contact-resolver abstraction so platform-specific integrations (macOS Contacts) can be swapped for a no-op on Linux.
Goals
ContactResolver/ address-book provider) so Linux (and other platforms) supply a no-op or alternative implementation.Design direction
internal/web:SetDetector/SetEnabler/SetPairingSourcewith theirEnabler/PairingSourceinterfaces (internal/web/enable.go,internal/web/settings.go), and the detector patterns ininternal/setup. The desktop shell wires the real (macOS) implementation; tests and Linux wire fakes / no-ops.contacts+contact_identifiers; a merge likely needs a stable "canonical person" grouping plus manual override records that survive re-ingest.docs/openspec/specs/contact-merge/(spec.md+design.md) and an ADR (MADR) underdocs/adr/(next number is 0022). Related prior art: ADR-0011 (contact-facts-extraction),docs/openspec/specs/contact-facts.Child issues
ContactResolver/ address-book interface + Linux no-op impl(Child issues are also attached as GitHub sub-issues; the checklist above mirrors them.)
Relevant code
internal/store/schema.go(contacts,contact_identifiers),internal/store/store.go(get-or-create linking),internal/store/sources.go(per-source cleanup/merge)internal/web/enable.go,internal/web/settings.go(seam patterns:Enabler,PairingSource,SetEnabler,SetPairingSource)internal/setup/(detector patterns)internal/facts/and ADR-0011 (adjacent contact work)