You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Phase 2.5 / follow-up of #437. Auto-publish a NIP-05 mapping for any pod that ran with --provision-keys, so the pod owner's Nostr-flavoured identity becomes discoverable as name@domain by other Nostr clients.
Why
Phase 2 wired the provisioned key into the WebID profile and added the did:nostr: controller. NIP-05 is the standard "human-friendly identifier" layer on top of a Nostr pubkey: clients fetch https://<domain>/.well-known/nostr.json?name=<name> and expect { "names": { "<name>": "<pubkey hex>" } } (optionally with relays). JSS now has the pubkey and the domain; serving NIP-05 is one small route handler.
Shape
A single route handler at /.well-known/nostr.json. Returns a { names, relays?, nip46? } document built from whichever pods on this server have an owner key.
Per-pod vs shared aggregated
Subdomain mode (--subdomains + --base-domain): pods live at alice.example.com, bob.example.com. Each subdomain naturally serves its own .well-known/nostr.json — "one per pod" falls out for free. The handler reads the requesting Host, finds the matching pod, returns just that pod's mapping.
Path mode (default multi-user): pods live at example.com/alice/, example.com/bob/. There's only one origin, so only one .well-known/nostr.json. The handler aggregates: { names: { alice: "<pubkey-a>", bob: "<pubkey-b>", … } } for every pod with a provisioned key.
Single-user: trivially one mapping. Default name from --single-user-name (me by default), single entry.
The handler doesn't need separate code paths per mode — read the Host, list local pods, filter by host visibility, emit the mapping.
Design questions to settle
Default name. For a pod at /alice/, default the NIP-05 name to alice (matches the pod name)? Or require an explicit --nip05-name (or nip05Name in pod-creation body) to opt in per-pod?
Auto-include relays when --nostr is on? The pod's own /relay is an obvious entry. Could be [ "wss://<host>/relay" ]. Operators with their own relay infrastructure might want to override.
Auto-include nip46 (remote signer) when applicable, or leave for a follow-up?
Discovery boundary. NIP-05 names are public — surfacing every pod's name on /.well-known/nostr.json reveals the operator's pod inventory. Should multi-user mode default to opt-in per pod (operator-controlled) rather than auto-listing every pod?
My defaults if no answer: default name from pod name, opt-out via config (not opt-in — most operators want the discovery), auto-include wss://<host>/relay when --nostr is on, skip nip46 for now, source from the WebID profile's VM (no need to read the secret file).
Acceptance
GET /.well-known/nostr.json?name=<name> returns { names: { <name>: <pubkey-hex> } } for any pod with a provisioned key visible to the requesting host.
Subdomain mode: per-host filtering — alice.example.com/.well-known/nostr.json returns only alice's mapping.
Path mode: aggregated — example.com/.well-known/nostr.json returns all pods.
relays field auto-populated with the local relay URL when --nostr is on.
?name= query: when present, return only that name (per NIP-05); when absent, return everything.
Public read (no WAC) — NIP-05 verifiers don't authenticate.
Tests: route returns expected JSON for single-user, multi-user path mode, multi-user subdomain mode; query-filter; relay inclusion when --nostr on.
Out of scope
NIP-46 remote signer (could land in a follow-up if there's demand).
Per-pod overrides for relays / extra metadata. Phase 2.5 ships defaults; later iterations can add knobs.
Cross-domain proxying / CORS for NIP-05 verification beyond the standard Access-Control-Allow-Origin: *.
MVP (sub-issue feat: NIP-05 MVP — /.well-known/nostr.json for single-user pods (#445) #446) — single-user only, single name, no extras. Just GET /.well-known/nostr.json → { names: { <single-user-name>: <hex> } } from the profile VM. No relays, no ?name= filter, no aggregation. Multi-user returns 404.
Phase 2 — multi-user aggregation: path mode emits one combined index, subdomain mode filters per host. Adds the ?name= query filter per NIP-05 §3.
Phase 3 — relays field auto-populated when --nostr is on; per-pod opt-out / custom name knobs; nip46 if there's demand.
Phase 2.5 / follow-up of #437. Auto-publish a NIP-05 mapping for any pod that ran with
--provision-keys, so the pod owner's Nostr-flavoured identity becomes discoverable asname@domainby other Nostr clients.Why
Phase 2 wired the provisioned key into the WebID profile and added the
did:nostr:controller. NIP-05 is the standard "human-friendly identifier" layer on top of a Nostr pubkey: clients fetchhttps://<domain>/.well-known/nostr.json?name=<name>and expect{ "names": { "<name>": "<pubkey hex>" } }(optionally withrelays). JSS now has the pubkey and the domain; serving NIP-05 is one small route handler.Shape
A single route handler at
/.well-known/nostr.json. Returns a{ names, relays?, nip46? }document built from whichever pods on this server have an owner key.Per-pod vs shared aggregated
--subdomains+--base-domain): pods live atalice.example.com,bob.example.com. Each subdomain naturally serves its own.well-known/nostr.json— "one per pod" falls out for free. The handler reads the requesting Host, finds the matching pod, returns just that pod's mapping.example.com/alice/,example.com/bob/. There's only one origin, so only one.well-known/nostr.json. The handler aggregates:{ names: { alice: "<pubkey-a>", bob: "<pubkey-b>", … } }for every pod with a provisioned key.--single-user-name(meby default), single entry.The handler doesn't need separate code paths per mode — read the Host, list local pods, filter by host visibility, emit the mapping.
Design questions to settle
/alice/, default the NIP-05nametoalice(matches the pod name)? Or require an explicit--nip05-name(ornip05Namein pod-creation body) to opt in per-pod?relayswhen--nostris on? The pod's own/relayis an obvious entry. Could be[ "wss://<host>/relay" ]. Operators with their own relay infrastructure might want to override.nip46(remote signer) when applicable, or leave for a follow-up?/.well-known/nostr.jsonreveals the operator's pod inventory. Should multi-user mode default to opt-in per pod (operator-controlled) rather than auto-listing every pod?<pod>/private/privkey.jsonld(privileged) or from<pod>/profile/card.jsonldverificationMethod(public)? The latter is simpler — the public side is already exposed there since feat: --provision-keys Phase 2 — wire the owner key into the WebID profile, close the LWS-CID loop (#437) #443.My defaults if no answer: default name from pod name, opt-out via config (not opt-in — most operators want the discovery), auto-include
wss://<host>/relaywhen--nostris on, skipnip46for now, source from the WebID profile's VM (no need to read the secret file).Acceptance
GET /.well-known/nostr.json?name=<name>returns{ names: { <name>: <pubkey-hex> } }for any pod with a provisioned key visible to the requesting host.alice.example.com/.well-known/nostr.jsonreturns only alice's mapping.example.com/.well-known/nostr.jsonreturns all pods.relaysfield auto-populated with the local relay URL when--nostris on.?name=query: when present, return only that name (per NIP-05); when absent, return everything.--nostron.Out of scope
relays/ extra metadata. Phase 2.5 ships defaults; later iterations can add knobs.Access-Control-Allow-Origin: *.Refs #437.
Phased plan
GET /.well-known/nostr.json→{ names: { <single-user-name>: <hex> } }from the profile VM. No relays, no?name=filter, no aggregation. Multi-user returns 404.?name=query filter per NIP-05 §3.relaysfield auto-populated when--nostris on; per-pod opt-out / custom name knobs;nip46if there's demand.