Chat-first Fedimint wallet PWA with an LLM-powered agent.
The project uses a Nix flake (flake.nix) for a reproducible dev shell. Enter it with:
nix develop # if experimental features are enabled globally
# or
nix --extra-experimental-features 'nix-command flakes' developThe shell provides:
- Rust stable (via
rust-overlay) with thewasm32-unknown-unknowntarget - Trunk 0.21 for building and serving the WASM app
- wasm-bindgen-cli, binaryen for post-processing
- clang as the C/C++ compiler for wasm32 native dependencies
- cargo-leptos, leptosfmt, cargo-nextest
- Node.js 22 + Chromium for Playwright-based E2E tests
Key environment variables set by the shell:
| Variable | Purpose |
|---|---|
CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUSTFLAGS |
--cfg getrandom_backend="wasm_js" |
CC_wasm32_unknown_unknown |
Points to unwrapped clang for wasm linking |
PLAYWRIGHT_BROWSER_EXECUTABLE_PATH |
Nix-provided Chromium |
trunk build # production build to dist/
trunk serve # dev server on http://127.0.0.1:8080Trunk reads Trunk.toml which points at crates/fedigents-web/index.html as the entry point. The HTML uses data-trunk links to pull in the Rust binary, CSS, and static assets (manifest, service worker, icon, skills directory).
┌─────────────────────────────────────────────────┐
│ Browser main thread │
│ │
│ main.rs ─── app.rs (Leptos CSR UI) │
│ │ │
│ ├── agent.rs (WalletAgent) │
│ │ Uses rig-core 0.30 to │
│ │ drive an LLM tool-use loop │
│ │ via PPQ (OpenAI-compat API) │
│ │ │
│ └── wallet_runtime.rs │
│ WalletRuntime (thin client)│
│ ↕ postMessage (JSON) │
├─────────────────────────────────────────────────┤
│ Web Worker thread │
│ │
│ wallet_runtime.rs ── run_worker_entrypoint() │
│ ↕ │
│ fedimint.rs ── WalletRuntimeCore │
│ Fedimint client SDK │
│ OPFS-backed redb database │
└─────────────────────────────────────────────────┘
The same WASM binary serves both contexts. On load it checks web_sys::window():
- Window present → main thread: mounts the Leptos app.
- Window absent → worker thread: runs
run_worker_entrypoint(), which listens forpostMessagecommands from the main thread.
Leptos 0.7 in CSR (client-side rendering) mode. A single App component manages:
- Wallet bootstrap flow (connect → first deposit → PPQ funding)
- Chat interface with markdown rendering and inline QR codes
- Payment confirmation card for outgoing Lightning payments
- QR scanner via
leptos-qr-scanner - Background receive watchers that push notifications into the chat
Uses rig-core 0.30 with its ToolDyn trait for dynamic tool dispatch. The agent talks to claude-haiku-4.5 through PPQ (OpenAI-compatible API).
A single WalletTool enum implements ToolDyn with six variants:
| Tool | Description |
|---|---|
get_balance |
Returns current wallet balance in sats |
create_invoice |
Creates a BOLT11 invoice to receive a payment |
propose_payment |
Proposes an outgoing Lightning payment for user confirmation |
list_operations |
Lists recent wallet operations (waits 200ms for non-final ops to settle) |
show_receive_code |
Shows the wallet's LNURL receive code |
load_skill |
Loads a skill prompt by slug from the skills catalog |
Tool parameter schemas are auto-generated from schemars::JsonSchema derives with doc comments providing descriptions.
The main thread's WalletRuntime is a thin async client that serializes Command enums to JSON, posts them to the Web Worker, and awaits responses via oneshot channels. The worker deserializes commands, calls WalletRuntimeCore, and posts back ResponseEnvelope messages.
Two event streams flow worker → main thread outside the request/response cycle:
- Bootstrap events: progress notes, receive code, balance updates during initial setup
- Operation events: payment settlement notifications from background watchers
WalletRuntimeCore wraps the Fedimint client SDK. It:
- Joins a federation and initializes wallet/mint/LN modules
- Uses OPFS
FileSystemSyncAccessHandlefor the redb database (viafedimint-cursed-redb) - Falls back to
LocalStoragewhen sync access handles are unavailable - Manages LNURL recurring receive subscriptions
- Spawns background watchers for incoming LN payments that trigger cached outcome settlement
PPQ provides an OpenAI-compatible LLM API funded via Lightning. On first run, Fedigents:
- Creates a PPQ account (stored in Fedimint client metadata)
- Funds it with a $0.10 Lightning payment
- Uses the API key for all subsequent agent calls
public/sw.js— Service worker for PWA offline supportpublic/manifest.webmanifest— PWA manifestpublic/icon.svg— App iconskills/— Skill catalog (index.json + prompt files) loaded at runtimecrates/fedigents-web/src/browser.js— JS glue for OPFS, service worker registration, clipboard, and worker creationcrates/fedigents-web/src/wallet-worker.js— Worker bootstrap script