| name | saturnzap |
| description | Non-custodial Lightning wallet for AI agents via `sz` CLI: send/receive sats, pay invoices, auto-pay HTTP 402 (L402), manage channels and liquidity. Use when: (1) paying for API access with Lightning, (2) creating or paying BOLT11 invoices, (3) checking wallet balance or channel health, (4) managing peers and channels. NOT for: on-chain-only Bitcoin transactions, custodial Lightning services. |
| homepage | https://github.com/lqwdtech/SaturnZap |
| metadata | {"openclaw":{"emoji":"⚡","os":["linux"],"requires":{"bins":["sz"],"env":["SZ_PASSPHRASE"]},"optionalEnv":["SZ_MCP_MAX_SPEND_SATS","SZ_CLI_MAX_SPEND_SATS","SZ_NETWORK","SZ_REGION","SZ_MAINNET_CONFIRM","SZ_PRETTY","SZ_ALIAS","SZ_TRUSTED_PEERS_NO_RESERVE","SZ_ESPLORA_URL"],"primaryEnv":"SZ_PASSPHRASE","install":[{"id":"uv","kind":"uv","package":"saturnzap","bins":["sz"],"label":"Install SaturnZap (uv)"}]}} |
SaturnZap Lightning Wallet
Non-custodial Lightning Network wallet for autonomous AI agents. All output is JSON by default — no --json flag needed. Parse stdout for success ("status": "ok") and stderr for errors ("status": "error").
See {baseDir}/references/json-contracts.md for full JSON output shapes.
For deep agent integration scenarios, error recovery trees, and anti-patterns, see docs/agent-guide.md.
Quick Decision — 5 Most Common Agent Actions
sz setup --auto
sz fetch "https://api.example.com/data" --max-sats 100
sz status
sz invoice --amount-sats 1000 --memo "service fee" --wait
sz pay --invoice "lnbc..." --max-sats 5000
When to Use
✅ USE this skill when:
- Paying for API access via Lightning (L402 / HTTP 402 auto-pay)
- Creating BOLT11 invoices to receive payments
- Paying BOLT11 invoices or sending keysend payments
- Checking wallet balance (on-chain + Lightning)
- Opening, closing, or listing Lightning channels
- Connecting to or managing Lightning peers
- Monitoring channel liquidity health
- Requesting inbound liquidity from an LSP
When NOT to Use
❌ DON'T use this skill when:
- On-chain-only Bitcoin transactions (use a Bitcoin wallet CLI)
- Custodial Lightning services (use hosted APIs like Strike, LNBits)
- Non-Lightning crypto payments (ETH, stablecoins, etc.)
- Mainnet is the default network. Use
--network signet for development and testing with free test coins.
Setup
curl -LsSf https://raw.githubusercontent.com/lqwdtech/SaturnZap/main/install.sh | sh
export SZ_PASSPHRASE="your-secure-passphrase"
sz init --backup-to ~/.saturnzap-mnemonic --no-mnemonic-stdout
sz init --for-lqwd-faucet --backup-to ~/.saturnzap-mnemonic --no-mnemonic-stdout
sz status
sz service install
Passphrase injection — pick the safest available option
In order of preference:
-
Systemd EnvironmentFile= (recommended for production agents).
sz service install writes /etc/saturnzap/saturnzap.env (mode 0600,
owner-only) and references it from the systemd unit. The unit file itself
contains no secrets.
-
Secret store / environment injection at the agent runtime layer
(Vault, 1Password CLI, doppler, AWS Secrets Manager, etc.) writing
SZ_PASSPHRASE into the process environment.
-
Shell export in a non-shared session — fine for local development.
-
openclaw.json (development/testing only). This stores the passphrase
at rest in a config file. Use only on isolated dev machines and only when
the file is mode-0600 in an encrypted home directory:
{
"skills": {
"entries": {
"saturnzap": {
"enabled": true,
"env": { "SZ_PASSPHRASE": "your-dev-passphrase" }
}
}
}
}
Do not use this path for wallets holding production funds.
Security Model — Why This Skill Is Flagged "Suspicious" (And Why That's Correct)
SaturnZap is a self-custodial Lightning wallet. The ClawHub security scanner
correctly flags four behaviors that are inherent to any self-custodial wallet. If
you're evaluating this skill, read this section before installing.
1. Installs a vendored wheel from GitHub Releases. The --find-links flag pulls
the ldk-node Python bindings wheel from the SaturnZap GitHub Releases page. This is
because ldk-node is not yet published to PyPI. The wheel is built from the official
LDK Node v0.7.0 source, vendored in-repo at vendor/ldk_node-0.7.0-py3-none-any.whl,
and its SHA256 is pinned in vendor/ldk_node.sha256 (verified in CI on every push).
2. Emits a BIP39 mnemonic on first init. sz init prints the 24-word recovery
phrase exactly once, to stdout, so the operator can back it up. It is never
re-emitted by any other command. It is also never sent over the network. Losing the
mnemonic means losing the funds; that is the self-custody tradeoff.
3. Passphrase injection via openclaw.json. The passphrase decrypts the seed
file (Fernet AES-128 + PBKDF2, 600k iterations). It must be available on every
wallet operation. Two options:
- Environment variable (recommended):
export SZ_PASSPHRASE=... in your shell
profile or systemd unit. Never written to disk by SaturnZap.
openclaw.json: convenient for agents, but the passphrase lives in that file
at rest. Use only if the file itself is protected (0600, encrypted home dir,
etc.).
4. Optional systemd service. sz service install is optional. It keeps the
Lightning node running across reboots, which is necessary for payments to clear
reliably. The service runs as the invoking user, writes state under
~/.local/share/saturnzap/<network>/, and does not escalate privileges beyond
opening port 9735 via UFW if UFW is active.
What this skill does NOT do:
- Transmit the seed or passphrase anywhere
- Contact any server except Esplora (Bitcoin chain data) and peers you explicitly add
- Run with elevated privileges
- Modify any system config outside the Lightning listen port
Operator responsibilities:
- Back up the 24-word mnemonic offline before funding the wallet
- Use a strong passphrase (12+ chars; minimum enforced at init)
- Set
SZ_MCP_MAX_SPEND_SATS to cap agent spending
- Review
docs/security-scenarios.md in the SaturnZap repo for the full threat model
For the full security architecture, see
docs/security-scenarios.md.
Node Management
sz setup
sz setup --auto
sz init
sz start
sz stop
sz stop --close-all
sz status
sz connect-info
The node auto-starts when needed. Most commands call sz start internally if the node isn't running.
For agents: Prefer sz setup --auto over sz init — it's idempotent and handles the full first-run flow in one command.
Wallet
sz address
sz send <address> --amount 50000
sz send <address>
sz balance
Payment commands (pay, keysend, send) include pre-flight balance checks — they return a clear INSUFFICIENT_FUNDS error with the current balance if funds are too low.
Payments
sz invoice --amount-sats 1000 --memo "payment for data"
sz invoice --amount-sats 1000 --memo "service fee" --wait
sz invoice --amount-sats 0 --memo "tips welcome"
sz pay --invoice "lnbc..." --max-sats 5000
sz keysend --pubkey "03abc..." --amount-sats 500
sz transactions --limit 10
Spending Caps
Always use --max-sats when paying invoices on behalf of a user to enforce a spending limit. If the invoice exceeds the cap, the payment is rejected with a SPENDING_CAP_EXCEEDED error.
L402 (HTTP 402 Auto-Pay)
Fetch a URL and automatically pay the Lightning invoice if the server returns HTTP 402:
sz fetch "https://api.example.com/premium-data"
sz fetch "https://api.example.com/data" --max-sats 100
sz fetch "https://api.example.com/submit" \
-X POST \
-H "Content-Type: application/json" \
-d '{"query": "analysis"}' \
--max-sats 500
sz fetch "https://api.example.com/slow" --timeout 60
The response includes the HTTP status, body (parsed as JSON if possible), and payment details if a 402 was paid.
Channels
sz channels list
sz channels open --peer "03abc...@1.2.3.4:9735" --amount-sats 100000
sz channels open --lsp lqwd --amount-sats 100000
sz channels open --lsp lqwd --region JP --amount-sats 200000
sz channels open --lsp lqwd --amount-sats 100000 --no-announce
sz channels close --channel-id "abc123" --counterparty "03abc..."
sz channels close --channel-id "abc123" --counterparty "03abc..." --force
sz channels wait --channel-id "abc123" --timeout 300
Minimum channel sizes: LQWD nodes require at least 2,000,000 sats per channel. If the peer rejects, sz returns a CHANNEL_REJECTED error with the reason (e.g. "below min chan size").
Public routing by default: On mainnet, channels are announced to the gossip graph when the node is reachable from the internet, making the agent a public routing node automatically. The response includes announce and announce_reason (reachable, unreachable, non_mainnet_default, explicit, etc.). On unreachable, a warnings array suggests running sz connect-info --check and opening port 9735 on the cloud firewall. Override per-channel with --announce/--no-announce, or globally via sz config set node.announce_default never.
Peers
sz peers list
sz peers add "03abc...@1.2.3.4:9735"
sz peers remove "03abc..."
sz peers trusted-list
sz peers trust "03abc..."
sz peers untrust "03abc..."
Config
sz config list
sz config get node.alias
sz config set node.alias "my-agent"
sz config set node.listen_port 9735
sz config unset esplora_url
Changes apply on the next node start. Known keys: node.alias,
node.listen_port, node.min_confirms, node.trusted_peers_no_reserve,
esplora_url, network.
Liquidity
sz liquidity status
sz liquidity request-inbound --amount-sats 100000
sz liquidity request-inbound --amount-sats 100000 --region CA
Health scores range 0–100. Labels: healthy (40+), warning (20–40), critical (0–20).
Channels with offline peers are flagged as stale with force-close recommendations.
Service Management
sz service install
sz service status
sz service uninstall
When the systemd service is running, the node stays up between CLI calls (no per-command startup overhead).
Guardrails
- Always use
--max-sats on sz pay and sz fetch to enforce spending caps. Never pay unbounded invoices autonomously.
- Never expose the mnemonic — the seed phrase from
sz init must never appear in chat, logs, or tool output after initial display.
- Check balance first — payment commands now check balance automatically and return
INSUFFICIENT_FUNDS with the current balance. You can also run sz balance before large payments.
- Parse JSON output — all
sz commands output JSON to stdout on success, stderr on error. Use the status field to branch logic.
- Check for warnings —
sz pay, sz keysend, sz balance, and sz fetch may include a "warnings" array when channel capacity is low or no channels exist. Act on warnings: open a channel, request inbound liquidity, or log for review.
- Verify connectivity — after setup, run
sz connect-info --check to confirm the Lightning port is reachable. If "reachable" is false, the firewall may be blocking peers.
- Mainnet by default — SaturnZap defaults to Bitcoin mainnet (real sats). Use
--network signet for testing. Always use --max-sats spending caps on mainnet.
- Passphrase security —
SZ_PASSPHRASE encrypts the seed on disk. Keep it out of chat and logs.
Workflow Templates
Pay for API Access (L402)
sz balance
sz fetch "https://api.example.com/premium" --max-sats 100
Receive a Payment
sz invoice --amount-sats 1000 --memo "service fee" --wait
sz invoice --amount-sats 1000 --memo "service fee"
sz transactions --limit 1
Check Channel Health
sz liquidity status
sz balance
Open a Channel and Send Payment
sz channels open --lsp lqwd --amount-sats 100000
sz channels wait --timeout 300
sz pay --invoice "lnbc..." --max-sats 5000
Notes
- All output is JSON. Use
--pretty or SZ_PRETTY=1 for human-readable formatting.
- The node auto-starts from the encrypted seed when any command needs it. Explicit
sz start is rarely needed.
- LQWD region codes:
AI (LQWD-AI-Grid, default on mainnet, LSPS1/LSPS2 JIT-capable), NEAREST (timezone-based fallback), or a specific country: CA, US, SE, FR, GB, IE, IT, DE, BH, JP, AU, SG, HK, KR, ID, IN, BR, ZA.
sz fetch caches L402 tokens — repeated requests to the same endpoint reuse the token without re-paying.