cloud-sync-module

Write, review, and debug CloudSyncDataManager modules that sync user data through Ledger Sync.

615|491|Updated Jan 4, 2022
One-click install
npx skills add https://github.com/LedgerHQ/ledger-live --skill cloud-sync-module
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: cloud-sync-module
Source: https://github.com/LedgerHQ/ledger-live/tree/main/.agents/skills/cloud-sync-module
Command: npx skills add https://github.com/LedgerHQ/ledger-live --skill cloud-sync-module

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve?

Writing a cloudSyncModule.ts for Ledger Sync involves subtle invariants around diffing, merging, and schema design; breaking any one of them causes infinite sync loops, silent data loss across a user's devices, or sync failures for unrelated modules. This Skill encodes the contract, the invariants, and the known traps so a module works correctly the first time.

Core Features & Use Cases

  • Contract guidance: Explains the three hooks (diffLocalToDistant, resolveIncrementalUpdate, applyUpdate), their sync/async constraints, and the six invariants (short-circuiting, stability, round-trip, convergence, purity) the sync loop depends on.
  • Data-loss risk checklist: Covers the traps that wipe or corrupt user data — persistence lifetime mismatches, strict schemas, discarded .transform() outputs, forbidden migrations, and payload privacy rules.
  • Testing and wiring: Provides the mandatory describeCloudSyncModuleContract test setup, module-specific test cases that catch what the contract suite misses, and the full registration checklist across walletSyncComposition.ts, both apps' reducers, useWatchWalletSync, and web-tools.
  • Use Case: When adding a new entity (e.g., a settings slice) that must sync between Ledger Wallet Desktop and Mobile, use this Skill to author the module, write its tests, and complete every registration site without missing the duplicated schema or the third web-tools registration.

Quick Start

Use the cloud-sync-module skill to write a new cloudSyncModule.ts for my entity and list every file I need to touch to register it.

Frequently Asked Questions about cloud-sync-module

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I write a cloudSyncModule.ts for Ledger Sync?

Implement the CloudSyncDataManager contract with three hooks: diffLocalToDistant, resolveIncrementalUpdate, and applyUpdate. Place it in domain/entity/<name>/src/ beside schema.ts and slice.ts, then run the mandatory describeCloudSyncModuleContract test and complete the wiring checklist.

Why does my Ledger Sync module cause an infinite sync loop?

Infinite loops happen when resolveIncrementalUpdate fails to short-circuit on content-equal incoming states, or when diffLocalToDistant is unstable (using Date.now(), random ids, or comparing fields applyUpdate cannot reproduce). Add a content-equality check and ensure re-diffing your own nextState reports no changes.

Can I use zod .transform() in a cloud sync schema?

You can, but the transform output is discarded in production: both parse call sites pass the raw JSON onward to preserve unknown fields. Hooks receive un-normalised data typed as the transform's output, so normalise inside the hooks instead of relying on the transform.

How do I add a new module to the wallet sync aggregator?

Register the key in createAggregator and the hand-maintained walletSyncSchema in walletSyncComposition.ts, add reducers and export/import handling in both apps' wallet reducers, update useWatchWalletSync in LWD and LWM, and register again in web-tools' AppAccountsSync.tsx.

Why did my cloud sync module delete user data on other devices?

This happens when LocalState is not persisted with the same lifetime as walletSyncState.version: after a restart the loop never pulls, and diffLocalToDistant pushes an empty state over the distant data. Wire exportWalletState and importWalletState so local state survives restarts.

What are the schema design rules for Ledger Sync modules?

Schemas must stay permissive: optional fields only, z.unknown() with safeParse-and-filter for lists, never .strict(). The wire format is permanent and shared across app versions, so never rename, repurpose, or require keys — there are no migrations.