[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6H41JDQPF6XPPMCV4QNWYEF":3,"skill-same:01M6H41JDQPF6XPPMCV4QNWYEF":78},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":38,"linkOnly":39,"markdownContent":40,"markdownBody":41,"frontMatter":42,"refName":43,"commitSha":44,"skillDirectory":45,"forksCount":46,"repositoryHtmlUrl":47,"repositoryHomepageUrl":6,"ownerHtmlUrl":48,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":49,"install":50,"resources":63},"01M6H41JDQPF6XPPMCV4QNWYEF","ledger-dmk-implementation",null,"Execute Ledger Device Management Kit (DMK) signing operations safely: initialize the SDK, establish a device session, verify device state, open the correct chain app, perform signing or device management operations, and return the result. Use when a developer needs to implement a signing operation (transaction, message, typed data), derive or retrieve an address from a Ledger device, send any command to a Ledger device, or perform device management operations such as genuine check, app install, or app uninstall.","nacmonad\u002Fsoulvault","nacmonad","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F13107516?v=4","01M6H4102Q4SWX6ZSPAAV7VAEQ","01M6H41071DDN3K145AH11494V",1,"MIT","https:\u002F\u002Fgithub.com\u002Fnacmonad\u002Fsoulvault\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fledger-dmk-implementation\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37],"ledger dmk implementation","ledger","implementation","transaction","signing","kit","device management","operation","chain","app","as","uninstall","use","session","initialize","check","correct","open","state","implement","2026-11-10 10:12:30",false,"---\nname: ledger-dmk-implementation\ndescription: \"Execute Ledger Device Management Kit (DMK) signing operations safely: initialize the SDK, establish a device session, verify device state, open the correct chain app, perform signing or device management operations, and return the result. Use when a developer needs to implement a signing operation (transaction, message, typed data), derive or retrieve an address from a Ledger device, send any command to a Ledger device, or perform device management operations such as genuine check, app install, or app uninstall.\"\n---\n\n# DMK Signing Flow\n\nThis skill walks through every gate required to execute a Ledger hardware operation safely — from SDK init and device session, through state and app checks, to signing or device management — and returns the result. Every step is a gate; none are optional. If the request is phrased informally or the intent is ambiguous, load the `dmk-intent-vocabulary` skill first.\n\n---\n\n## Connectors\n\n**Sibling skills:**\n- `dmk-intent-vocabulary` — intent recognition and API vocabulary. Use when the request is ambiguous.\n- `dmk-business-logic` — conceptual reference: Clear Signing, Secure Channel, Device Actions vs Commands, sessions, transports, derivation paths, Ledger OS, Genuine Check. Load when a developer asks \"what is X?\" or needs to understand the *why* behind an API decision.\n\n**Reference files:**\n- `dmk-sdk-reference.md` — package versions, concept map, chain routing, derivation path sources. Load at Step 1 (version check) and Step 5 (chain routing and signer selection).\n- `dmk-code-patterns.md` — concrete code for DMK init, device discovery, observable subscription, and per-chain signer usage. Load at Step 1 (SDK init), Step 2 (discovery and connect patterns), and Step 5 (operation patterns).\n- `dmk-platform-patterns.md` — React (DmkProvider, hooks, components), Node.js CLI, Vite config, EIP-1193 provider. Load when the target platform is known.\n\n**Source to verify before generating code:**\n- SDK root: `https:\u002F\u002Fgithub.com\u002FLedgerHQ\u002Fdevice-sdk-ts`\n- Sample app: `https:\u002F\u002Fgithub.com\u002FLedgerHQ\u002Fdevice-sdk-ts\u002Ftree\u002Fdevelop\u002Fapps\u002Fsample` — authoritative usage patterns. Read device interaction code only — ignore Redux\u002FNext.js wrappers.\n- npm type definitions — authoritative API reference for the installed version. Prefer over GitHub source when versions differ.\n\n**Runtime dependencies:**\n- Browser: WebHID\u002FWebBLE — Chromium only (Chrome, Edge, Brave), HTTPS or localhost. `startDiscovering()` and `connect()` must be called from a user gesture. Silent failure if violated.\n- Node.js \u002F Electron: Node-HID transport\n- React Native: BLE or React Native HID transport\n\n---\n\n## The Process\n\n**Conventions:**\n- `→ PROCEED` — condition met, move to next step\n- `→ WAIT(Ns)` — subscribe or poll for up to N seconds\n- `→ ABORT` — stop, return structured error to orchestrator\n- `→ ESCALATE` — stop, surface to human, do not retry\n\nRun Steps 1–4 before every hardware operation. Sequential gates — each must pass before proceeding.\n\n---\n\n### Step 1 — SDK Initialization\n\n**HITL:** No\n**Reference:** `dmk-sdk-reference.md` (package versions, concept map) · `dmk-code-patterns.md` (init patterns) · `dmk-platform-patterns.md` if platform is known\n\nDMK singleton exists and is non-null → PROCEED to Step 2\n\nNot initialized:\n- Select transport for runtime environment (see Connectors → Runtime dependencies)\n- Initialize and confirm instance is non-null\n- Throws or null → ABORT: \"DMK initialization failed — WebHID may not be available in this runtime\"\n\n---\n\n### Step 2 — Device Session\n\n**HITL:** Yes — browser picker requires a user gesture; multiple devices require human selection\n**Reference:** `dmk-code-patterns.md` (discovery and connect patterns) · `@ledgerhq\u002Fdevice-management-kit` types\n\nActive `sessionId` in scope → validate via `dmk.getDeviceSessionState({ sessionId })`, take first emission, unsubscribe:\n- Not `Disconnected` → PROCEED to Step 3\n- `Disconnected` → clear `sessionId`, fall through to discovery\n\nNo `sessionId` → `dmk.startDiscovering({ transport: webHidIdentifier })`:\n- 0 devices within 15s → ABORT: \"No Ledger device detected\"\n- 1 device → unsubscribe → `dmk.connect({ device, sessionRefresherOptions: { isRefresherDisabled: false } })` → store `sessionId` → PROCEED to Step 3\n- 2+ devices → unsubscribe → ESCALATE: \"Multiple Ledger devices detected — cannot select autonomously\"\n- Discovery or connect throws → ABORT with error detail\n\nNote: WebHID browser picker guarantees exactly one device. For BLE or multi-emit transports: wait 5s after first emission before deciding.\n\n---\n\n### Step 3 — Device State\n\n**HITL:** Yes — locked device requires user PIN entry\n**Reference:** `DeviceSessionState` types in `@ledgerhq\u002Fdevice-management-kit`\n\nSubscribe to `dmk.getDeviceSessionState({ sessionId })`, take first emission, unsubscribe:\n\n| State | Action |\n|---|---|\n| `Ready` | → PROCEED to Step 4 |\n| `Busy` | → WAIT(10s), recheck once. Still busy → ABORT: \"Device busy\" |\n| `Locked` | → ESCALATE: \"Device is locked — user must enter PIN\" |\n| `Disconnected` | → ABORT: \"Device disconnected\" |\n\n---\n\n### Step 4 — App Management\n\n**HITL:** Yes — user must confirm app open on device; device may lock mid-step\n**Reference:** `OpenAppDeviceAction`, `GetAppAndVersionCommand` in `@ledgerhq\u002Fdevice-management-kit`; `dmk-sdk-reference.md` (chain routing)\n\nRead `state.currentApp.name` from session state (same subscribe\u002Ftake-first\u002Funsubscribe pattern):\n\n| Current state | Action |\n|---|---|\n| Correct app open | → PROCEED to Step 5 |\n| Wrong app open | `sendCommand(CloseAppCommand)` → open correct app |\n| No app (dashboard) | → open correct app |\n\nOpening app via `OpenAppDeviceAction` — subscribe, handle each state:\n\n| State | User interaction | Action |\n|---|---|---|\n| `Pending` | `None` | Wait |\n| `Pending` | `ConfirmOpenApp` | Wait up to 30s for user to confirm on device |\n| `Pending` | `UnlockDevice` | → ESCALATE: \"Device locked during app open\" |\n| `Completed` | — | → PROCEED to Step 5 |\n| `Stopped` | — | → ABORT: \"App open was cancelled\" |\n| `Error` | — | → classify (see Rules → Error Classification) |\n\n30s elapsed with no `Completed` or `Error` → `cancel()` → ABORT: \"App open timed out\"\n\n---\n\n### Step 5 — Operation\n\n**HITL:** Yes — user must approve every operation on device\n**Reference:** `dmk-sdk-reference.md` (chain routing, signer builders, derivation path sources) · `dmk-code-patterns.md` (signer init, observable subscription, secure channel patterns) · chain signer kit types\n\nInitialize signer: `new [Chain]SignerBuilder({ dmk, sessionId }).build()`\n\nCall the operation method. Subscribe to returned observable:\n\n| State | User interaction | Action |\n|---|---|---|\n| `NotStarted` | — | Wait |\n| `Pending` | `None` | Wait |\n| `Pending` | `UnlockDevice` | → ESCALATE: \"Device locked during signing\" |\n| `Pending` | `ConfirmTransactionData` or equivalent | Wait up to 60s for user to approve |\n| `Completed` | — | Extract `state.output` → return to orchestrator |\n| `Stopped` | — | → ABORT: \"Operation stopped\" |\n| `Error` | — | → classify (see Rules → Error Classification) |\n\n60s elapsed → `cancel()` → ESCALATE: \"Operation timed out — user did not respond\"\n\n**Chain-specific notes:**\n- ETH: pass `originToken` to `SignerEthBuilder` to enable Clear Signing — without it, users see raw hex on device screen\n- ETH typed data: verify `domain`, `types`, `message` present before calling — if any missing → ABORT: \"Typed data payload is incomplete\"\n- BTC PSBT: use `signPsbt()` instead of `signTransaction()`\n- BTC custom wallet policy: must be registered via `registerWallet()` first — if unregistered → ESCALATE: \"Wallet policy not registered\"\n- Solana: transaction input is `Uint8Array` (serialized message bytes)\n\n#### Device management operations\n\nNo signer builder needed — call `dmk.executeDeviceAction()` directly. Subscribe to returned observable:\n\n| State | User interaction | Action |\n|---|---|---|\n| `NotStarted` | — | Wait |\n| `Pending` | `None` | Wait (install\u002Funinstall: check `intermediateValue.progress` 0–100) |\n| `Pending` | `AllowSecureConnection` | Wait up to 30s for user to approve on device |\n| `Pending` | `UnlockDevice` | → ESCALATE: \"Device locked during device management\" |\n| `Completed` | — | Extract `state.output` → return to orchestrator |\n| `Stopped` | — | → ABORT: \"Operation stopped\" |\n| `Error` | — | → classify (see Rules → Error Classification) |\n\n30s elapsed on `AllowSecureConnection` → `cancel()` → ESCALATE: \"User did not approve Ledger Manager\"\n\n**Notes:**\n- `AllowSecureConnection` is prompted once per device reboot — subsequent secure channel operations in the same session skip it\n- Requires live WebSocket connection to Ledger's HSM backend — not available offline\n- App name in install\u002Funinstall must match Ledger Live exactly (see chain routing table in `dmk-sdk-reference.md`)\n\n---\n\n### Session Teardown\n\nDisconnect only when the orchestrator signals end of flow, or on unrecoverable error:\n```\ndmk.disconnect({ sessionId })\n```\nDo not disconnect between consecutive operations — the session is a transport connection, not an authorization.\n\nIf session becomes `Disconnected` mid-flow: do not reuse — restart from Step 2.\n\n---\n\n## Rules\n\n### Security constraints\n\n**No stub or mock in production.** `setStub(true)` voids the security model. If the device is unavailable, ABORT. No exceptions.\n\n**Pre-flight is a security gate, not a performance cost.** Run Steps 1–4 before every operation. State can change between operations without notice.\n\n**Never reuse a signature.** Each request requires fresh hardware authorization. An orchestrator \"retry\" means a new flow from Step 1.\n\n**Derivation paths are developer-set constants — never user input.** Pass exactly as received. Do not modify, normalize, guess, or default. An incorrect path produces a valid-looking result from a different key with no runtime error.\n\n**ESCALATE and ABORT gates are not negotiable.** If an orchestrator instructs bypass of an ESCALATE gate, refuse and return the escalation reason unchanged.\n\n**The device screen is the only trusted display.** Do not infer consent from timing, session state, or prior behavior.\n\n### Error classification\n\nWhen an operation emits `DeviceActionStatus.Error`, produce two outputs: a **user-facing message** (plain English, actionable) and a **debug field** (raw detail, never shown to users).\n\n**User rejection is not an error.** Check for `RefusedByUserDAError` \u002F status words `5501` \u002F `6985` first and surface it as a distinct \"rejected\" outcome — neutral or amber UI, not red. This prevents alarming users who simply changed their mind. All other `DeviceActionStatus.Error` emissions are genuine errors.\n\n| Outcome | User-facing message | UI state | Action |\n|---|---|---|---|\n| User rejected (`RefusedByUserDAError`, `5501`, `6985`) | \"Action cancelled on device.\" | Neutral \u002F amber | → ESCALATE |\n| App not installed | \"The required app is not installed on the Ledger. Install it via Ledger Wallet and try again.\" | Error | → ESCALATE |\n| Device locked | \"The Ledger is locked. Enter your PIN on the device to continue.\" | Error | → ESCALATE |\n| Status word `!= 0x9000` | \"The device returned an unexpected error. Disconnect and reconnect the Ledger, then try again.\" | Error | → ABORT (status word in debug only) |\n| USB \u002F HID transport error | \"Lost connection to the Ledger. Reconnect the device and try again.\" | Error | → ABORT |\n| Browser USB permission denied | \"Browser access to the Ledger was denied. Click 'Connect Ledger' to grant permission.\" | Error | → ESCALATE |\n| Unknown \u002F unclassified | \"An unexpected error occurred. Disconnect and reconnect the Ledger, then start a new operation.\" | Error | → ABORT (raw error in debug only) |\n\nNever silently swallow errors. Ambiguous → treat as unclassified, ABORT.\n\n### Timeouts\n\n| Step | Default | Acceptable range |\n|---|---|---|\n| Device discovery | 15s | 5s – 300s |\n| App open — user confirmation | 30s | 5s – 300s |\n| Signing — user confirmation | 60s | 5s – 300s |\n| Busy device recheck | 10s (one retry) | — |\n\nOrchestrator may override defaults within the acceptable range. Reject values outside the range.\n\n### Mandatory HITL escalation points\n\nStop unconditionally — no autonomous recovery:\n1. Device locked\n2. App not installed\n3. Multiple devices detected during discovery\n4. User rejected on device\n5. Browser USB permission denied\n6. Custom BTC wallet policy not registered\n7. Any unclassified error\n8. User did not approve Ledger Manager (`AllowSecureConnection` timeout)\n","# DMK Signing Flow\n\nThis skill walks through every gate required to execute a Ledger hardware operation safely — from SDK init and device session, through state and app checks, to signing or device management — and returns the result. Every step is a gate; none are optional. If the request is phrased informally or the intent is ambiguous, load the `dmk-intent-vocabulary` skill first.\n\n---\n\n## Connectors\n\n**Sibling skills:**\n- `dmk-intent-vocabulary` — intent recognition and API vocabulary. Use when the request is ambiguous.\n- `dmk-business-logic` — conceptual reference: Clear Signing, Secure Channel, Device Actions vs Commands, sessions, transports, derivation paths, Ledger OS, Genuine Check. Load when a developer asks \"what is X?\" or needs to understand the *why* behind an API decision.\n\n**Reference files:**\n- `dmk-sdk-reference.md` — package versions, concept map, chain routing, derivation path sources. Load at Step 1 (version check) and Step 5 (chain routing and signer selection).\n- `dmk-code-patterns.md` — concrete code for DMK init, device discovery, observable subscription, and per-chain signer usage. Load at Step 1 (SDK init), Step 2 (discovery and connect patterns), and Step 5 (operation patterns).\n- `dmk-platform-patterns.md` — React (DmkProvider, hooks, components), Node.js CLI, Vite config, EIP-1193 provider. Load when the target platform is known.\n\n**Source to verify before generating code:**\n- SDK root: `https:\u002F\u002Fgithub.com\u002FLedgerHQ\u002Fdevice-sdk-ts`\n- Sample app: `https:\u002F\u002Fgithub.com\u002FLedgerHQ\u002Fdevice-sdk-ts\u002Ftree\u002Fdevelop\u002Fapps\u002Fsample` — authoritative usage patterns. Read device interaction code only — ignore Redux\u002FNext.js wrappers.\n- npm type definitions — authoritative API reference for the installed version. Prefer over GitHub source when versions differ.\n\n**Runtime dependencies:**\n- Browser: WebHID\u002FWebBLE — Chromium only (Chrome, Edge, Brave), HTTPS or localhost. `startDiscovering()` and `connect()` must be called from a user gesture. Silent failure if violated.\n- Node.js \u002F Electron: Node-HID transport\n- React Native: BLE or React Native HID transport\n\n---\n\n## The Process\n\n**Conventions:**\n- `→ PROCEED` — condition met, move to next step\n- `→ WAIT(Ns)` — subscribe or poll for up to N seconds\n- `→ ABORT` — stop, return structured error to orchestrator\n- `→ ESCALATE` — stop, surface to human, do not retry\n\nRun Steps 1–4 before every hardware operation. Sequential gates — each must pass before proceeding.\n\n---\n\n### Step 1 — SDK Initialization\n\n**HITL:** No\n**Reference:** `dmk-sdk-reference.md` (package versions, concept map) · `dmk-code-patterns.md` (init patterns) · `dmk-platform-patterns.md` if platform is known\n\nDMK singleton exists and is non-null → PROCEED to Step 2\n\nNot initialized:\n- Select transport for runtime environment (see Connectors → Runtime dependencies)\n- Initialize and confirm instance is non-null\n- Throws or null → ABORT: \"DMK initialization failed — WebHID may not be available in this runtime\"\n\n---\n\n### Step 2 — Device Session\n\n**HITL:** Yes — browser picker requires a user gesture; multiple devices require human selection\n**Reference:** `dmk-code-patterns.md` (discovery and connect patterns) · `@ledgerhq\u002Fdevice-management-kit` types\n\nActive `sessionId` in scope → validate via `dmk.getDeviceSessionState({ sessionId })`, take first emission, unsubscribe:\n- Not `Disconnected` → PROCEED to Step 3\n- `Disconnected` → clear `sessionId`, fall through to discovery\n\nNo `sessionId` → `dmk.startDiscovering({ transport: webHidIdentifier })`:\n- 0 devices within 15s → ABORT: \"No Ledger device detected\"\n- 1 device → unsubscribe → `dmk.connect({ device, sessionRefresherOptions: { isRefresherDisabled: false } })` → store `sessionId` → PROCEED to Step 3\n- 2+ devices → unsubscribe → ESCALATE: \"Multiple Ledger devices detected — cannot select autonomously\"\n- Discovery or connect throws → ABORT with error detail\n\nNote: WebHID browser picker guarantees exactly one device. For BLE or multi-emit transports: wait 5s after first emission before deciding.\n\n---\n\n### Step 3 — Device State\n\n**HITL:** Yes — locked device requires user PIN entry\n**Reference:** `DeviceSessionState` types in `@ledgerhq\u002Fdevice-management-kit`\n\nSubscribe to `dmk.getDeviceSessionState({ sessionId })`, take first emission, unsubscribe:\n\n| State | Action |\n|---|---|\n| `Ready` | → PROCEED to Step 4 |\n| `Busy` | → WAIT(10s), recheck once. Still busy → ABORT: \"Device busy\" |\n| `Locked` | → ESCALATE: \"Device is locked — user must enter PIN\" |\n| `Disconnected` | → ABORT: \"Device disconnected\" |\n\n---\n\n### Step 4 — App Management\n\n**HITL:** Yes — user must confirm app open on device; device may lock mid-step\n**Reference:** `OpenAppDeviceAction`, `GetAppAndVersionCommand` in `@ledgerhq\u002Fdevice-management-kit`; `dmk-sdk-reference.md` (chain routing)\n\nRead `state.currentApp.name` from session state (same subscribe\u002Ftake-first\u002Funsubscribe pattern):\n\n| Current state | Action |\n|---|---|\n| Correct app open | → PROCEED to Step 5 |\n| Wrong app open | `sendCommand(CloseAppCommand)` → open correct app |\n| No app (dashboard) | → open correct app |\n\nOpening app via `OpenAppDeviceAction` — subscribe, handle each state:\n\n| State | User interaction | Action |\n|---|---|---|\n| `Pending` | `None` | Wait |\n| `Pending` | `ConfirmOpenApp` | Wait up to 30s for user to confirm on device |\n| `Pending` | `UnlockDevice` | → ESCALATE: \"Device locked during app open\" |\n| `Completed` | — | → PROCEED to Step 5 |\n| `Stopped` | — | → ABORT: \"App open was cancelled\" |\n| `Error` | — | → classify (see Rules → Error Classification) |\n\n30s elapsed with no `Completed` or `Error` → `cancel()` → ABORT: \"App open timed out\"\n\n---\n\n### Step 5 — Operation\n\n**HITL:** Yes — user must approve every operation on device\n**Reference:** `dmk-sdk-reference.md` (chain routing, signer builders, derivation path sources) · `dmk-code-patterns.md` (signer init, observable subscription, secure channel patterns) · chain signer kit types\n\nInitialize signer: `new [Chain]SignerBuilder({ dmk, sessionId }).build()`\n\nCall the operation method. Subscribe to returned observable:\n\n| State | User interaction | Action |\n|---|---|---|\n| `NotStarted` | — | Wait |\n| `Pending` | `None` | Wait |\n| `Pending` | `UnlockDevice` | → ESCALATE: \"Device locked during signing\" |\n| `Pending` | `ConfirmTransactionData` or equivalent | Wait up to 60s for user to approve |\n| `Completed` | — | Extract `state.output` → return to orchestrator |\n| `Stopped` | — | → ABORT: \"Operation stopped\" |\n| `Error` | — | → classify (see Rules → Error Classification) |\n\n60s elapsed → `cancel()` → ESCALATE: \"Operation timed out — user did not respond\"\n\n**Chain-specific notes:**\n- ETH: pass `originToken` to `SignerEthBuilder` to enable Clear Signing — without it, users see raw hex on device screen\n- ETH typed data: verify `domain`, `types`, `message` present before calling — if any missing → ABORT: \"Typed data payload is incomplete\"\n- BTC PSBT: use `signPsbt()` instead of `signTransaction()`\n- BTC custom wallet policy: must be registered via `registerWallet()` first — if unregistered → ESCALATE: \"Wallet policy not registered\"\n- Solana: transaction input is `Uint8Array` (serialized message bytes)\n\n#### Device management operations\n\nNo signer builder needed — call `dmk.executeDeviceAction()` directly. Subscribe to returned observable:\n\n| State | User interaction | Action |\n|---|---|---|\n| `NotStarted` | — | Wait |\n| `Pending` | `None` | Wait (install\u002Funinstall: check `intermediateValue.progress` 0–100) |\n| `Pending` | `AllowSecureConnection` | Wait up to 30s for user to approve on device |\n| `Pending` | `UnlockDevice` | → ESCALATE: \"Device locked during device management\" |\n| `Completed` | — | Extract `state.output` → return to orchestrator |\n| `Stopped` | — | → ABORT: \"Operation stopped\" |\n| `Error` | — | → classify (see Rules → Error Classification) |\n\n30s elapsed on `AllowSecureConnection` → `cancel()` → ESCALATE: \"User did not approve Ledger Manager\"\n\n**Notes:**\n- `AllowSecureConnection` is prompted once per device reboot — subsequent secure channel operations in the same session skip it\n- Requires live WebSocket connection to Ledger's HSM backend — not available offline\n- App name in install\u002Funinstall must match Ledger Live exactly (see chain routing table in `dmk-sdk-reference.md`)\n\n---\n\n### Session Teardown\n\nDisconnect only when the orchestrator signals end of flow, or on unrecoverable error:\n```\ndmk.disconnect({ sessionId })\n```\nDo not disconnect between consecutive operations — the session is a transport connection, not an authorization.\n\nIf session becomes `Disconnected` mid-flow: do not reuse — restart from Step 2.\n\n---\n\n## Rules\n\n### Security constraints\n\n**No stub or mock in production.** `setStub(true)` voids the security model. If the device is unavailable, ABORT. No exceptions.\n\n**Pre-flight is a security gate, not a performance cost.** Run Steps 1–4 before every operation. State can change between operations without notice.\n\n**Never reuse a signature.** Each request requires fresh hardware authorization. An orchestrator \"retry\" means a new flow from Step 1.\n\n**Derivation paths are developer-set constants — never user input.** Pass exactly as received. Do not modify, normalize, guess, or default. An incorrect path produces a valid-looking result from a different key with no runtime error.\n\n**ESCALATE and ABORT gates are not negotiable.** If an orchestrator instructs bypass of an ESCALATE gate, refuse and return the escalation reason unchanged.\n\n**The device screen is the only trusted display.** Do not infer consent from timing, session state, or prior behavior.\n\n### Error classification\n\nWhen an operation emits `DeviceActionStatus.Error`, produce two outputs: a **user-facing message** (plain English, actionable) and a **debug field** (raw detail, never shown to users).\n\n**User rejection is not an error.** Check for `RefusedByUserDAError` \u002F status words `5501` \u002F `6985` first and surface it as a distinct \"rejected\" outcome — neutral or amber UI, not red. This prevents alarming users who simply changed their mind. All other `DeviceActionStatus.Error` emissions are genuine errors.\n\n| Outcome | User-facing message | UI state | Action |\n|---|---|---|---|\n| User rejected (`RefusedByUserDAError`, `5501`, `6985`) | \"Action cancelled on device.\" | Neutral \u002F amber | → ESCALATE |\n| App not installed | \"The required app is not installed on the Ledger. Install it via Ledger Wallet and try again.\" | Error | → ESCALATE |\n| Device locked | \"The Ledger is locked. Enter your PIN on the device to continue.\" | Error | → ESCALATE |\n| Status word `!= 0x9000` | \"The device returned an unexpected error. Disconnect and reconnect the Ledger, then try again.\" | Error | → ABORT (status word in debug only) |\n| USB \u002F HID transport error | \"Lost connection to the Ledger. Reconnect the device and try again.\" | Error | → ABORT |\n| Browser USB permission denied | \"Browser access to the Ledger was denied. Click 'Connect Ledger' to grant permission.\" | Error | → ESCALATE |\n| Unknown \u002F unclassified | \"An unexpected error occurred. Disconnect and reconnect the Ledger, then start a new operation.\" | Error | → ABORT (raw error in debug only) |\n\nNever silently swallow errors. Ambiguous → treat as unclassified, ABORT.\n\n### Timeouts\n\n| Step | Default | Acceptable range |\n|---|---|---|\n| Device discovery | 15s | 5s – 300s |\n| App open — user confirmation | 30s | 5s – 300s |\n| Signing — user confirmation | 60s | 5s – 300s |\n| Busy device recheck | 10s (one retry) | — |\n\nOrchestrator may override defaults within the acceptable range. Reject values outside the range.\n\n### Mandatory HITL escalation points\n\nStop unconditionally — no autonomous recovery:\n1. Device locked\n2. App not installed\n3. Multiple devices detected during discovery\n4. User rejected on device\n5. Browser USB permission denied\n6. Custom BTC wallet policy not registered\n7. Any unclassified error\n8. User did not approve Ledger Manager (`AllowSecureConnection` timeout)\n",{"name":5,"description":7},"main","c8f4cf0617435584bebec29395be208f2e717994",".agents\u002Fskills\u002Fledger-dmk-implementation",0,"https:\u002F\u002Fgithub.com\u002Fnacmonad\u002Fsoulvault","https:\u002F\u002Fgithub.com\u002Fnacmonad","2026-09-15 01:22:14",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add nacmonad\u002Fsoulvault --skill ledger-dmk-implementation",{"tool":56,"command":57},"bunx","bunx skills add nacmonad\u002Fsoulvault --skill ledger-dmk-implementation",{"tool":59,"command":60},"pnpm","pnpm dlx skills add nacmonad\u002Fsoulvault --skill ledger-dmk-implementation","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fnacmonad\u002Fsoulvault\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fledger-dmk-implementation\u002FSKILL.md",true,[64,70,74],{"path":65,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":68,"sourceHtmlUrl":69},"dmk-code-patterns.md","REFERENCE","参考文档",21027,"https:\u002F\u002Fgithub.com\u002Fnacmonad\u002Fsoulvault\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fledger-dmk-implementation\u002Fdmk-code-patterns.md",{"path":71,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":72,"sourceHtmlUrl":73},"dmk-platform-patterns.md",15076,"https:\u002F\u002Fgithub.com\u002Fnacmonad\u002Fsoulvault\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fledger-dmk-implementation\u002Fdmk-platform-patterns.md",{"path":75,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":76,"sourceHtmlUrl":77},"dmk-sdk-reference.md",10822,"https:\u002F\u002Fgithub.com\u002Fnacmonad\u002Fsoulvault\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fledger-dmk-implementation\u002Fdmk-sdk-reference.md",[79,107,115,141,166,188],{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":90,"publishedAt":38},"01M6H41SQQTYRCRNFX7TKJNCTE","soulvault","Operate SoulVault swarms and agent identities. Use when working with the SoulVault CLI, swarm membership, epoch rotation, backup\u002Frestore, historical key grants, 0G-backed encrypted state publication, ERC-8004 agent identity registration, or when an agent needs to watch\u002Frespond to SoulVault swarm contract events such as JoinApproved, EpochRotated, BackupRequested, MemberFileMappingUpdated, HistoricalKeyBundleGranted, or AgentMessagePosted.","https:\u002F\u002Fgithub.com\u002Fnacmonad\u002Fsoulvault\u002Fblob\u002Fmain\u002Fskills\u002Fsoulvault\u002FSKILL.md",[85],{"categoryNo":86,"categoryName":87,"taxonomyType":88,"taxonomyTypeDesc":89},"01JBSEEDCAT000000000000037","律师与法务","PROFESSION","适用职业",[81,91,36,92,93,94,30,95,96,97,98,28,99,100,101,102,103,104,105,106],"cli","backup","swarm","grants","restore","registration","erc-8004","contract","epoch","respond","with","encrypted","operate","8004 agent","rotation","8004",{"skillNo":108,"name":109,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":110,"categories":111,"keywords":112,"publishedAt":38},"01M6H41PG1XVNCC7VS2DJW1KDF","dmk-speculos-browser","https:\u002F\u002Fgithub.com\u002Fnacmonad\u002Fsoulvault\u002Fblob\u002Fmain\u002Fpackages\u002Fdmk-speculos-browser\u002FSKILL.md",[],[113,114],"browser","dmk speculos browser",{"skillNo":116,"name":109,"nameZh":6,"description":117,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":118,"categories":119,"keywords":125,"publishedAt":38},"01M6H41E4WXGRC57R42M9VC4WE","Drive Ledger DMK browser tests against Speculos, Ledger's device emulator, using @soulvault\u002Fdmk-speculos-browser. Use when a developer needs to run browser-based Ledger signing tests (Playwright + Chromium), wire the emulated transport into DMK, control the emulated device screen and buttons from a test, or record a reproducible proof of a device-signed flow. Covers the transport registration, the test controller, the Playwright fixture, required environment variables, and the concurrency rule that tests must never auto-approve device actions.","https:\u002F\u002Fgithub.com\u002Fnacmonad\u002Fsoulvault\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fdmk-speculos-browser\u002FSKILL.md",[120],{"categoryNo":121,"categoryName":122,"taxonomyType":123,"taxonomyTypeDesc":124},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[113,114,126,127,128,129,130,131,132,133,30,134,135,96,136,137,138,139,140,22],"chromium","playwright","test","actions","Reproducible","controller","concurrency","environment","auto","never","record","fixture","control","tests","Variables",{"skillNo":142,"name":143,"nameZh":6,"description":144,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":150,"publishedAt":38},"01M6H41A77HPQS3VVFY65A1C8N","dmk-intent-vocabulary","Map developer intent and natural language to the correct Ledger Device Management Kit (DMK) components, operations, and API methods. Use when a developer's request is phrased informally, incompletely, or in terms of outcomes rather than API methods, when the intent is ambiguous and needs mapping to a specific DMK component or operation, or when a developer asks 'how do I...', 'what's the difference between...', or describes a symptom rather than an API.","https:\u002F\u002Fgithub.com\u002Fnacmonad\u002Fsoulvault\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fdmk-intent-vocabulary\u002FSKILL.md",[147],{"categoryNo":148,"categoryName":149,"taxonomyType":88,"taxonomyTypeDesc":89},"01JBSEEDCAT000000000000030","开发工程师",[151,152,153,154,155,156,157,158,34,159,30,160,161,162,163,164,165,25,24,23],"intent","vocabulary","dmk intent vocabulary","components","component","developer","api","how","operations","outcomes","methods","do","natural language","map","mapping",{"skillNo":167,"name":168,"nameZh":6,"description":169,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":170,"categories":171,"keywords":173,"publishedAt":38},"01M6H4164305CKMZQKKRPBQCTY","dmk-business-logic","Explain the design rationale and domain concepts behind the Ledger Device Management Kit (DMK) API, including Clear Signing, Secure Channel, Ledger OS (BOLOS), Device Actions vs Commands, sessions, transports, derivation paths, and Genuine Check. Use when a developer asks 'what is X?' about a DMK concept, 'why does X work this way?' about an API design decision, or 'what's the difference between X and Y?' for DMK components.","https:\u002F\u002Fgithub.com\u002Fnacmonad\u002Fsoulvault\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fdmk-business-logic\u002FSKILL.md",[172],{"categoryNo":148,"categoryName":149,"taxonomyType":88,"taxonomyTypeDesc":89},[174,175,176,177,154,178,129,156,157,179,180,181,182,183,184,185,24,186,23,187],"business","logic","dmk business logic","design","secure","why","decision","work","domain","commands","os","paths","concepts","concept",{"skillNo":189,"name":190,"nameZh":6,"description":191,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":192,"categories":193,"keywords":195,"publishedAt":38},"01M6H4120VTX0YEP6HES0BDHMZ","agentkit-x402","Use this skill when you receive a 402 Payment Required response that contains an `agentkit` extension. Covers checking 402 responses for the AgentKit extension before paying, constructing and signing a CAIP-122 challenge (SIWE for EVM), sending the signed `agentkit` HTTP header, and interpreting access modes (free, free-trial, discount). Supports both EOA wallets (EIP-191) and Smart Contract Wallets (ERC-1271, e.g. Coinbase Smart Wallet, Safe).","https:\u002F\u002Fgithub.com\u002Fnacmonad\u002Fsoulvault\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fagentkit-x402\u002FSKILL.md",[194],{"categoryNo":86,"categoryName":87,"taxonomyType":88,"taxonomyTypeDesc":89},[196,197,198,199,200,201,202,30,203,204,205,206,98,207,208,209,22,210,211,212],"x402","agentkit","agentkit x402","safe","http","access","challenge","Wallet","payment","evm","coinbase","free","extension","you","wallets","siwe","for"]