Sure! All good questions!!
Why daemon + client?
The split exists because WhiteNoise initialization is expensive and stateful. The daemon (wnd) does a bunch of stuff on startup.
The client (wn) is a thin JSON-over-Unix-socket wrapper. Each command connects, sends one request, reads one response (or streams), and exits. This means for example `wn messages list` doesn't need to initialize the whole stack, it just asks the already-running daemon.
Does the daemon actively sync state?
Yes! It subscribes to Nostr relays for real-time updates and runs background maintenance tasks.
Does the daemon hold keys?
Not continuously in memory. Keys are stored in the platform's native keyring (macOS Keychain, Linux keyutils, etc.).
When the daemon needs to sign or decrypt, it calls get_signer_for_account() (mod.rs:834-855) which retrieves the key on-demand from the keyring. The nsec is only in-process transiently during signing operations, it's not cached in a struct field on the daemon.
We do have NIP-55/Amber support, but I haven't really tested doing anything with it on the CLI.
Socket auth: is there anything beyond Unix file permissions?
No. File permissions are the only security boundary. Any process running as the same OS user can connect and issue any command, including `export_nsec`. Any malicious process running as your user has full access to all accounts. This is standard for local daemon IPC, OS user isolation is the security boundary.