Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture

Caparra is a host for plugs: the BNAP socket sits in one small crate, every plug point is a Rust trait, and the binaries assemble the plugs an operator chooses. This page maps the BNAP v0.5 overview’s crate plan onto the workspace.

Crate map

The overview groups the crates into families:

FamilyRoleWorkspace crates today
bnap-coreThe socket: Offer, envelope, Digest, use store logic, outcome state machine, receipts, test vectorsbnap-core
bnap-plugThe plug traits, plus the WIT interface definition generated from thembnap-plug
bnap-scheme-*Credential schemesbnap-scheme-notes, bnap-scheme-l402, bnap-scheme-mpp, bnap-scheme-webbotauth, bnap-scheme-dpop
bnap-rail-*Settlement railsbnap-rail-phoenixd, bnap-rail-nwc, bnap-rail-lnd, bnap-rail-fake
bnap-store-*Use storesbnap-store-postgres, bnap-store-sqlite, bnap-store-tests
bnap-signer-*Offer and receipt signersbnap-signer-file, bnap-signer-process
bnap-carrier-*Carriers that move BNAP messagesbnap-carrier-http, bnap-carrier-mcp
ApplicationsThe gateway, the client wallet, the MCP server and the CLIcaparra-gate, caparra-wallet, bnap-mcp, bnap-cli

Workspace crates

CrateKindRole
bnap-corelibraryCore protocol types, encoding and verification logic, free of I/O
bnap-pluglibraryPlug traits that connect signers, stores, schemes, rails and carriers to the core
bnap-scheme-noteslibraryPayment scheme that accepts Cashu ecash notes (bnap:notes, the default scheme)
bnap-scheme-l402libraryL402: macaroon plus Lightning invoice
bnap-scheme-mpplibraryThe Machine Payments Protocol (MPP)
bnap-scheme-webbotauthlibraryWeb Bot Auth, based on HTTP Message Signatures
bnap-scheme-dpoplibraryProof of possession based on DPoP (RFC 9449)
bnap-rail-phoenixdlibrarySettlement through a phoenixd Lightning node
bnap-rail-nwclibrarySettlement over Nostr Wallet Connect (NIP-47)
bnap-rail-lndlibrarySettlement through an LND node over gRPC
bnap-rail-fakelibraryIn-memory rail for tests and local development
bnap-store-postgreslibraryPostgreSQL use store
bnap-store-sqlitelibrarySQLite use store
bnap-store-testslibraryConformance suite every use store must pass
bnap-signer-filelibrarySigner backed by a key file on local disk
bnap-signer-processlibrarySigner that delegates to an external process
bnap-carrier-httplibraryBNAP messages in HTTP requests and responses
bnap-carrier-mcplibraryBNAP messages in MCP tool calls and results
caparra-gatebinary caparra-gateGate in front of an HTTP or MCP service that enforces payment and authorization
caparra-walletlibraryClient wallet that holds funds and answers payment challenges
bnap-mcpbinary bnap-mcpMCP server exposing wallet and payment tools to agents
bnap-clibinary bnapCommand-line tool for inspecting, paying and testing BNAP flows

The three binaries are the ones release builds ship.

Planned, not in the workspace yet

The overview also names plugs that have no crate yet: the x402, privpass and oauth schemes; the ldk, ark and fedimint rails plus the off-by-default x402-evm and mpp-card rails; a KMS-unwrap signer; and SASL and Nostr carriers.

How the pieces fit

           caparra-gate   caparra-wallet   bnap-mcp   bnap (bnap-cli)
                 \              |              |          /
                  +-------------+--------------+---------+
                                |
      schemes   rails   stores   signers   carriers      (the plugs)
                                |
                            bnap-plug                    (the plug traits)
                                |
                            bnap-core                    (the socket, no I/O)

The socket owns everything that must be computed one way only. Per the overview, only bnap-core computes the OfferID, Context, Digest and ReplayKey, prefixes use IDs, compares value with price, commits uses and builds every message the signer signs. A scheme gets a capped signer that can verify notes and sign blinded outputs up to the change cap bnap-core computed, and nothing more. Every other plug gets read access to what it needs and returns data.

TODO: replace the sketch above with the dependency graph the crates actually have once they depend on each other, and link each plug trait to its rustdoc.

Ways to load a plug

WayForIsolationPlanned release
Compiled in (Cargo features)First-party plugsSame processv0.5
Sidecar over gRPC or HTTP, same interfaceAny language and heavy dependenciesSeparate processv0.6
WASM component (WIT world bnap:plug)Third-party schemes, pricers and judgesSandbox with fuel and memory limitsv0.7

Fronts

Operators on any stack can put caparra-gate in front of a service as a standalone proxy or behind Envoy ext_authz, Caddy forward_auth or nginx auth_request, so they need no Rust of their own.

Workspace rules

  • One secp256k1 per dependency tree, taken through the bitcoin re-export (bitcoin::secp256k1). cargo deny fails CI on a second copy.
  • Shared dependency versions live in [workspace.dependencies]; member crates use dep.workspace = true.
  • The minimum supported Rust version is 1.94. CI checks it on every push.
  • unsafe code is forbidden workspace-wide.