Skip to content

feat: per-community workspace icon set by admins, served via NIP-11#1463

Merged
wesbillman merged 1 commit into
mainfrom
brain/workspace-icon
Jul 2, 2026
Merged

feat: per-community workspace icon set by admins, served via NIP-11#1463
wesbillman merged 1 commit into
mainfrom
brain/workspace-icon

Conversation

@wesbillman

@wesbillman wesbillman commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

What

Workspace-wide icon: relay owners/admins set it once, every member (and any NIP-11-aware client) sees the same icon in the workspace rail/switcher instead of name initials.

Direction per Tyler: the icon is per community/tenant and served just in NIP-11 — no custom snapshot event kind.

How

Relay

  • New admin command kind:9033 (["icon", <value>] tag), role-gated exactly like the neighboring 9030–9032 membership commands (NIP-43 admin/owner state). Values validated on ingest: http(s) or data:image/* only, no whitespace/control chars, size caps (2 KB URL / 96 KB data URL).
  • The accepted icon is stored as per-community state (communities.icon, additive migration 0003) and served in the standard NIP-11 icon field, bound to the community resolved from the request Host on all three NIP-11 serving paths (/info, nostr+json root, non-WS fallback).
  • Multi-tenant conformance: the RelayInfo::build static-input fence is preserved (the icon arrives as a pre-derived host-scoped scalar via bind_community), and the enumeration-oracle test now proves the served doc varies only by the requesting host's own icon — an unmapped host gets an icon-less document, never another tenant's icon.

Desktop

  • Admin/owner-gated "Workspace icon" editor in Settings → Relay Access; images are downscaled client-side to a 128px data URL before publishing 9033.
  • The rail/switcher read each workspace's icon with one unauthenticated NIP-11 HTTP GET (new fetch_workspace_icon Tauri command) — works for inactive workspaces with no WebSocket session — plus a localStorage cache so icons render instantly on boot and for unreachable relays, falling back to initials.

Docs

  • docs/nips/NIP-WP.md: spec for the 9033 write path + plain NIP-11 read path, including why NIP-86 changerelayicon (separate JSON-RPC surface/auth) and NIP-29 kind:39000 picture (per-group, not per-relay) were not used.
  • NOSTR.md cross-reference and the multi-tenant conformance table updated.

Testing

  • Full workspace Rust suite green against an isolated DB (incl. new nip11 unit tests + migration-count guard for 0003).
  • Desktop: check/typecheck/test (1494)/build, tauri check/test; both rustfmt passes + clippy clean.
  • Live-relay smoke, fresh DB, 18/18: no icon before set → owner sets → identical on all three NIP-11 paths → admin overwrite wins → plain member rejected → javascript:/non-image data: rejected → clear omits the field → unmapped Host gets the doc with no icon leak.

Adds a workspace-wide icon that owners/admins set once and every member
sees, replacing the initials-only avatars in the workspace rail.

Relay: new kind:9033 admin command (validated against relay_members role
like 9030-9032) stores the icon as per-community state
(communities.icon, additive migration 0003). The icon is served in the
standard `icon` field of the NIP-11 relay information document, bound to
the community resolved from the request Host; unmapped hosts get an
icon-less document (fail-open, no enumeration oracle — conformance test
updated to prove the doc varies only by the host's own icon). Icons are
small data:image/* URLs (or http(s) URLs), validated and size-capped on
ingest.

Desktop: admin/owner-gated "Workspace icon" editor in Settings > Relay
Access downscales the chosen image to a 128px data URL client-side and
publishes 9033. The rail and workspace switcher read each relay's
NIP-11 document with one unauthenticated HTTP GET (new
fetch_workspace_icon Tauri command) — active and inactive workspaces
alike — with a localStorage cache so icons render instantly on boot and
offline, falling back to initials.

Docs: draft NIP-WP (docs/nips/NIP-WP.md) specifying the kind:9033 write
path and the plain NIP-11 read path, including why NIP-86's
changerelayicon and NIP-29 group metadata were not used;
cross-referenced from NOSTR.md.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@wesbillman wesbillman force-pushed the brain/workspace-icon branch from 0454da0 to fc48cd8 Compare July 2, 2026 17:09
@wesbillman wesbillman changed the title feat: shared workspace icon set by relay admins/owners feat: per-community workspace icon set by admins, served via NIP-11 Jul 2, 2026
@wesbillman wesbillman merged commit 5bfd5ca into main Jul 2, 2026
29 checks passed
@wesbillman wesbillman deleted the brain/workspace-icon branch July 2, 2026 18:58
wpfleger96 added a commit that referenced this pull request Jul 2, 2026
…n-metrics

* origin/main:
  feat: per-community workspace icon set by admins, served via NIP-11 (#1463)
  perf(relay): batch outbound websocket data frames (#1464)
  Make reaction ingest atomic (#1458)
  Serialize fan-out EVENT frames once (#1459)
  fix: agent reliability — no restart on channel-add, visible dead-letter notice (#1468)

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

# Conflicts:
#	crates/buzz-relay/src/handlers/event.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant