Skip to content

Add Convos Vault plan: multi-device key sync via hidden conversation#555

Draft
yewreeka wants to merge 16 commits intodevfrom
jarod/convos-vault-plan
Draft

Add Convos Vault plan: multi-device key sync via hidden conversation#555
yewreeka wants to merge 16 commits intodevfrom
jarod/convos-vault-plan

Conversation

@yewreeka
Copy link
Copy Markdown
Contributor

@yewreeka yewreeka commented Mar 5, 2026

Add Convos Vault plan: multi-device key sync via hidden conversation

Specify conversationType in ConversationCustomMetadata protobuf for Vault identification

Store Vault key in iCloud Keychain by default, update recovery flows

Add manual Vault key backup requirement for non-Apple platforms

Redesign pairing flow: Device A confirms code from Device B, add vault merging and multi-device edge case

Use standard invite system for Vault pairing with 6-digit code verification gate

Set Vault pairing invite expiry to 60 seconds for full flow

Resolve key rotation question: revokeInstallations + MLS forward secrecy is sufficient

Track installation IDs alongside shared keys, defer selective revocation to future phase

Include device name in pairing join request, use as Vault profile display name

Add JoinRequest custom content type as phase 1 prerequisite with optional profile, device name, and confirmation code

Move deviceName and confirmationCode to JoinRequest metadata map

Remove DeviceKeyRequest: XMTP history sync handles recovery by replaying Vault messages

Set 10 device max matching XMTP installation limit

Acknowledge device compromise limitation, defer to future phase

Correct recovery section: XMTP history sync requires active installation

History sync replicates between live installations, not from an
archive. Single-device users who lose their only device cannot recover
Vault message history even with the Vault key.

Note

Add design document for Convos Vault multi-device key sync via hidden XMPP conversation

Adds convos-vault.md, a design plan for syncing end-to-end encryption keys across devices using a hidden XMTP "vault" conversation.

  • Defines the full device lifecycle: first install, pairing, key exchange, merge, and ongoing sync using custom XMTP content types (JoinRequest, DeviceKeyBundle, DeviceKeyShare)
  • Identifies the vault conversation via a conversationType: "vault" field in ConversationCustomMetadata protobuf
  • Covers recovery scenarios, offline behavior, locking, and device management
  • Documents resolved design decisions and one open question around key share expiry

Macroscope summarized e7a7b29.

yewreeka added 16 commits March 4, 2026 14:46
…onal profile, device name, and confirmation code
History sync replicates between live installations, not from an
archive. Single-device users who lose their only device cannot recover
Vault message history even with the Vault key.
Copy link
Copy Markdown
Contributor Author

yewreeka commented Mar 5, 2026


How to use the Graphite Merge Queue

Add the label merge-queue to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@claude
Copy link
Copy Markdown

claude Bot commented Mar 5, 2026

Claude finished @yewreeka's task —— View job


PR Review: Convos Vault Plan

I've reviewed the Convos Vault plan document. This is a well-structured design that thoughtfully addresses multi-device key sync for Convos' unique per-conversation identity architecture. Below is my detailed feedback.


✅ Strengths

1. Architecture & XMTP Integration

  • Clever reuse of XMTP group conversations as the sync mechanism — leverages existing MLS encryption and message infrastructure
  • conversationType field in protobuf (field 6) is the right approach for identifying Vault conversations after sync
  • Reuses existing invite system (ConvosInvites package) with minimal additions — good engineering economy
  • Vault locking mechanism reuses existing lock/unlock infrastructure

2. Security Model

  • End-to-end encryption via XMTP MLS keeps key material away from any server
  • 6-digit confirmation code with physical device access requirement provides strong pairing security
  • 60-second invite expiry limits attack window
  • Device compromise acknowledgment is realistic — full key rotation is complex and appropriately deferred

3. Recovery & Platform Support

  • iCloud Keychain for Apple platforms is the right default (automatic, secure)
  • Explicit requirement for manual backup on non-Apple platforms shows good cross-platform thinking
  • Recovery section correctly identifies XMTP history sync limitation (requires active installation)

4. Future Extensions

  • IAP credits ledger is a clever use of the Vault infrastructure
  • Preferences sync is a natural extension

🔍 Issues & Concerns

1. Protobuf Schema Conflict (Critical)

The plan shows conversationType as field 6 in ConversationCustomMetadata:

optional string conversationType = 6;  // "vault" for Convos Vault

However, the actual protobuf file (ConvosAppData/Sources/ConvosAppData/Proto/conversation_custom_metadata.proto) currently only has 5 fields:

message ConversationCustomMetadata {
    string tag = 1;
    repeated ConversationProfile profiles = 2;
    optional sfixed64 expiresAtUnix = 3;
    optional bytes imageEncryptionKey = 4;
    optional EncryptedImageRef encryptedGroupImage = 5;
}

Field 6 is available and the plan is correct, but this needs to be implemented as part of the Vault work. The plan should explicitly call this out as a prerequisite change to the protobuf schema.

Recommendation: Add a "Phase 1 Prerequisites" section listing:

  • Add conversationType field to ConversationCustomMetadata protobuf
  • Implement JoinRequest custom content type (already mentioned but should be grouped with other prereqs)

2. JoinRequest Content Type Design (Moderate)

The metadata map approach for Vault-specific fields is flexible but has trade-offs:

| metadata | map | no | Extensible key-value pairs for context-specific data |

Concerns:

  • Type safety: Metadata is string→string, so confirmationCode is a string "123456" rather than a typed integer
  • No compile-time validation of required Vault fields (deviceName, confirmationCode)
  • Discovery: Other engineers won't easily know what metadata keys exist without reading docs

Alternative: Consider a oneof union type in the protobuf:

message JoinRequest {
    string inviteSlug = 1;
    optional Profile profile = 2;
    oneof context {
        VaultPairingContext vault = 3;
        // Future contexts here
    }
}

message VaultPairingContext {
    string deviceName = 1;
    string confirmationCode = 2;  // 6 digits
}

Pros: Type-safe, self-documenting, compile-time validation
Cons: Less flexible for ad-hoc extensions

If sticking with metadata map, at least define constants:

enum JoinRequestMetadataKey {
    static let deviceName = "deviceName"
    static let confirmationCode = "confirmationCode"
}

3. Recovery Limitations Not Prominent Enough (Moderate)

The recovery section (lines 173-193) correctly explains that single-device users who lose their only device cannot recover, even with the Vault key. This is a critical limitation that could lead to catastrophic data loss.

Issue: This limitation is buried in the "Recovery" section. Users may:

  • Enable Vault thinking it provides full backup/recovery
  • Not understand they need a second device for true recovery
  • Lose all conversations after a device failure

Recommendations:

  1. Onboarding UI warning: "Vault syncs keys between devices, but does not back up your conversations. Keep at least 2 devices paired for recovery protection."
  2. Single-device detection: If user has only 1 device after 7+ days, show persistent warning: "Pair a second device to protect against data loss"
  3. Update plan section 1: Add explicit warning in "First device install" section about backup limitations

4. Vault Merging UX Complexity (Moderate)

The Vault merging flow (lines 89-106) requires Device B to:

  1. Check if it's the sole member of its Vault
  2. Show error if other devices exist
  3. Force user to unpair all other devices first
  4. Then proceed with pairing

Edge case: User has:

  • Device B with devices C, D, E already paired in its Vault
  • Wants to pair B with Device A

They must:

  1. Unpair C, D, E from B's Vault
  2. Pair B with A
  3. Re-pair C, D, E individually with A

This is tedious for users with multiple devices.

Alternative approach: Support "full Vault migration":

  1. Device B provides list of all members in its Vault (C, D, E)
  2. Device A's owner confirms: "Add 3 devices from Device B's Vault?"
  3. A sends Vault invites to C, D, E with a special "migration" flag
  4. C, D, E auto-accept and join A's Vault
  5. B's old Vault is abandoned

Pros: Better UX for multi-device users
Cons: More complex pairing flow, potential security implications (auto-accept)

At minimum, document this UX complexity in the plan as a known limitation.


5. Installation ID Tracking Not Fully Specified (Minor)

The plan mentions tracking installation IDs (lines 224-225):

When a device shares a conversation key (via DeviceKeyBundle or DeviceKeyShare), it also includes the installation ID it created for that conversation.

Missing details:

  • How are installation IDs stored? New protobuf fields in DeviceKeyBundle/DeviceKeyShare?
  • Where is the device→installation mapping persisted? Local database? Vault message?
  • How is this mapping updated when new installations are created?

Recommendation: Add a "Content Type Schemas" section with full protobuf definitions:

message DeviceKeyBundle {
    repeated ConversationKey keys = 1;
}

message DeviceKeyShare {
    ConversationKey key = 1;
}

message ConversationKey {
    string conversationId = 1;
    bytes privateKey = 2;
    string installationId = 3;  // XMTP installation ID
    sfixed64 sharedAtUnix = 4;
}

6. 10-Device Limit Enforcement (Minor)

Line 226: "The Vault UI should enforce this limit and show an error when attempting to pair an 11th device."

Questions:

  • Does XMTP's 10-installation limit apply per-inbox or per-conversation?
  • If Device A has 10 installations across all conversations, can it still create an 11th for a new conversation?
  • How does the app detect this limit before attempting to add a device?

XMTP Context Needed: Verify whether the 10-installation limit is:

  • Global per inbox (all conversations share the limit)
  • Per conversation (each conversation has 10 installation slots)

This affects whether Vault membership is practically limited or not.


7. Explode/Expiry Exemption Incomplete (Minor)

Open question #1 (line 230): "The Vault conversation should probably not have an expiry timer."

Additional consideration: Vault should also be exempt from:

  • Message explode feature (ADR 004) — Vault messages must persist indefinitely
  • Conversation deletion UI — Vault shouldn't appear in delete conversation flows
  • Message limits — If the app limits message history, Vault should be unlimited

Recommendation: Add explicit exemptions for Vault in the plan:

  • No expiry timer
  • No explode functionality
  • No deletion from conversation list
  • No message history limits

🎯 Recommendations Summary

Priority Item Action
P0 Protobuf schema Add conversationType field to schema; list as Phase 1 prerequisite
P0 Recovery warning Add prominent warning in onboarding and for single-device users
P1 JoinRequest type safety Use oneof or define metadata key constants
P1 Installation tracking Specify protobuf schema for DeviceKeyBundle/DeviceKeyShare
P2 Vault merging UX Document tedious re-pairing flow; consider migration alternative
P2 10-device limit Clarify XMTP limit scope (per-inbox vs per-conversation)
P2 Vault exemptions Explicitly list all feature exemptions (explode, delete, limits)

📋 Missing Sections (Optional Enhancements)

  1. Testing Strategy

    • How to test pairing flow (need 2 devices or simulator instances)
    • Mock XMTP network for unit tests
    • Vault merging edge case tests
  2. Error Handling

    • Pairing timeout (invite expires mid-flow)
    • Network failure during key exchange
    • Corrupted key bundle recovery
  3. Performance Considerations

    • Size of DeviceKeyBundle with 100+ conversations
    • Message load time for Vault conversation
    • Key import performance on new device
  4. Migration Path

    • How do existing Convos users adopt Vault?
    • Retroactive key distribution for existing conversations
    • Versioning if Vault protocol changes

✨ Overall Assessment

This is a strong, well-thought-out plan that elegantly solves multi-device key sync within Convos' unique architecture. The reuse of XMTP infrastructure and existing invite system shows good engineering judgment.

Main gaps:

  • Protobuf schema changes need explicit prerequisites
  • Recovery limitations need more prominent user-facing warnings
  • Some technical details (installation tracking, content type schemas) need fleshing out

Recommendation: Address P0 items before implementation begins. P1/P2 items can be resolved during detailed design phase.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant