Skip to main content

CLI-first, non-custodial Lightning Network wallet for autonomous AI agents

Project description

SaturnZap

A CLI-first, non-custodial Lightning Network wallet built for autonomous AI agents.
Ultra-lightweight. Self-sovereign. No full Bitcoin node required.

CI PyPI Python versions License: MIT

sz init
sz channels open --lsp lqwd
sz pay --invoice lnbc1...
sz fetch https://api.example.com/data

What is SaturnZap?

SaturnZap is an open-source Lightning wallet designed from the ground up for AI agents operating without human supervision. The agent installs SaturnZap, initializes its own Lightning node, opens channels to any peer on the network, sends and receives Bitcoin payments, and autonomously pays for L402-gated APIs.

SaturnZap is a CLI tool. It is not a hosted wallet, not a custodial service, and not a web application. Keys live on the agent's machine. The agent IS the Lightning node.

Two ways to integrate:

  • CLI — call sz commands from any language, parse JSON from stdout
  • MCP Server — connect AI agents directly via Model Context Protocol (stdio)

Documentation: See the docs/ folder for detailed guides on getting started, configuration, MCP server integration, architecture, and JSON API reference.


Business Model

SaturnZap has two layers:

CLI — Open Source (MIT)

The sz command-line tool is free and open source under the MIT license. Anyone can install it, fork it, audit it, and build on it. There is no licensing fee, no API key required to use the software itself, and no telemetry.

LQWD (LSP)

SaturnZap ships pre-configured to use LQWD Technologies as its default Lightning Service Provider (LSP). LQWD operates 18 Lightning nodes across 18 countries with deep global channel liquidity.

When an agent uses LQWD's infrastructure, LQWD earns through:

  • Routing fees — sats earned as payments route through LQWD nodes
  • Channel leasing — fees for opening and providing inbound liquidity to agents
  • Managed connectivity — premium peering and reliability for agents that need it

LQWD is the default, not a requirement. Agents can open channels to any node on the Lightning Network. SaturnZap never enforces LQWD usage. LQWD competes on quality — 18-country coverage, deep liquidity, fast channel opens — not on lock-in.

This model mirrors how open-source software with cloud backends works: the tool is free, the infrastructure is the business.


Key Properties

  • Non-custodial — BIP39 seed lives encrypted on the agent's machine. SaturnZap never holds, transmits, or has access to private keys.
  • No full Bitcoin node — Esplora REST API provides chain data with automatic fallback (LQWD → blockstream.info → mempool.space). No bitcoind required.
  • Peer-agnostic — Open channels to any Lightning node. LQWD is a smart default with global reach, but the agent controls its own peer relationships entirely.
  • JSON-first — Every command writes structured JSON to stdout. Errors go to stderr. Designed for machine consumption from day one.
  • MCP-native — Built-in MCP server exposes 25 tools over stdio. Connect Claude, Cursor, VS Code, or any MCP-compatible agent with a single config block.
  • Autonomous — No interactive prompts in normal operation. Designed to run inside agent runtimes, shell scripts, and orchestration pipelines. (Mainnet spending commands prompt for confirmation unless --yes is passed.)

Architecture

Full architecture details: docs/architecture.md

Component Map

┌─────────────────────────────────────────────────────────┐
│                    Integration Layer                    │
│                                                         │
│  sz CLI          MCP Server         OpenClaw Skill      │
│  (typer)         (FastMCP/stdio)    (gateway)           │
│      │               │                  │               │
│      └───────────────┼──────────────────┘               │
│                      │                                  │
│              ┌───────▼───────┐                          │
│              │  IPC Client   │  (auto-detect daemon)    │
│              └───────┬───────┘                          │
└──────────────────────┼──────────────────────────────────┘
                       │ Unix Domain Socket (sz.sock)
┌──────────────────────▼──────────────────────────────────┐
│              Daemon (sz start --daemon)                  │
│                                                         │
│  IPC Server (asyncio) ─── Wallet Core                   │
│  22 JSON methods          node.py, payments.py, l402.py │
│  threading.Lock           liquidity.py, keystore.py     │
│  0600 socket perms        lqwd.py, config.py, output.py │
│                           ipc.py                        │
└──────────────────────┬──────────────────────────────────┘
                       │
┌──────────────────────▼──────────────────────────────────┐
│                    LDK Node                             │
│  - Full Lightning protocol implementation               │
│  - Esplora chain sync (LQWD → blockstream → mempool)   │
│  - BIP39 key management                                 │
│  - Peer connections and channel state machine           │
└──────────────┬────────────────────────┬─────────────────┘
               │                        │
┌──────────────▼──────────┐  ┌──────────▼──────────────────┐
│   LQWD Global Nodes     │  │   Any Lightning Node        │
│   (default — 18 nodes,  │  │   (agent can peer with      │
│   18 countries, deep    │  │   any public node on the    │
│   liquidity, LSPS)      │  │   Lightning Network)        │
└─────────────────────────┘  └─────────────────────────────┘

Key Design Decisions

Unix Domain Socket IPC

The daemon (sz start --daemon) owns the LDK node and exposes 22 methods over a Unix Domain Socket at ~/.local/share/saturnzap/<network>/sz.sock. CLI commands, the MCP server, and OpenClaw automatically detect the daemon and route through IPC — no port conflicts, no database locks. If no daemon is running, commands fall back to starting an ephemeral node.

Esplora chain sync with fallback

LDK Node syncs chain data via Esplora (block explorer REST API). No external Bitcoin node is needed. SaturnZap ships with a fallback chain — if the primary Esplora server is unreachable, it automatically probes alternatives (LQWD, blockstream.info, mempool.space) and connects to the first healthy endpoint. First sync takes a few minutes on a fresh install; subsequent starts are near-instant.

LQWD as default LSP

All 18 LQWD node pubkeys and connection strings are embedded in SaturnZap's default config. On sz init, the wallet automatically peers with the nearest LQWD node based on the system's timezone offset — each node has a UTC offset, and sz picks the one closest to yours. A server in UTC gets LQWD-England, one in EST gets LQWD-Canada, one in JST gets LQWD-Japan. Override with SZ_REGION=CA or --region CA to force a specific node. A fresh agent install goes from zero to channel-ready in under five minutes.

Peer-agnostic after init

After the initial channel, agents use standard Lightning channel open flows to peer with anyone. SaturnZap has no routing logic that artificially prefers LQWD — Lightning pathfinding selects the best route. LQWD nodes appear as attractive routes naturally because of their connectivity and capacity across 18 countries.

JSON-first, no interactive prompts

All commands are designed for non-interactive execution. No [y/N] confirmations. No spinners that break pipe parsing. Pass --pretty for human-readable output in a TTY. Default is always clean JSON.

Autonomous channel management

SaturnZap monitors channel health. When configured, it automatically opens new channels when outbound liquidity drops below a threshold, and requests inbound liquidity from the configured LSP when needed. Agents can run indefinitely without manual intervention.


Technology Stack

Component Library Notes
Language Python 3.12 Type hints throughout
Lightning node ldk-node 0.7.0 LDK Node Python bindings, Neutrino built-in
CLI framework typer Clean API, auto-generated help
HTTP client httpx Used for L402 interceptor
Config storage platformdirs + TOML OS-appropriate config paths
Key encryption cryptography Fernet encryption for seed file
BIP39 mnemonic Seed phrase generation
Package manager uv Fast, modern Python tooling
MCP server mcp ≥1.26 Model Context Protocol for AI agent integration
Testing pytest Unit + integration, 415 tests
Linting ruff Fast Python linter and formatter

LQWD Node Directory

Embedded in SaturnZap as trusted default peers. On sz init or sz channels open --lsp lqwd, the nearest node is auto-selected by comparing the system's UTC offset against each node's timezone — smallest offset difference wins. Override with SZ_REGION env var or --region flag. Full pubkeys and connection strings are in src/saturnzap/lqwd.py.

Alias Region
LQWD-Canada CA
LQWD-Sweden SE
LQWD-France FR
LQWD-England GB
LQWD-Japan JP
LQWD-Australia AU
LQWD-Brazil BR
LQWD-Bahrain BH
LQWD-Singapore SG
LQWD-SouthAfrica ZA
LQWD-HongKong HK
LQWD-SouthKorea KR
LQWD-Indonesia ID
LQWD-Ireland IE
LQWD-Italy IT
LQWD-Germany DE
LQWD-India IN
LQWD-US-West US

Full pubkeys and host:port connection strings are in src/saturnzap/lqwd.py. Signet/testnet node details maintained separately for development.


CLI Reference

Full JSON API reference: docs/json-api-reference.md

Binary: sz

All commands output JSON to stdout. Errors exit with code 1, written to stderr.

Global options:

sz --network bitcoin|signet|testnet <command>   # Select Bitcoin network (default: bitcoin)
sz --pretty <command>                             # Pretty-print JSON output

Node

sz init                          # Generate seed, start node, peer with nearest LQWD node
sz setup                         # Guided first-run: init + address (idempotent)
sz setup --auto                  # Non-interactive: init + address + request inbound from LQWD
sz start                         # Start the node (verify connectivity, then exit)
sz start --daemon                # Keep node running (for systemd); starts IPC server
sz stop                          # Stop the node daemon
sz stop --close-all              # Cooperatively close all channels, then stop
sz status                        # Node pubkey, sync state, peer/channel counts

Wallet

sz address                       # New on-chain receiving address
sz send <address>                # Send all on-chain sats to address
sz send <address> -a 50000       # Send specific amount on-chain
sz send <address> --yes          # Skip mainnet confirmation prompt
sz balance                       # Onchain + lightning balances, per-channel breakdown
sz transactions --limit 20       # Payment history

Peers

sz peers list
sz peers add <pubkey>@<host>:<port>
sz peers remove <pubkey>

Channels

sz channels list

# Open to any node
sz channels open --peer <pubkey>@<host>:<port> --amount-sats 100000

# Open via LQWD — nearest node automatically selected
sz channels open --lsp lqwd --amount-sats 100000

# Open via LQWD in a specific region
sz channels open --lsp lqwd --region JP --amount-sats 100000

# Skip mainnet confirmation (for automation)
sz channels open --lsp lqwd --amount-sats 100000 --yes

sz channels close --channel-id <id>
sz channels close --channel-id <id> --force

# Wait for a channel to become usable (blocks until ready or timeout)
sz channels wait --channel-id <id> --timeout 300

Payments

sz invoice --amount-sats 1000 --memo "for data"
sz invoice --amount-sats 1000 --wait    # Block until paid or expired
sz pay --invoice lnbc1...
sz pay --invoice lnbc1... --max-sats 500    # spending cap for agent safety
sz pay --invoice lnbc1... --yes             # skip mainnet confirmation
sz keysend --pubkey <pubkey> --amount-sats 100
sz keysend --pubkey <pubkey> --amount-sats 100 --yes

L402 — Autonomous API Payments

# Auto-detects HTTP 402, pays invoice, retries request, returns body
sz fetch https://api.example.com/data

# With per-request spending cap
sz fetch https://api.example.com/data --max-sats 100

# With custom headers
sz fetch https://api.example.com/data --header "X-Custom: value"

Liquidity

sz liquidity status
sz liquidity request-inbound --amount-sats 500000

Service Management

sz service install               # Install and start systemd service
sz service status                # Check service status
sz service uninstall             # Stop and remove systemd service

MCP Server

sz mcp                           # Start MCP server on stdio (for AI agent integration)

Or use the standalone entry point:

sz-mcp                           # Same as sz mcp

Agent configuration (Claude Desktop, Cursor, VS Code, etc.):

{
  "mcpServers": {
    "saturnzap": {
      "command": "sz",
      "args": ["mcp"],
      "env": {
        "SZ_PASSPHRASE": "your-passphrase"
      }
    }
  }
}

The MCP server exposes 25 tools covering node lifecycle, wallet, peers, channels, payments, L402 fetch, and liquidity management. Set SZ_MCP_MAX_SPEND_SATS to enforce a global per-request spending cap on L402 payments.


JSON Output Format

sz balance

{
  "status": "ok",
  "network": "signet",
  "onchain_sats": 0,
  "lightning_sats": 45000,
  "channels": [
    {
      "channel_id": "abc123",
      "peer_pubkey": "036491...",
      "peer_alias": "LQWD-Canada",
      "capacity_sats": 100000,
      "outbound_sats": 45000,
      "inbound_sats": 55000,
      "state": "open"
    }
  ]
}

sz pay

{
  "status": "ok",
  "network": "signet",
  "payment_hash": "def456...",
  "amount_sats": 1000,
  "fee_sats": 1,
  "duration_ms": 342
}

sz fetch (L402 flow)

{
  "status": "ok",
  "network": "signet",
  "url": "https://api.example.com/data",
  "payment_hash": "ghi789...",
  "amount_sats": 10,
  "fee_sats": 1,
  "http_status": 200,
  "body": {}
}

Error (any command)

{
  "status": "error",
  "code": "INSUFFICIENT_OUTBOUND_LIQUIDITY",
  "message": "Not enough outbound liquidity. Available: 200 sats, required: 1000 sats."
}

Exit Codes

Code Meaning
0 Success
1 General error
2 Node not running — run sz start
3 Insufficient funds
4 Channel not found
5 Peer unreachable
6 Invoice expired or invalid
7 LSP request failed

Project Structure

/
├── README.md
├── LICENSE                        # MIT
├── pyproject.toml                 # Package definition, sz entry point
├── uv.lock
├── .env.example                   # Environment variable template
│
├── docs/
│   ├── getting-started.md         # Installation and first-run guide
│   ├── configuration.md           # Config file and env var reference
│   ├── mcp-server.md              # MCP server setup and tool reference
│   ├── architecture.md            # Design decisions and component map
│   └── json-api-reference.md      # Full JSON shapes for all commands
│
├── src/
│   └── saturnzap/
│       ├── __init__.py
│       ├── cli.py                 # Typer app — all sz commands
│       ├── node.py                # LDK Node lifecycle + channels + peers
│       ├── payments.py            # Send / receive / invoice / keysend
│       ├── l402.py                # L402 HTTP interceptor
│       ├── liquidity.py           # Channel health scoring + recommendations
│       ├── keystore.py            # BIP39 seed, Fernet encryption
│       ├── lqwd.py                # LQWD node directory (18 regions)
│       ├── config.py              # Config paths, Esplora fallback, TOML loader
│       ├── mcp_server.py          # MCP server — 25 tools for AI agents
│       ├── service.py             # Systemd service generator
│       └── output.py              # JSON output, TTY detection, --pretty
│
├── tests/
│   ├── test_cli.py                # CLI smoke tests
│   ├── test_keystore.py           # Seed encryption
│   ├── test_node.py               # Node lifecycle + channel rejection
│   ├── test_ipc.py                # IPC layer
│   ├── test_payments.py           # Payment helpers
│   ├── test_l402.py               # L402 parsing
│   ├── test_liquidity.py          # Health scoring
│   ├── test_config.py             # Config + env vars
│   ├── test_mcp_server.py         # MCP server
│   ├── test_backup.py             # Backup/restore
│   ├── test_service.py            # Systemd service
│   ├── test_lqwd.py               # LQWD directory
│   ├── test_output.py             # JSON output
│   ├── integration/               # Multi-command flows
│   ├── security/                  # Input validation, spending guards
│   ├── reliability/               # Edge cases, concurrency
│   ├── ux/                        # Agent workflow scenarios
│   └── live/                      # Droplet tests (@live marker)
│
├── skills/
│   └── saturnzap/
│       ├── SKILL.md               # OpenClaw skill definition
│       └── references/
│           └── json-contracts.md  # Full JSON output reference
│
├── vendor/
│   └── ldk_node-0.7.0-py3-none-any.whl  # LDK Node Python bindings (Linux x86_64)
│
├── security/
│   ├── security_scan.py
│   └── profiles/
│       └── saturnzap.yaml
│
├── hooks/
│   ├── pre-commit
│   └── pre-push
│
└── .github/
    └── workflows/
        ├── ci.yml                 # Lint + test on push/PR
        └── publish.yml            # PyPI publish on version tags

Development Environment

OS Ubuntu 24.04 (DigitalOcean Droplet, 2GB RAM / 2 vCPU)
Editor VS Code via Remote SSH
Python 3.12
Network Bitcoin mainnet (default) / signet / testnet — selectable via --network
Chain source Esplora REST API with automatic fallback chain
LQWD nodes 18 regions, pubkeys embedded in src/saturnzap/lqwd.py

Droplet Setup

# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env

# Clone and install
git clone https://github.com/lqwdtech/SaturnZap
cd saturnzap
uv venv
source .venv/bin/activate
uv sync

# Run
sz --help

Install from PyPI

# ldk-node is not yet on PyPI — use --find-links to pull it from GitHub Releases
pip install saturnzap --find-links https://github.com/lqwdtech/SaturnZap/releases/latest/download/

# Or with uv
uv pip install saturnzap --find-links https://github.com/lqwdtech/SaturnZap/releases/latest/download/

Development Phases

Phase 1 — Node Foundation ✅

sz init, sz start, sz stop, sz status

BIP39 seed generation, encrypted storage, LDK Node startup, Esplora chain sync, auto-peer with nearest LQWD node, JSON output infrastructure.

Phase 2 — Channel Management ✅

sz channels, sz peers, sz address, sz balance

Open channels to any node. LQWD LSP-assisted channel opens. LQWD node directory embedded (18 regions, timezone-based auto-selection). Channel list and close.

Phase 3 — Payments ✅

sz invoice, sz pay, sz keysend, sz transactions

Full BOLT11 send and receive. Variable-amount invoices. Keysend. Transaction history with sorting and pagination.

Phase 4 — L402 ✅

sz fetch

HTTP client with 402 detection, invoice extraction, auto-pay, request retry. Per-request spending caps. Token caching to avoid re-paying the same resource.

Phase 5 — Liquidity Intelligence ✅

sz liquidity

Channel health monitoring with 0-100 scoring. Actionable recommendations. Inbound liquidity requests via LQWD. Geography-aware peer selection across 18 regions.

Phase 6 — Packaging and Integration ✅

pip install saturnzap / uv add saturnzap / sz mcp

MCP server with 25 tools. Esplora fallback chain. GitHub Actions CI/CD. PyPI packaging. OpenClaw skill definition. Security scanner (Grade A+).

Phase 7 — Mainnet Support ✅

sz --network bitcoin

Network selection via CLI flag (--network signet|testnet|bitcoin), config.toml, or default. Network-namespaced data directories isolate wallets per network. Real LQWD mainnet node directory (18 nodes). Mainnet safety confirmation prompt on spending commands, skippable with --yes flag or SZ_MAINNET_CONFIRM=yes. Network field included in all JSON responses.

Upcoming

  • PyPI publish (trusted publisher workflow ready)
  • Docker image
  • OpenClaw ClawHub listing

Responsible Use

SaturnZap is non-custodial software. You hold your own keys, and you are solely responsible for your funds. It is provided under the MIT license on an "as is" basis — the usual open-source terms apply. A few practical suggestions:

  • Start with small amounts on mainnet while you get comfortable with the tooling.
  • Back up your seed phrase somewhere safe and offline. Without it, there is no recovery path.
  • Use --network signet for development and integration testing — signet coins are free and isolated from your mainnet wallet.
  • Set spending caps (--max-sats, SZ_CLI_MAX_SPEND_SATS, SZ_MCP_MAX_SPEND_SATS) when running autonomous agents.

See SECURITY.md for the threat model and disclosure policy.


License

MIT License. See LICENSE.

The SaturnZap CLI is free and open source. LQWD infrastructure services are commercial. Using SaturnZap with non-LQWD peers requires no agreement with LQWD Technologies.


About LQWD

LQWD Technologies Corp (TSXV: LQWD | OTCQX: LQWDF) is a publicly traded Lightning Network infrastructure company. LQWD operates 18 Lightning nodes across 18 countries, providing routing infrastructure, liquidity services, and LSP connectivity for agents and developers building on Bitcoin's Lightning Network.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

saturnzap-1.0.2.tar.gz (149.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

saturnzap-1.0.2-py3-none-any.whl (53.1 kB view details)

Uploaded Python 3

File details

Details for the file saturnzap-1.0.2.tar.gz.

File metadata

  • Download URL: saturnzap-1.0.2.tar.gz
  • Upload date:
  • Size: 149.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for saturnzap-1.0.2.tar.gz
Algorithm Hash digest
SHA256 4499f35a830619c72678c4504f5e48e72e197c194b1717eb4586a0e078eba894
MD5 22aea92ba3279bbb16436bb115aeb0de
BLAKE2b-256 494dd1c3438095adfdfafd4fd0a98b5d6ed456f1f26b7b7ff86d29f9e99ec506

See more details on using hashes here.

Provenance

The following attestation bundles were made for saturnzap-1.0.2.tar.gz:

Publisher: publish.yml on lqwdtech/SaturnZap

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file saturnzap-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: saturnzap-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 53.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for saturnzap-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 b559ebb4b1ecf30c3362cf4945bc12653799953e60181bbadf4f4ca53b8b7018
MD5 f6ed9aff947cb7a72573af95cfb083d1
BLAKE2b-256 ea9f51683387a3e5f3510ddc7cabf1fcae2ede878a497eabf2ca00065a8a55fb

See more details on using hashes here.

Provenance

The following attestation bundles were made for saturnzap-1.0.2-py3-none-any.whl:

Publisher: publish.yml on lqwdtech/SaturnZap

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page