Agent skill

Ledger Wallet CLI

by LedgerHQ in LedgerHQ/ledger-live

Official Ledger wallet-cli - USB-based CLI for Ledger hardware wallet flows (account discover, receive, balances, operations, send, swap quote/execute/status, genuine-check, assets token /…

MITAuto-check passedBackend & APIs

Install Ledger Wallet CLI

skills CLI
$ npx skills add LedgerHQ/ledger-live --skill ledger-wallet-cli -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install LedgerHQ/ledger-live ledger-wallet-cli --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/LedgerHQ/ledger-live.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/ledger-wallet-cli .claude/skills/ledger-wallet-cli && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
ledger-wallet-cli
GitHub stars
622
Token cost
~12k tokens
SKILL.md length
4,556 words
Files
2 (incl. references)
Skills in repo
50
Repo updated
First seen
Licence
MIT

At a glance

Official Ledger wallet-cli - USB-based CLI for Ledger hardware wallet flows (account discover, receive, balances, operations, send, swap quote/execute/status, genuine-check, assets token /…

  • Any wallet-cli command execution and for mapping informal requests to the right command
  • SKILL.md covers Intent map, Out of scope — say no, don't…, Session & labels and Commands, plus 3 more sections
  • Calls pnpm
  • Tasks that involve Smart contracts

What it does

Ledger Wallet CLI is an agent skill from LedgerHQ/ledger-live. Official Ledger wallet-cli - USB-based CLI for Ledger hardware wallet flows (account discover, receive, balances, operations, send, swap quote/execute/status, genuine-check, assets token / token-by-id), the Ledger Key Ring (ring init/encrypt/decrypt/keys/destroy — LKRP-backed encryption of files and text), and Agent Intent (agent-intent enroll/recover/list/show/sync/send — enroll or recover a remote agent's software identity, import the Ledger Sync accounts it was granted and propose EVM payments for human…

Its SKILL.md is about 12k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files, including reference files (for example `references/business-logic.md`).

It sits in Backend & APIs, covering Smart contracts. The repository describes itself as: Mono-repository for Ledger Wallet apps and related packages. The licence is MIT.

When your agent uses it

  • Any wallet-cli command execution and for mapping informal requests to the right command
  • Tasks that involve Smart contracts

Example prompts

  • “/ledger-wallet-cli”

What it can do on your machine

Read from SKILL.md and the folder at commit 30d7883. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • pnpm

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use pnpm, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Ledger Wallet CLI loads about 12k tokens when it runs, and up to ~12k if it reads all its reference files. Until then it costs about 177 tokens; SKILL.md has 4,556 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~177
When it runs · the whole SKILL.md, loaded when a task matches
~12k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~12k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from LedgerHQ/ledger-live at commit 30d7883, republished under its MIT licence (© LedgerHQ). 4,556 words, ~11,714 tokens.

Download SKILL.mdSave it as .claude/skills/ledger-wallet-cli/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
ledger-wallet-cli
description
Official Ledger wallet-cli - USB-based CLI for Ledger hardware wallet flows (account discover, receive, balances, operations, send, swap quote/execute/status, genuine-check, assets token / token-by-id), the Ledger Key Ring (ring init/encrypt/decrypt/keys/destroy — LKRP-backed encryption of files and text), and Agent Intent (agent-intent enroll/recover/list/show/sync/send — enroll or recover a remote agent's software identity, import the Ledger Sync accounts it was granted and propose EVM payments for human review, no device required, never broadcasts, a separate trust model from `ring`). Use for any wallet-cli command execution and for mapping informal requests to the right command.

wallet-cli

USB-based CLI for Ledger wallet flows. Networks: bitcoin, ethereum, solana (mainnet + testnets).

Run from repo root: pnpm --silent wallet-cli start <command> [flags]

Concepts & rationale: for why a command behaves the way it does, or to surface a safety rule that this skill states tersely (genuine check, receive-address verification, sessions, sandbox, device contention), read references/business-logic.md.

Session first: When invoked without a specific task, immediately run session view — do not ask the user what to do first. Show the result, then ask what to do next. If labels exist, skip account discover.

Sandbox: account discover, receive (without --no-verify), send (without --dry-run), genuine-check, swap execute, earn deposit (without --dry-run), earn withdraw (without --dry-run), ring init must use dangerouslyDisableSandbox: true — these open the device over USB (via the node-webusb DMK transport) and are blocked by USB restrictions. ring encrypt, ring decrypt, ring destroy, agent-intent enroll, agent-intent recover, agent-intent sync, agent-intent send (without --dry-run) never open the device but also need the bypass — they're blocked by OS keychain access restrictions instead (agent-intent enroll/recover also hold a WebSocket to the Trustchain relay). ring keys needs neither, and neither does agent-intent list/show: they only read the local session file, so they run without the bypass.

Device contention: Never run two device commands in parallel — they fail with [object Object] or garbled APDU. Run sequentially.

Device readiness: Before running a device command, briefly describe what you're about to do. The CLI prompts for device interaction itself — don't time out or kill the command. Exception: genuine-check exits immediately ([✖] Wrong app. Open Ledger dashboard., exit code 4) if any currency app is open — unlike the other device commands, it targets the dashboard and has no auto-launch path. Ensure the device is on the dashboard before running; if it exits, ask the user to back out to the dashboard and re-run.

Ambiguous requests — ask, don't guess. If a required parameter is missing or unclear (no recipient for send, no network for account discover, an amount with no ticker), stop and ask. A wrong guess on a hardware wallet flow can mean irreversible fund loss.


Intent map

Map informal phrasings to commands. Account references use a session label (e.g. ethereum-1).

User saysCommand
"show me my wallet", "what do I have", "let's get started", no specific tasksession view (run immediately, before asking anything)
"find my accounts", "scan my wallet", "import my wallet", "set up Ethereum/Bitcoin"account discover <network>
"where do I send funds to", "give me my address", "deposit address"receive <account>
"how much do I have", "balance", "what's my ETH balance"balances <account>
"what did I send", "transaction history", "recent activity"operations <account>
"send X to Y", "transfer", "pay", "withdraw to an exchange"send <account> --to <address> --amount '<amount> <ticker>'
"swap A to B", "convert", "trade ETH for BTC", "exchange"swap quote -> swap execute -> swap status
"where can I earn", "staking rates", "yield/APY", "best return on my ETH/SOL"earn yields [-n <network>]
"what am I staking", "my staking positions", "earn balance"earn positions <account>
"stake my SOL", "deposit into a vault", "earn yield on my USDC", "delegate"earn deposit <account> --product <id> --amount '<amount>'
"unstake", "withdraw my stake", "redeem from vault", "stop earning"earn withdraw <account> …
"is this Ledger real", "verify authenticity", "I bought this off eBay"genuine-check
"encrypt this file / these env vars / publish tokens", "GPG alternative", "secret manager", "decrypt anywhere with my Ledger"ring init -> ring encrypt --key <name> / ring decrypt --key <name>
"what keys do I have on my ring", "list domains/projects I've encrypted under"ring keys
"wipe my key ring", "destroy the ring", "tear down LKRP membership"ring destroy
"enroll this agent", "let an agent propose intents", "set up Agent Intent for a bot"agent-intent enroll --profile <id> --name <name> --source <runtime> (no device; blocks until approved)
"recover this agent", "re-enroll an agent into its trustchain"agent-intent recover --profile <id> (no device; blocks until approved)
"what agents are enrolled", "list agent profiles"agent-intent list
"show me that agent profile", "what's the fingerprint for this agent"agent-intent show --profile <id>
"pull my synced accounts", "import from Ledger Sync", "sync the agent's accounts"agent-intent sync --profile <id> (no device)
"have the agent request a payment", "propose sending X to Y for approval"agent-intent send --profile <id> --account <label> --to <address> --amount '<amount> <ticker>' (no device, never broadcasts)
"start over", "clear my session", "I switched devices"session reset

Out of scope — say no, don't improvise

If the user asks for any of the following, surface that wallet-cli does not support it yet rather than constructing a command:

  • NFTs (mint, transfer, view).
  • OpenPGP-compatible output or key-share / multi-recipient encryption (the ring commands encrypt with a per-user Ledger Key Ring, not a sharable key).
  • send, receive, operations, or swap execute on testnets and layer 2s (e.g. Base).
  • Custom chains not listed in the Networks line above.

Session & labels

account discover persists accounts. Each gets a label: <network>[-derivation][-env]-<n> (e.g. ethereum-1, bitcoin-native-1, ethereum-sepolia-1).

All --account flags accept a session label (e.g. ethereum-1). Run account discover first to populate the session.


Commands

CommandDeviceSandboxTTY†Network
session viewNoNoNoNo
session resetNoNoNoNo
account discoverYesRequiredNoYes
receiveYes*RequiredNoNo
sendYes*RequiredNoYes
genuine-checkYesRequiredNoYes
balancesNoNoNoYes
operationsNoNoNoYes
swap quoteNoNoNoYes
swap executeYesRequiredNoYes
swap statusNoNoNoYes
assets tokenNoNoNoNo
assets token-by-idNoNoNoNo
earn yieldsNoNoNoYes
earn positionsNoNoNoYes
earn depositYes*RequiredNoYes
earn withdrawYes*RequiredNoYes
ring initYesRequiredRequired‡Yes
ring encryptNoRequiredNoYes
ring decryptNoRequiredNoYes
ring keysNoNoNoNo
ring destroyNoRequiredRequired‡‡Yes
agent-intent enrollNoRequiredNoYes
agent-intent recoverNoRequiredNoYes
agent-intent listNoNoNoNo
agent-intent showNoNoNoNo
agent-intent syncNoRequiredNoYes

*receive with --no-verify, send with --dry-run, and earn deposit/earn withdraw with --dry-run need no device and no sandbox bypass.

†TTY: whether the command requires an interactive terminal for user input.

‡ring init requires a password to protect the ring. WALLET_PASS must already be provided in the environment by the developer/user before the command runs — the agent never sets or injects it (see Non-TTY password injection).

‡‡ring destroy prompts for typed confirmation ("destroy"). Pipe it in non-interactive shells: echo "destroy" | wallet-cli ring destroy. If a password was set, WALLET_PASS must already be present in the environment (provided by the developer, not the agent).

session view / reset
bash
pnpm --silent wallet-cli start session view
pnpm --silent wallet-cli start session reset
account discover
bash
pnpm --silent wallet-cli start account discover ethereum
pnpm --silent wallet-cli start account discover bitcoin
pnpm --silent wallet-cli start account discover ethereum:sepolia

Networks: bitcoin (mainnet), ethereum, solana, ethereum:sepolia, bitcoin:testnet, solana:devnet.

receive
bash
pnpm --silent wallet-cli start receive ethereum-1
pnpm --silent wallet-cli start receive ethereum-1 --no-verify  # skip device confirmation

If the on-screen address differs from the terminal address: do not share or use the address. Have the user disconnect the device and run genuine-check before retrying. See references/business-logic.md § Receive-address verification for context.

genuine-check
bash
pnpm --silent wallet-cli start genuine-check
pnpm --silent wallet-cli start genuine-check --output json  # only if a downstream caller needs to parse the result

Preconditions: device unlocked and on the dashboard (exit any open app); host has internet access (the secure channel reaches Ledger's backend — offline runs fail).

balances
bash
pnpm --silent wallet-cli start balances ethereum-1
pnpm --silent wallet-cli start balances ethereum-1 --output json
operations
bash
pnpm --silent wallet-cli start operations ethereum-1
pnpm --silent wallet-cli start operations ethereum-1 --limit 20 --cursor <cursor>

Pagination: next cursor on stderr (human) or nextCursor in JSON.

send
bash
pnpm --silent wallet-cli start send ethereum-1 --to 0xDEF... --amount '0.5 ETH'
pnpm --silent wallet-cli start send ethereum-1 --to 0xDEF... --amount '100 USDT'  # ERC-20
pnpm --silent wallet-cli start send bitcoin-native-1 --to bc1q... --amount '0.001 BTC' --fee-per-byte 15 --rbf
pnpm --silent wallet-cli start send ethereum-1 --to 0xDEF... --amount '0.5 ETH' --dry-run

Ticker is mandatory in --amount. No --token flag — ticker drives asset resolution.

Bitcoin flags: --fee-per-byte <sats>, --rbf

Solana flags: --mode send|stake.createAccount|stake.delegate|stake.undelegate|stake.withdraw, --validator <addr>, --stake-account <addr>, --memo <text>

EVM flags: --data <hex> — raw calldata for contract calls (0x-prefixed hex, even digit count). Use for contract interactions the CLI has no dedicated command for (e.g. WETH wrap/unwrap below). Omit for plain native/token transfers.

Contract calls with --data (wrap/unwrap example)

Canonical pattern: WETH wrap/unwrap. deposit() (wrap ETH → WETH, no args) is selector 0xd0e30db0, sent with --amount as the ETH value. withdraw(uint256) (unwrap WETH → ETH, one uint256 arg = amount in wei) is selector 0x2e1a7d4d followed by the amount left-padded to 32 bytes.

bash
# wrap 0.5 ETH into WETH
pnpm --silent wallet-cli start send ethereum-1 --to <WETH_CONTRACT_ADDRESS> --amount '0.5 ETH' --data 0xd0e30db0

# unwrap 0.5 WETH back to ETH (0.5 ETH = 500000000000000000 wei = 6f05b59d3b20000 hex, padded to 32 bytes)
pnpm --silent wallet-cli start send ethereum-1 --to <WETH_CONTRACT_ADDRESS> --amount '0 ETH' --data 0x2e1a7d4d00000000000000000000000000000000000000000000000006f05b59d3b20000

Always run with --dry-run first to validate calldata before signing. The CLI cannot verify the semantic correctness of hand-supplied --data — the device screen is the last line of defense, so review the decoded call on-device before approving.

swap quote

Fetches quotes in parallel from the built-in provider list (no device required; addresses are resolved from session accounts).

Currencies: --from / -f and --to / -t are Ledger currency IDs — native assets (e.g. ethereum, bitcoin, solana) or token IDs when the token’s parent chain is a supported native swap currency (same IDs the CLI allows for swap). They are not session account labels — use --from-account / --to-account for accounts.

Default providers queried by swap quote and usable by swap execute: changelly, changelly_v2, cic, cic_v2, exodus, lifi, nearintents, okx, oneinch, swapsxyz, uniswap, velora. Some are CEX/aggregators run through the legacy Exchange-app pipeline; the DEX providers (uniswap, oneinch, velora, okx) execute in the partner's embedded coin app — see swap execute — DEX providers.

Accounts: --from-account and --to-account accept a session label only; the CLI resolves a fresh receive address from the account like receive.

bash
pnpm --silent wallet-cli start swap quote --from ethereum --to bitcoin --amount 0.1 --from-account ethereum-1 --to-account bitcoin-native-1
pnpm --silent wallet-cli start swap quote -f ethereum -t bitcoin --amount 0.1 --from-account ethereum-1 --to-account bitcoin-native-1 --output json

Required: --from, --to, --from-account, --to-account, --amount.

swap execute

Currencies: --from / -f and --to / -t are Ledger currency IDs (same as swap quote): native assets or tokens on an allowed parent chain. They must match the asset of the source --account and of --to-account respectively.

Providers: Valid --provider values are changelly, changelly_v2, cic, cic_v2, exodus, lifi, nearintents, okx, oneinch, swapsxyz, uniswap, velora. Aliases: changelly → changelly_v2, 1inch → oneinch. Use the provider id shown on the quote line you pick from swap quote.

DEX providers (uniswap, oneinch, velora, okx): these run end-to-end in the partner's embedded coin app on the device (via the Device Intent Executor), not the legacy Exchange app. The flow re-fetches a quote for the chosen provider, then drives an on-device approval + swap sequence (sign-approval / sign-permit2 / sign-swap / broadcast), switching device apps as needed — confirm each Open <app> and signing prompt on the device.

  • EVM only. DEX execution requires an EVM source account (e.g. ethereum); a non-EVM --account falls through to the legacy pipeline.
  • RFQ quotes are not supported in the CLI. If the picked quote resolves to an RFQ plan (rfq-order / approval-then-rfq-order), the embedded flow is skipped and execution falls back to the legacy Exchange-app pipeline (you'll see a falling back to legacy Exchange-app pipeline progress line).

All other providers (changelly, cic, exodus, nearintents, swapsxyz, lifi, …) run the legacy Exchange-app pipeline (nonce → payload → complete exchange → sign/broadcast).

Fee strategy: --fee-strategy accepts slow, medium (default), or fast. On the legacy pipeline it sets the refund-chain transaction fee.

bash
pnpm --silent wallet-cli start swap execute --from ethereum --to bitcoin --account ethereum-1 --to-account bitcoin-native-1 --provider changelly --amount 0.1
pnpm --silent wallet-cli start swap execute -f ethereum -t bitcoin --account ethereum-1 --to-account bitcoin-native-1 --provider changelly --amount 0.1 --fee-strategy fast
pnpm --silent wallet-cli start swap execute --from ethereum --to bitcoin --account ethereum-1 --to-account bitcoin-native-1 --provider changelly --amount 0.1 --output json
# DEX (embedded coin app): EVM-only, source and destination on an EVM chain
pnpm --silent wallet-cli start swap execute --from ethereum --to ethereum/erc20/usd_tether__erc20_ --account ethereum-1 --to-account ethereum-1 --provider uniswap --amount 0.1

Required flags: --from, --to, --account, --to-account, --provider, --amount. Use a --provider value that matches the provider id on the quote line you pick from swap quote.

swap status
bash
pnpm --silent wallet-cli start swap status --swap-id <swapId> --provider changelly
pnpm --silent wallet-cli start swap status --swap-id <swapId> --provider changelly --output json

Required flags: --swap-id, --provider

assets token / token-by-id

Resolve token metadata from the cryptoassets store. No device, no session.

bash
pnpm --silent wallet-cli start assets token ethereum 0xdac17f958d2ee523a2206206994597c13d831ec7
pnpm --silent wallet-cli start assets token-by-id ethereum/erc20/usd_tether__erc20_

Use token when you have the contract address; use token-by-id when you have the id. Exits non-zero if not found.

For non-EVM chains pass --identifier.

The id printed here is the same id accepted by swap quote --from / --to and swap execute --from / --to.

ring — Ledger Key Ring (LKRP)

Trustless, hardware-rooted encryption for files and text. The key ring is provisioned once on your Ledger via the Ledger Sync app; afterwards encrypt/decrypt run without the device — keys derive deterministically via HKDF-SHA256 from the LKRP-shared root and never leave AES-256-GCM. encrypt/decrypt still call the LKRP backend to restore the trustchain on each invocation, so network access is required. The ring is recoverable from your seed on any new machine.

bash
# One-time provisioning (device required). Password comes from WALLET_PASS in the environment (see below); name the machine with --name.
pnpm --silent wallet-cli start ring init
pnpm --silent wallet-cli start ring init --name my-laptop

# File round-trip (no device after init):
pnpm --silent wallet-cli start ring encrypt --key my-oss-project -i .publish-tokens -o .publish-tokens.enc
pnpm --silent wallet-cli start ring decrypt --key my-oss-project -i .publish-tokens.enc -o .publish-tokens

# Text via stdin/stdout (clipboard pattern):
pbpaste | pnpm --silent wallet-cli start ring encrypt --key personal-notes | pbcopy
pbpaste | pnpm --silent wallet-cli start ring decrypt --key personal-notes | pbcopy

# List the keys this machine has used; tear down the ring:
pnpm --silent wallet-cli start ring keys
pnpm --silent wallet-cli start ring destroy

Always provision with a password. The ring must be protected by a password. The user provides it via WALLET_PASS in the environment before running ring init (see Non-TTY password injection) — the agent never provisions a ring without one.

Decrypted output is sensitive. ring decrypt emits secrets — never print them to the terminal, cat a decrypted file, or otherwise surface the decrypted contents, since they land in the agent transcript, logs, and scrollback. Pipe decrypt straight to its destination (a file via -o, another process, or the clipboard as shown above) or capture it into an env var; avoid --output/logging sinks that could echo it back.

--key <name> derives a per-name AES-256-GCM key; matching name at decrypt time is mandatory. Names are free-form (max 253 chars, no whitespace) — common patterns: project slugs (my-oss-project), env tags (openClaw-prod), notebooks (personal-notes).

Non-TTY (CI / agentic) password injection: the ring commands read the password from the WALLET_PASS env var when there is no TTY. The password itself must be provisioned by the developer/user (exported in the environment or stored in the OS keychain) — the agent never chooses, types, or otherwise handles the secret value; it only references what the user has already provisioned.

  • Never write the password literally into a command (e.g. WALLET_PASS=hunter2 wallet-cli …, or via a flag). A literal leaks into shell history, ps output, CI logs, and — when an agent runs the command — the agent transcript. This applies to throwaway/test passwords too: make it a habit, because the same command shape is reused with a real secret.
  • Always inject via command substitution so the secret never appears in the command text you type:
    • macOS : WALLET_PASS=$(security find-generic-password -a default -s ledger-wallet-cli -w) wallet-cli ring encrypt …
    • Linux : WALLET_PASS=$(secret-tool lookup service ledger-wallet-cli account default) wallet-cli ring encrypt …
  • Agents must not handle the secret at all. Ask the user to store the password once in their OS keychain, then reference only the $(…) substitution. If a test or ring init needs a password, store a throwaway value in the keychain first (security add-generic-password -a default -s ledger-wallet-cli -w) and inject it the same way — never type the literal into a tool call.
  • Even via substitution the value lives in the child process environment (readable via ps eww by the same user) — acceptable, but prefer the keychain form and avoid --output json sinks or logs that could echo it back.

Rotation limitation: the domain key derives from the ring's wallet-sync encryption key, which the LKRP protocol rotates when a ring member is removed. After a rotation, data encrypted before it can no longer be decrypted (decrypt fails with a "wrong key name, corrupted data, or the Ledger Key Ring rotated" error, and the CLI prints a ⚠ Ledger Key Ring rotated warning). Re-encrypt the affected data under the new ring after a member is removed. ring destroy aborts (no changes) if you enter a wrong password, and also if WALLET_PASS is set but empty (a failed keychain lookup) — this is treated as a mistake, not a skip, so it never orphans the remote ring. To intentionally skip the remote teardown and wipe only local credentials, press Enter at the interactive password prompt.


Agent Intent

Separate trust model from ring. The agent is a software-only LKRP member: it joins its own Agent Intent (App-18) Trustchain and is granted access to the user's Ledger Sync (App-16) stream, but it never opens the device and never receives ring's (App-17) domain keys.

Agent Intent enrolls a remote agent (a bot proposing transaction intents for human review) as a software identity local to this machine — no device required for enroll/recover/list/show/sync. Each profile gets its own secp256k1 keypair; the private key never leaves the OS keychain and is never printed, logged, or included in any command's output (human or --output json).

bash
# Create a pending profile, print its signed enrollment URL + fingerprint, then BLOCK until the
# human approves in the Agent Intent frontend (default environment: production):
pnpm --silent wallet-cli start agent-intent enroll --profile my-bot --name "My Bot" --source claude-code
pnpm --silent wallet-cli start agent-intent enroll --profile my-bot --name "My Bot" --source other \
  --environment staging --expires-in 2h

# Re-enroll an enrolled profile's existing key into its previous Trustchain, then
# BLOCK until approved (environment/keycloak come from the profile):
pnpm --silent wallet-cli start agent-intent recover --profile my-bot

# List/inspect local profiles (never reveals the secret key):
pnpm --silent wallet-cli start agent-intent list
pnpm --silent wallet-cli start agent-intent show --profile my-bot

# Import the Ledger Sync accounts the agent was granted into the session (explicit, never automatic):
pnpm --silent wallet-cli start agent-intent sync --profile my-bot
pnpm --silent wallet-cli start agent-intent sync --profile my-bot --output json

Always pass --source. It is the runtime or harness the agent runs in (not its model provider): openclaw, hermes, claude-code, codex, cursor, muse, grok-bot, or other when none matches. Omitting it defaults to other. The frontend shows it as the agent's source; never pass a value outside this list.

One blocking command, no copy/paste. enroll prints the URL first (with --output json: an enrollment-pending NDJSON event), then waits on an encrypted Trustchain relay channel bound into the signed request. The frontend delivers the completion over that channel; there is no complete command and no manual JSON fallback. Keep the process running until it prints the final enrolled result (json: status: "success", enrolled: true, trustchainId, accountAccessEnvironment). The wait is bounded by --expires-in (default 30m).

Nothing is trusted from the relay alone. Before saving, enroll proves the completion: the agent key must obtain an App-18 access token for the claimed Trustchain (Keycloak), and must authenticate to the claimed App-16 stream with exactly the expected permission. Only then are trustchainId and the (non-secret) accountAccess references written to the profile.

On timeout, Ctrl+C, or a failed check the profile stays pending (and later expired) and cannot be resumed — start a fresh enrollment with a new --profile id.

Recovery reuses the same key. recover --profile <id> signs a recovery request for the profile's existing key and Trustchain (no new key, accountAccess untouched), then waits on the relay exactly like enroll (json: a recovery-pending event, then status: "success", recovered: true, trustchainId). Any enrolled profile whose keychain key matches the recorded public key can be recovered, whatever its --source. The completion must name the same agent key, the same signed request and the same Trustchain, and the agent key must obtain an App-18 token for it (App-16 is not re-checked). While it waits, list/show report recovering; on timeout, Ctrl+C, or a failed check the marker is cleared and the profile stays enrolled with its previous data — re-run recover to retry.

Fingerprint is the safety check. enroll prints a public-key fingerprint alongside the enrollment URL, and show prints the same fingerprint for any profile afterwards — compare it against what the Agent Intent frontend/device displays before approving. A mismatched fingerprint means the enrollment request was tampered with or sent to the wrong agent.

Duplicate protection: enroll refuses to reuse a --profile id already recorded in the session, and separately refuses if a keychain entry for that id exists without a matching session record (an inconsistent state you must clear manually before re-enrolling under the same id).

Keychain required: enroll needs a working OS keychain — macOS Keychain, Windows Credential Manager, or on Linux a running Secret Service provider (e.g. gnome-keyring or KeePassXC) with an unlocked collection. Without one (headless Linux, containers, some CI runners) enroll fails with Could not store the agent's secret key in the OS keychain (…) and saves nothing — fix the keychain and re-run the same command; there is no file-based fallback by design.

Environment isolation: each profile records the environment (staging/production) it was enrolled against. A completion whose accountAccess.environment doesn't match is rejected, so a profile enrolled for staging can never end up holding a production Trustchain ID. --bff-url and --keycloak-url override that environment's defaults (http(s) only, no user:pass@).

Status is derived, not stored: list/show compute pending / enrolled / recovering / expired from trustchainId, enrollmentExpiresAt and any unexpired recovery marker, and show the granted account access (environment + App-16 application path) once enrolled.

Show full SKILL.md (1,498 more words)Show less
Syncing Ledger Sync accounts

agent-intent sync --profile <id> imports the accounts synchronized from your other Ledger Wallet instances (desktop, mobile) so they can be referenced by label. It authenticates with the agent's own key (from the OS keychain), which the frontend added to the App-16 stream at enrollment — it never opens the device and there is no separate Ledger Sync enrollment. The environment comes from the profile's accountAccess.

  • Requires an enrolled profile: a pending/expired profile (no accountAccess) or a missing keychain key fails with a clear error.
  • Lost access is reported, not repaired: if the agent was removed from Ledger Sync, sync reports "no longer has Ledger Sync access" and deletes nothing.
  • Key rotation is followed: if Ledger Sync rotated its key (a member was removed), the profile's accountAccess is updated to the new application path and the sync proceeds.
  • Additive and idempotent: never deletes or re-labels a session account and never uploads anything; a repeat run reports unchanged entries or "Up to date".
  • Unsupported/malformed entries are isolated: an account for a currency family wallet-cli doesn't support (only bitcoin/evm/solana) is skipped, a malformed one is invalid — the rest of the import still proceeds, and an invalid entry keeps the next sync from treating the data as up to date.
Proposing a payment (agent-intent send)

agent-intent send proposes an Ethereum send for a human to review — it never signs or broadcasts anything and needs no device. It signs the proposal with the profile's key, submits it to the Agent Intent service, and prints a review link; the payment only happens if a human opens that link and approves it on their Ledger device.

bash
# Native ETH, sender from a session label:
pnpm --silent wallet-cli start agent-intent send --profile my-bot --account ethereum-1 \
  --to 0xRecipient --amount '0.01 ETH' --description "Invoice #42"

# ERC-20: pass the token contract; the ticker in --amount must match it:
pnpm --silent wallet-cli start agent-intent send --profile my-bot --from 0xSender \
  --to 0xRecipient --amount '25 USDC' --token 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48

# Validate everything and print the proposal without submitting (no keychain, no sign-in):
pnpm --silent wallet-cli start agent-intent send --profile my-bot --account ethereum-1 \
  --to 0xRecipient --amount '0.01 ETH' --dry-run
  • Enrolled profile only (its agent-intent enroll approval went through). It uses the profile's environment, the BFF and Keycloak URLs recorded at enroll time (so an enroll-time --bff-url/--keycloak-url override carries over), and its key in the OS keychain.
  • Ethereum mainnet only, for both a --account label and a --from address. The Agent Intent SDK has no testnet, so a staging profile also proposes an Ethereum mainnet transfer.
  • Addresses: --from, --to and --token must be 0x + 40 hex characters. Mixed-case input must pass its EIP-55 checksum, which catches a typo in a copied address.
  • Amounts are exact and never rounded. More decimals than the asset has, zero, or an amount above uint256 is an error. JSON output gives amount in base units as a string.
  • --fee-strategy slow|medium|fast (default medium) is the fee level the human is asked to approve. wallet-cli doesn't check the sender's balance; the human reviewing the intent is responsible for that.
  • Don't retry blindly. If the service accepted the request (a timeout, or an unreadable link), the intent may already exist. Check the frontend before re-running, or you'll propose a duplicate. A service rejection is explained with a next step (for example, re-enroll after an issuer mismatch).

earn (staking & DeFi yield)

Earn covers two flows: Ethereum ERC-4626 DeFi vaults (deposit/redeem) and Solana native staking (delegate/undelegate). yields and positions are read-only (no device); deposit and withdraw sign on the device.

Only ethereum & solana support deposit/withdraw. Other networks appear in earn yields (informational) but cannot be deposited to via the CLI.

earn yields

Lists yield opportunities (no device). Without --network it prints every network's headline rate. With -n ethereum or -n solana it also prints the concrete deposit targets, each ending with the exact → --product <id> value to pass to earn deposit:

  • ethereum → ERC-4626 vault ids (e.g. 1_0x7daeba3f217614e409f85d3014d33923a6b03630).
  • solana → validator vote accounts. The CLI surfaces the Ledger-operated validators ("Ledger by Figment", "Ledger by Bitwise") as the recommended targets; any other valid vote account also works as --product.
bash
pnpm --silent wallet-cli start earn yields
pnpm --silent wallet-cli start earn yields -n solana
pnpm --silent wallet-cli start earn yields -n ethereum --output json

There is no separate "list validators / vaults" command — earn yields -n <network> is how you discover a valid --product. In JSON, the value is the vaultId (ETH) or validator (SOL) field on each row.

earn positions

Lists active earn positions for an account (no device). Account-based networks only (solana, ethereum).

bash
pnpm --silent wallet-cli start earn positions solana-1
pnpm --silent wallet-cli start earn positions solana-1 --fresh   # request a background refresh

--fresh flags stale rows for an async backend refresh; the refreshed data shows up on a re-run, not in the same response. Watch for the (stale) marker.

Solana stake accounts: for Solana accounts the command also reads on-chain stake accounts and prints each one's → --stake-account <address>, its state (active / inactive / activating / deactivating), balance, and validator. This is where you get the --stake-account value for earn withdraw. In JSON they're a top-level stakes[] array alongside positions (each entry: stakeAccount, validator, state, stakeBalance, withdrawable); the stakes key is omitted entirely when there are none. Stake accounts show up here right after a deposit even if the backend snapshot is still empty. (Requires a chain sync; if it can't be reached the backend snapshot still prints, with a warning.)

earn deposit

Stakes (Solana) or deposits into a vault (Ethereum). Touches the device to sign — bypass the sandbox. --product comes from earn yields -n <network> (see above). --amount requires a ticker.

bash
# Solana: --product is a validator vote account
pnpm --silent wallet-cli start earn deposit solana-1 --product 26pV97Ce83ZQ6Kz9XT4td8tdoUFPTng8Fb8gPyc53dJx --amount '1.5 SOL'
# Ethereum: --product is a vault id
pnpm --silent wallet-cli start earn deposit ethereum-1 --product 1_0x7daeba3f217614e409f85d3014d33923a6b03630 --amount '100 USDC'
# Validate without signing (no device, no sandbox bypass)
pnpm --silent wallet-cli start earn deposit solana-1 --product 26pV97… --amount '1.5 SOL' --dry-run

Solana stake.createAccount creates and delegates the stake account in one transaction. Ethereum deposits may run two transactions (ERC-20 approve then deposit).

First-time ETH vault deposit — dry-run can't validate the deposit leg. A first deposit into a vault you've never used is approve → deposit, and the deposit can only be built once a non-zero allowance exists on-chain. In --dry-run nothing is broadcast, so when an approve is still required the CLI validates the approve and skips the deposit build (status not-simulated …, overall dry-run: approve validated; deposit needs an on-chain allowance to simulate) rather than surfacing the backend's opaque 500. This is expected — not a balance error. The only way to validate the deposit leg is the real run (broadcast approve, wait for confirmation, then deposit). Treat a clean dry-run here as "approve is fine"; confirm with the user before the live run since it's an irreversible on-device signature. Once the allowance exists, a re-run of --dry-run will simulate the deposit normally.

earn withdraw

Unstakes (Solana) or redeems from a vault (Ethereum). Touches the device — bypass the sandbox.

  • Ethereum: --product <vault-id> required; --amount optional. The amount is in the vault's asset units (e.g. '50 USDC'); if a ticker is given it must match the vault asset. Omit --amount for a full exit: the CLI sends amount:"max" and the backend redeems the entire share balance, leaving no dust (don't compute the asset amount yourself for a full exit — the share→asset rate drifts).
  • Solana: --stake-account <address> (required). Two-phase: run once to undelegate (deactivate), wait for the deactivation epoch boundary (~2–3 days), then re-run with --finalize to withdraw the now-inactive lamports back to the main account. coin-solana computes the withdrawable amount on-chain, so --amount is ignored on finalize.
bash
# Ethereum vault redeem
pnpm --silent wallet-cli start earn withdraw ethereum-1 --product 1_0x7daeba3f… --amount '50 USDC'
# Solana phase 1: deactivate
pnpm --silent wallet-cli start earn withdraw solana-1 --stake-account <stakeAccountAddr>
# Solana phase 2 (after ~2–3 days): withdraw
pnpm --silent wallet-cli start earn withdraw solana-1 --stake-account <stakeAccountAddr> --finalize

Get the Solana --stake-account address from earn positions <account> (its stakes[] / → --stake-account lines) — that's the stake account created by your earlier earn deposit.


Common errors

ErrorCauseFix
Amount must include a ticker--amount missing tickerAsk the user which asset they mean — do not guess. Then pass the ticker inline, e.g. --amount '0.5 ETH'.
Ticker UNKN not found in accountticker not in account balancesRun balances <account> and show the user the tickers held by this account. Ask the user which ticker to use, or whether they meant a different account — do not silently substitute another ticker.
[✖] Wrong app. Open Ledger dashboard. (exit code 4)genuine-check invoked while a currency app is open. Unlike other device commands, genuine-check targets the dashboard and has no auto-launch path.Ask the user to exit the foreground app on the device (short-press both buttons on the app's main screen until Quit shows, then confirm), then re-run genuine-check. Other device commands (account discover, receive, send, swap execute) don't hit this — they auto-prompt the correct app launch.
[✖] Rejected on device. No action taken.user rejected a sign request on deviceThe rejection was deliberate. Ask the user whether to retry or abort — do not auto-retry. If they retry, have them review amount, recipient, and fees on the device screen before approving.
[✖] Rejected on device. App was not opened.user rejected the app-open prompt on deviceAsk the user to confirm the app-open prompt on the device and re-run the command.
[✖] Timed out talking to the Ledger over USB. The device may be busy or locked. Retry the command.sandbox blocking USB, or device busy/lockedSurface to the user that the command needs dangerouslyDisableSandbox: true and ask for confirmation before re-running with the bypass. The bypass is expected for device commands (account discover, receive, send, genuine-check, swap execute, earn deposit, earn withdraw, ring init); if this error fires on any other command, investigate before bypassing rather than disabling the sandbox by reflex.
[object Object] or garbled APDU outputtwo device commands running in parallel (contention)Run device-touching commands sequentially — never in parallel tool calls.
[✖] Ledger not detected. Plug in, unlock, retry. (exit code 3)device powered off or unpluggedAsk the user to power on the device, unlock it, and connect via USB, then re-run the command.
device-state … awaiting_approval … reason: unlock (JSON stream)device lockedKeep the command running — the CLI resumes automatically once unlocked. Ask the user to unlock the device with their PIN.

© LedgerHQ, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file (references) in .agents/skills/ledger-wallet-cli of LedgerHQ/ledger-live.

  • SKILL.md
  • references/business-logic.md

Open the folder on GitHubat commit 30d7883

Compare with similar skills

Ledger Wallet CLI next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Ledger Wallet CLI compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Ledger Wallet CLI this skillLedgerHQ/ledger-live622—~12kAutomated safety check: PassMIT
Fizz Convertpashov/skills1.2k2 repos~3.7kAutomated safety check: PassMIT
Solana Devsolana-foundation/solana-dev-skill574—~3.8kAutomated safety check: PassMIT
Feynman Auditor0xiehnnkta/nemesis-auditor2431 repos~11kAutomated safety check: PassMIT
Smart Contract Auditgreatpie/smart-contract-audit-skill101—~1.1kAutomated safety check: PassNone
RadarAuditware/radar154—~2.1kAutomated safety check: PassGPL-3.0

Similar skills

  • Fizz Convert

    pashov/skills

    Convert English-language properties in PROPERTIES.md (produced by the Fizz skill) into Solidity assertions inside the existing fuzz harness, then flip their checkboxes.

    1.2k GitHub starsUsed in 2 repos~3.7k tokens
    Backend & APIsAuto-check passed
  • Solana Dev

    solana-foundation/solana-dev-skill

    A skill your agent uses when user asks to "build a Solana dapp", "write an Anchor program", "create a token", "debug Solana errors", "set up wallet connection", "test my Solana program", "fuzz my…

    574 GitHub stars~3.8k tokensUpdated today
    Backend & APIsAuto-check passed
  • Feynman Auditor

    0xiehnnkta/nemesis-auditor

    Deep business logic bug finder using the Feynman technique. An agent skill from 0xiehnnkta/nemesis-auditor.

    243 GitHub starsUsed in 1 repo~11k tokens
    Backend & APIsAuto-check passed
  • Smart Contract Audit

    greatpie/smart-contract-audit-skill

    Script-backed, out-of-box auditing workflow for Solidity/EVM repositories based on EVMbench detect/patch/exploit methodology.

    101 GitHub stars~1.1k tokensUpdated 7 mo ago
    Backend & APIsAuto-check passed
  • Radar

    Auditware/radar

    Use radar for smart contract security analysis, AST generation, and detection template development.

    154 GitHub stars~2.1k tokensUpdated 1 mo ago
    Backend & APIsAuto-check passed
  • Solidity Auditor

    Gabson0x/bountyforge

    Security audit of Solidity code while you develop. An agent skill from Gabson0x/bountyforge.

    443 GitHub stars~3.7k tokensUpdated 21 days ago
    Backend & APIsAuto-check passed

More from LedgerHQ/ledger-live

All 50 skills in this repo
  • Impacting PRs

    LedgerHQ/ledger-live

    Find which open PRs are impacted by a migration/sunset/refactor and notify their authors — blocking review when the old path is already gone from develop, heads-up comment when it is only deprecated…

    622 GitHub stars~3.3k tokensUpdated today
    Auto-check passed
  • Cloud Sync Module

    LedgerHQ/ledger-live

    Write, review or debug a cloudSyncModule.ts — a CloudSyncDataManager that syncs one slice of user data through Ledger Sync (Cloud Sync).

    622 GitHub stars~2.4k tokensUpdated today
    Auto-check passed
  • Codeownership

    LedgerHQ/ledger-live

    Maintain CODEOWNERS file and team directories. An agent skill from LedgerHQ/ledger-live.

    622 GitHub stars~687 tokensUpdated today
    Auto-check passed
  • Coin Families Contract

    LedgerHQ/ledger-live

    Coin-specific families logic must live in families/. An agent skill from LedgerHQ/ledger-live.

    622 GitHub stars~1k tokensUpdated today
    Auto-check passed
  • Data Layer Advanced

    LedgerHQ/ledger-live

    Structure a Ledger Wallet data layer where one API response serves several entities.

    622 GitHub stars~509 tokensUpdated today
    Auto-check passed
  • Debug Rn Native Crash

    LedgerHQ/ledger-live

    Investigate native React Native crashes (Fabric/Hermes/iOS) in ledger-live-mobile when JS error logs are missing or unhelpful.

    622 GitHub stars~1.2k tokensUpdated today
    Auto-check passed

Categories

Questions about Ledger Wallet CLI

What does Ledger Wallet CLI do?

Official Ledger wallet-cli - USB-based CLI for Ledger hardware wallet flows (account discover, receive, balances, operations, send, swap quote/execute/status, genuine-check, assets token /…. Ledger Wallet CLI is an agent skill from LedgerHQ/ledger-live.

When should I use Ledger Wallet CLI?

Ledger Wallet CLI fits situations like: any wallet-cli command execution and for mapping informal requests to the right command; tasks that involve Smart contracts.

How do I install Ledger Wallet CLI in Claude Code?

Run `npx skills add LedgerHQ/ledger-live --skill ledger-wallet-cli -a claude-code`. Or copy the skill folder (.agents/skills/ledger-wallet-cli in LedgerHQ/ledger-live) into .claude/skills/ledger-wallet-cli in your project. Claude Code loads it when a task matches its description.

How do I install Ledger Wallet CLI in Codex?

Run `npx skills add LedgerHQ/ledger-live --skill ledger-wallet-cli -a codex`. Or copy the skill folder (.agents/skills/ledger-wallet-cli in LedgerHQ/ledger-live) into .agents/skills/ledger-wallet-cli in your project. Codex loads it when a task matches its description.

Can I use Ledger Wallet CLI in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add LedgerHQ/ledger-live --skill ledger-wallet-cli -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/ledger-wallet-cli, .gemini/skills/ledger-wallet-cli, .github/skills/ledger-wallet-cli and .opencode/skills/ledger-wallet-cli in your project.

What does Ledger Wallet CLI need to run?

Going by SKILL.md and its folder, Ledger Wallet CLI needs the command-line tools its instructions call (pnpm).

Does Ledger Wallet CLI access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Ledger Wallet CLI safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Ledger Wallet CLI use?

Ledger Wallet CLI is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Ledger Wallet CLI use?

About 12k tokens (SKILL.md is roughly 47k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 717 tokens, read only when the agent opens those files.

What are the alternatives to Ledger Wallet CLI?

Skills that share tags, products or a category with Ledger Wallet CLI: Fizz Convert (pashov/skills, 1.2k stars), Solana Dev (solana-foundation/solana-dev-skill, 574 stars), Feynman Auditor (0xiehnnkta/nemesis-auditor, 243 stars) and Smart Contract Audit (greatpie/smart-contract-audit-skill, 101 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Ledger Wallet CLI?

LedgerHQ (a GitHub organization) maintains it in LedgerHQ/ledger-live, which has 622 GitHub stars. The repository holds 50 skills in this directory. The repository was last updated on October 8, 2026.

Source: LedgerHQ/ledger-live on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.