Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Coin-specific families logic must live in families/. Generic UI uses the families contract only (no if (family === "evm") in shared code). Use this guidance for work in "**/families/**", "**/mvvm/**", "**/renderer/**" and "**/screens/**".
.claude/skills/ledgerhq-coin-families-contract/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 9% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 3% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 3% | 0% |
| case-07 | ✗→✓ | ▲ Improved | -7% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 17% | 0% |
Principle: Coin-specific UI and behavior must live in families/. Generic screens, hooks, and components must not branch on family === "evm" (or any family name). They must use the families contract: optional slots defined in the family type, implemented per family, and consumed via a single lookup (e.g. getLLDCoinFamily(currency.family).SlotName). This keeps generic code family-agnostic and supports modularisation and lazy loading.
families/<family>/):if (currency.family === "evm") / if (transaction.family === "solana") to render or behave differently.@ledgerhq/coin-canton) in generic UI to branch on that coin.invariant(transaction.family === "bitcoin", "...") in families/bitcoin/) is acceptable; the rule applies to generic (shared) code only.LLDCoinFamily in apps/ledger-live-desktop/src/renderer/families/types.ts (e.g. NoAssociatedAccounts?: React.ComponentType<...>).noAssociatedAccountsByFamily) that families can optionally fill.families/<family>/ (e.g. families/hedera/NoAssociatedAccounts.tsx) and export it from the family index (Desktop: in the object passed to generated; Mobile: in the generated aggregation if applicable).if (family === "hedera"):getLLDCoinFamily(currency.family).NoAssociatedAccounts → use it when defined.getCustomNoAssociatedAccounts(currency) returning a component from a family map, then pass it to the screen (e.g. as CustomNoAssociatedAccounts in route params).apps/ledger-live-desktop/src/renderer/families/types.ts — NoAssociatedAccounts?: React.ComponentType<AddAccountsStepProps> on LLDCoinFamily.
apps/ledger-live-desktop/src/renderer/families/hedera/NoAssociatedAccounts.tsx and hedera/index.ts exporting it in the family object.
StepImport.tsx / useScanAccounts.ts: getLLDCoinFamily(mainCurrency.family).NoAssociatedAccounts — no Hedera-specific branch.
useScanDeviceAccountsViewModel.ts: getCustomNoAssociatedAccounts(currency) from ~/generated/NoAssociatedAccounts; result passed as CustomNoAssociatedAccounts to the NoAssociatedAccounts screen. No if (family === "hedera") in the VM.
When you need new coin-specific behavior in a generic flow (e.g. post-add-account navigation, custom empty state): extend the contract (add a new optional slot and document it), implement it in the relevant family folder, and have the generic code only read from the contract. Do not add new if (family === "…") branches in shared UI.
apps/ledger-live-desktop/src/renderer/families/ — contract in types.ts, implementations per family, aggregation in generated.ts; generic code under renderer/, mvvm/.apps/ledger-live-mobile/src/families/ — family-specific UI and flows; generic code under mvvm/, screens/. Use generated maps or a small helper (e.g. getCustomNoAssociatedAccounts) so generic code never branches on family name.Other measured skills in the registry, with their headline benchmark lift.