Nunchuk + Claude: AI Bitcoin Agent with Spending Limits
Audience: Intermediate — basic Bitcoin knowledge and command-line comfort required
Duration: 60–90 min
Outcomes: By the end, students will:
- Install Nunchuk CLI and connect Claude Code to it via agent skills
- Understand why bounded signing authority is safer than giving an AI full wallet access
- Build a 2-of-3 multisig wallet with a Nunchuk Platform key
- Set a daily spending limit enforced at the cryptographic level
- Send a transaction under the cap and demonstrate that exceeding it requires human cosigning
Abstract
Most AI agent setups give Claude access to a hot wallet or an API with full spending power. That's convenient but brittle — a misbehaving prompt, a confused agent, or a supply chain compromise and your funds are gone. There's a better design: give the AI bounded signing authority on one key in a multisig, and let cryptographic policy enforce the ceiling.
This walkthrough shows you how to build exactly that using the Nunchuk CLI and Claude Code. You'll create a 2-of-3 multisig wallet where Nunchuk's Platform key enforces a daily spending limit. Claude holds one key, you hold another, and Nunchuk's HSM holds the third. Any two signers can authorize a transaction — but the Platform key will only co-sign if the spend is within the policy limit. Above the cap, you have to cosign manually. The AI can pay invoices and rebalance within its budget. It cannot go rogue.
Concept Primer
Before getting into commands, here's the vocabulary you need:
Multisig wallets
A multisig (multi-signature) wallet requires M of N keys to authorize a transaction. A 2-of-3 means any 2 of the 3 key holders can sign — no single person can move funds unilaterally. This is the basis of both collaborative custody and AI-bounded authority: the AI is one keyholder, not all of them.
Platform key
Nunchuk's Platform key is an HSM-backed key held by Nunchuk's servers. Unlike a human cosigner, the Platform key applies programmable policies before signing. You set a daily spending limit in USD — the Platform key auto-signs anything under the limit and refuses everything over it. Changing the policy requires a signed dummy PSBT from the wallet's other signers, so the AI cannot raise its own limit.
PSBTs
A Partially Signed Bitcoin Transaction (PSBT) is the standard format for passing a transaction between multiple signers. Each signer adds their signature and passes it along. Nunchuk uses this same rail for policy changes — a dummy PSBT encodes a governance action (like a policy update) rather than a real spend, but it still requires the same M-of-N signatures to execute.
BIP32 and BIP39
BIP39 defines the 12- or 24-word mnemonic seed phrase. BIP32 defines how a single seed derives an unlimited tree of key pairs — your root key, your wallet xpub, and the individual signing keys all come from the same seed. When the CLI generates a software key, it creates a BIP39 mnemonic and derives keys from it using BIP32. Write the mnemonic down if this is a real wallet.
Agent skills
Agent skills are markdown files that tell Claude Code how to use a specific tool. Installing nunchuk-io/agent-skills drops seven skill files into Claude's skill directory. Claude reads them and learns the exact commands, flags, and error patterns for each Nunchuk operation — so natural language like "create a 2-of-3 wallet" maps directly to the right CLI invocations.
Bounded authority
The core design principle: the AI doesn't have the wallet. It has a key in a multisig with a cap. If Claude goes rogue — hallucination, prompt injection, a malicious skill — it cannot authorize a spend above the daily limit without your cosignature. The cryptographic policy is the fence, and neither you nor the AI can remove it unilaterally.
Agenda
| Part | Topic | Time |
|---|---|---|
| 1 | Connecting Claude to Nunchuk — install CLI, authenticate, install skills | 15 min |
| 2 | Use cases for AI treasury agents — the why before the how | 10 min |
| 3 | Building the wallet — generate key, sandbox, Platform key, policy, finalize | 25 min |
| 4 | Putting it to work — send under cap, hit the fence, policy enforcement demo | 15 min |
Prerequisites
- Node.js and npm — required to install the Nunchuk CLI. Run
node --versionandnpm --versionto verify they're installed. - Claude Code — the CLI-based AI agent. You need an active session running during the walkthrough.
- Nunchuk API key — get one at developer.nunchuk.io before starting. The free tier is sufficient for testnet use.
- Testnet BTC — you'll need a small amount of testnet coins to fund a transaction. A quick web search for "bitcoin testnet faucet" will find a free source.
- Hardware wallet (optional) — for the human key in the 2-of-3. You can also use a second software key. The walkthrough notes where this choice matters.
Do this walkthrough on testnet first. Testnet coins have no monetary value — mistakes cost nothing. Switch to mainnet only after you've run the full flow at least once and understand what each step does.
Part 1: Connecting Claude to Nunchuk
1.1 Install the CLI
The Nunchuk CLI is a Node package that bundles the crypto, the Electrum client, and the Nunchuk API wrapper into a single binary. Install it globally so Claude can call it as a shell tool from any directory.
npm install -g nunchuk-cli
nunchuk --help
A successful install prints the command tree: auth, sandbox, wallet, tx, key, network, config. If the binary isn't found after install, check that your npm global bin directory is on your PATH.
What to tell Claude: "Install the Nunchuk CLI globally and confirm it's working."
1.2 Get an API key
Nunchuk's server brokers multisig coordination — sandbox invites, encrypted PSBT relay, and Platform key signing. You need an API key to identify yourself to it. This is not a custodial account: the server never sees your private keys, only encrypted blobs.
Go to developer.nunchuk.io, sign in, create an API key, and copy it to your clipboard. This is a manual browser step — paste the key into your terminal when prompted in the next step.
1.3 Authenticate
This writes your API key into ~/.nunchuk-cli/config.json and creates an AES-256-GCM encrypted SQLite database at ~/.nunchuk-cli/data/<emailHash>/<network>/storage.sqlite. Every key, sandbox, and wallet state lives here, encrypted row-by-row with a master key at ~/.nunchuk-cli/master.key.
nunchuk auth login --api-key <your-key>
Verify with nunchuk auth status — it should report that you're logged in and your local vault is initialized.
What to tell Claude: "Log into Nunchuk with this API key: <key>."
1.4 Install Agent Skills
Agent skills are markdown-based plugins that tell Claude when to use a capability and how to invoke it. Installing nunchuk-io/agent-skills drops seven skill files into Claude's skill directory, teaching it the exact commands and error patterns for each Nunchuk operation.
npx skills add nunchuk-io/agent-skills --all --global
What to tell Claude: "Install all Nunchuk agent skills globally."
After installation, seven skills become available: nunchuk-setup, nunchuk-wallet-creation, nunchuk-invitations, nunchuk-platform-key, nunchuk-wallet-management, nunchuk-wallet-transactions, and nunchuk-coldcard-hsm. Restart your Claude Code session so they load.
After restarting Claude Code, try asking: "What Nunchuk skills do you have?" Claude should list all seven skills and their descriptions, confirming the install worked.
1.5 Pick a network
Nunchuk supports mainnet (real BTC), testnet (free test coins), and signet. For this walkthrough, use testnet — mistakes cost nothing. Network state is stored in config and applies to all subsequent commands.
nunchuk network set testnet
All subsequent commands will talk to testnet endpoints and use testnet BIP32 derivation paths (m/48h/1h/... instead of m/48h/0h/...).
What to tell Claude: "Switch Nunchuk to testnet."
Part 2: Use Cases for AI Treasury Agents
Before building the wallet, it helps to anchor the why. The combination of CLI + agent skills + Platform key policies unlocks use cases that custodial apps can't touch and that hot wallets can't do safely:
- AI treasury agent — give Claude a key in a 2-of-3 with a $500/day cap. It pays invoices, rebalances between cold storage, files receipts. If it goes rogue, the limit holds.
- Automated payroll in BTC — a monthly disbursement run by an agent with a spending cap equal to payroll plus 10%. Humans cosign only if the agent tries to exceed the cap.
- Agent-to-agent micropayments — one AI buys data or compute from another, each bounded by policy so neither can drain the wallet.
- Bill-pay with a signing delay — a 24-hour delay on all spends gives you a cancellation window if something looks wrong before broadcast.
- Self-custody with a human safety net — you hold 1 key, Nunchuk Platform holds 1, Claude holds 1. Any 2 sign. You can recover from losing any single factor.
- Auditable agent actions — every agent spend is a real Bitcoin transaction. No opaque "the AI did something" — it's on-chain and visible in your wallet history forever.
The key distinction: the AI doesn't have the wallet. It has bounded signing authority on one key in a multisig. This is a fundamentally different security model than giving an agent a hot wallet or API key with full spending power.
Part 3: Building the Wallet
3.1 Generate the agent's key
This creates a BIP39 24-word mnemonic, derives a BIP32 root, and extracts the xpub at the multisig derivation path m/48h/1h/0h/2h (testnet, native segwit). The key lives encrypted in SQLite on this machine — Claude can use it to sign, but the mnemonic never leaves the device.
nunchuk key generate --name "Agent"
What to tell Claude: "Generate a new software key named Agent."
A fingerprint (8 hex characters) prints to confirm success. Run nunchuk key list to verify it's stored. If this is a real mainnet wallet, write the mnemonic down — losing the device without a backup means losing the key permanently.
On testnet, losing the key just means losing test coins. On mainnet, it means losing real funds. Back up the mnemonic before loading any mainnet value into the wallet.
3.2 Create the sandbox
A sandbox is the pre-finalization state of a multisig wallet. It holds the wallet structure (M-of-N, address type, name) while participants add their keys. Once all N slots are filled, you finalize it into a real wallet.
nunchuk sandbox create --name "Agent Wallet" --m 2 --n 3 --address-type NATIVE_SEGWIT
What to tell Claude: "Create a 2-of-3 native segwit sandbox called Agent Wallet."
A sandbox ID prints. Run nunchuk sandbox get <id> to confirm 3 empty slots with status PENDING.
3.3 Enable the Platform key
This tells the sandbox that one of the 3 keys will be Nunchuk's HSM-backed Platform key. You don't supply an xpub — the server contributes its own xpub to the descriptor. This is the key that spending policies will apply to.
nunchuk sandbox platform-key enable <sandbox-id>
What to tell Claude: "Enable the Platform key on sandbox <id>."
After this command, one slot shows as filled by Nunchuk. Two slots remain for you and the agent.
3.4 Set the policy
This defines the bounded authority. The --auto-broadcast flag means the Platform key will co-sign and push to the network any transaction under the daily limit without asking. Above the limit, it refuses — and there's no way for the agent to override this without your cosigning a dummy PSBT.
nunchuk sandbox platform-key set-policy <sandbox-id> \
--auto-broadcast \
--limit-amount 100 --limit-currency USD --limit-interval DAILY
What to tell Claude: "Set a $100/day spending limit on the Platform key with auto-broadcast."
Run nunchuk sandbox platform-key get <id> to confirm the policy is attached before moving on.
3.5 Add your key and the agent's key
Fill the remaining 2 slots. One is your human key (from a hardware wallet, Nunchuk mobile, or another software key); the other is the agent key you generated in 3.1. Exporting your hardware wallet xpub requires using your device's export function — the exact steps depend on your hardware wallet model.
# Agent's software key — already on this device
nunchuk sandbox add-key <sandbox-id> --slot 1 --fingerprint <agent-xfp>
# Your key — paste the descriptor exported from your hardware wallet or Nunchuk mobile
nunchuk sandbox add-key <sandbox-id> --slot 2 \
--descriptor "[abcd1234/48h/1h/0h/2h]xpub..."
What to tell Claude: "Add the agent's key to slot 1. I'll paste my hardware wallet descriptor for slot 2."
Run nunchuk sandbox get <id> to confirm all 3 slots are filled before finalizing.
3.6 Finalize
Finalizing turns the sandbox into a real wallet. The CLI assembles the multisig descriptor, computes a wallet ID (a hash of the descriptor), and stores the finalized wallet locally and server-side. After this step, the wallet can receive funds.
nunchuk sandbox finalize <sandbox-id>
nunchuk wallet address get <wallet-id>
nunchuk wallet export <wallet-id> > agent-wallet-backup.txt
What to tell Claude: "Finalize the sandbox, give me a receive address, and export a backup."
You'll get a wallet ID, a testnet bech32 address starting with tb1q..., and a descriptor backup file. Send testnet coins to the address from a faucet to fund it for the next steps.
Keep agent-wallet-backup.txt safe. It contains the full multisig descriptor. If you ever need to recover the wallet in a different app, you'll need this file plus the individual seed phrases for each key.
3.7 Policy updates require cosigning
To prove the agent cannot raise its own spending limit: Nunchuk constructs a dummy PSBT — a non-broadcastable transaction that encodes the policy change. The wallet's M signers must sign it for the change to take effect. This is the same cryptographic rail that guards real spends, repurposed for governance.
# Attempt to raise the limit
nunchuk wallet platform-key update <wallet-id> \
--limit-amount 1000 --limit-currency USD --limit-interval DAILY
# Nunchuk returns a dummy transaction ID requiring signatures
nunchuk wallet dummy-tx list <wallet-id>
nunchuk wallet dummy-tx sign <wallet-id> --dummy-tx-id <id>
# The agent's signature alone is not enough — you must cosign from your hardware wallet
What to tell Claude: "Try to raise the limit to $1,000/day. Show me the dummy transaction it generates."
Claude's signature alone is insufficient. You must cosign from your hardware wallet for the policy change to execute. This is the enforcement demo: the fence holds even against the agent's own requests.
Part 4: Putting It to Work
4.1 Agent sends under the cap
With the wallet funded and policy set, instruct Claude to send a transaction end-to-end — construct, sign with the agent key, and broadcast — all from a single natural-language prompt.
nunchuk tx create --wallet <wallet-id> --to <address> --amount 50 --currency USD
nunchuk tx sign --wallet <wallet-id> --tx-id <tx-id>
nunchuk tx broadcast --wallet <wallet-id> --tx-id <tx-id>
What to tell Claude: "Send $50 from the agent wallet to tb1q..."
Claude runs all three commands. The Platform key auto-cosigns (the amount is under the $100 daily cap) and the transaction is broadcast. Verify in a testnet block explorer that it went through.
4.2 Agent tries to exceed the cap
Now test the fence. Ask Claude to send more than the daily limit. The transaction creation and the agent's signing step will both succeed — but the Platform key will refuse its cosignature. The transaction stays PENDING_SIGNATURE until a human cosigns from their hardware wallet.
What to tell Claude: "Send $500 from the agent wallet."
Observe that tx create and the agent's tx sign both succeed, but the broadcast never happens. Run nunchuk tx list --wallet <wallet-id> to see the transaction stuck at PENDING_SIGNATURE. This is bounded authority working as designed.
PENDING_SIGNATURE is not an error — it's the system working. The transaction will complete as soon as the required cosignature is added. You can reject it entirely by double-spending the input from your hardware wallet if needed.
Reference Links
- Nunchuk Developer Portal — API key registration and documentation
- Agent Skills — the markdown-based plugin system for Claude Code
- nunchuk-io/agent-skills on GitHub — source for the seven Nunchuk skills
- HD Wallets and Extended Keys — BIP32 key derivation explained clearly
- What is a PSBT? — the Partially Signed Bitcoin Transaction standard explained