Messages you own. A local-first chat client in one self-contained HTML file — no build, signs in with your Nostr key via the universal xlogin pill.
Pigeon stores your messages on your own Solid pod and uses Nostr purely for identity and discovery — not as the message transport. No phone number, no servers you don't control.
Identity did:nostr (your Nostr pubkey is your DID)
Discovery Nostr relays — your pod's built-in relay first, aggregator as fallback
Storage your Solid pod (durable, owned, addressable) + local-first cache
Realtime the pod's WebSocket notifications
Pigeon is served from your pod. With a local jspod:
npx jspod --nostr --git
# then open http://localhost:5444/public/apps/pigeon/
Tap the cloud to connect (NIP-07 extension or private key), and your identity resolves to your pod through the shared bridges resolver.
Your contacts are the people you follow who have storage:
- Sync Contacts (☰ menu) signs a
kind:3follow list with your key and publishes it to your pod's own relay — so the roster works locally and across your devices, independent of any aggregator being up. - Each follow resolves same-origin to their pod; those with a bridged pod show as Ready, the rest as Invite (the "upgrade to storage" growth loop).
Part of the solid-apps ecosystem. Sibling apps:
- bridges — link your Nostr key to a Solid pod (the resolver Pigeon shares).
- yap — the relay-transport messenger (NIP-04 encrypted DMs). Pigeon is the pod-first take on the same idea; the two converge over time.
v0.1 — the shell, identity, roster, discovery, and pod-relay sync are working.
The encrypted 1:1 DM send/receive path is next.