Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ This installs a `commit-msg` hook that adds the sign-off trailer automatically f

We review as capacity allows — focused PRs that follow this guide move fastest.

Hosted community vs Buzz identity questions (Builderlab email vs nsec) are covered in [docs/hosted-community-identity.md](docs/hosted-community-identity.md).

---

## Setting Up the Development Environment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -517,15 +517,26 @@ export function HostedCommunityOnboarding({
</DialogTitle>
<DialogDescription className="mt-2 text-sm leading-6 text-foreground">
Your Builderlab account
{auth.email ? ` (${auth.email})` : ""} is ready. Connect this
device’s Buzz identity to finish setup. Your private key stays
on this device.
{auth.email ? ` (${auth.email})` : ""} is ready. Connect the
Buzz identity already on this device to finish setup. Your
private key stays on this device — Builderlab never receives
it.
</DialogDescription>
<p
className="mt-4 w-full text-left text-xs leading-5 text-foreground/55"
data-testid="hosted-connect-identity-hint"
>
Need a different Buzz private key for this email? Close this
dialog, open Settings → Account, sign out of the current
identity (back up the nsec first), then import or create a new
key and return here to connect.
</p>
{errorBox ? <div className="mt-5 w-full">{errorBox}</div> : null}
<Button
className={`mt-6 ${MODAL_PRIMARY_ACTION_CLASS}`}
disabled={busy}
onClick={() => void connectIdentity()}
data-testid="hosted-connect-identity"
>
{busy ? (
<LoaderCircle className="h-4 w-4 animate-spin" />
Expand All @@ -539,8 +550,10 @@ export function HostedCommunityOnboarding({
This account uses a different Buzz identity
</DialogTitle>
<DialogDescription className="mt-2 text-sm leading-6 text-foreground">
This account is connected to another Buzz identity. Reconnect
this device, or sign out to use a different email.
This Builderlab account is already linked to a different Buzz
identity. Use this device&apos;s key (rebinds the account), sign
in with a different email, or switch the local Buzz identity
under Settings → Account before reconnecting.
</DialogDescription>
<p className="mt-4 w-full break-all rounded-xl bg-[rgb(var(--buzz-hosted-community-identity-bg)/0.5)] px-4 py-3 text-left font-mono text-xs text-foreground">
Account: {identity.npub ?? boundPubkey}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,9 @@ export function HostedCommunitiesSettingsCard() {
This Builderlab account isn&apos;t linked to a Buzz identity
yet. Connect this device&apos;s key to create and own
communities under it — Buzz signs a one-time challenge locally,
so your private key never leaves Desktop.
so your private key never leaves Desktop. To link a different
nsec, switch identities under Account (sign out, then import or
create) before connecting.
</p>
<Button
className="mt-4"
Expand Down
5 changes: 4 additions & 1 deletion desktop/tests/e2e/onboarding.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,10 @@ test("first-community owner can create and connect a hosted community", async ({
await expect(
page.getByRole("heading", { name: "Finish connecting Buzz" }),
).toBeVisible();
await page.getByRole("button", { name: "Connect and continue" }).click();
await expect(page.getByTestId("hosted-connect-identity-hint")).toContainText(
"different Buzz private key",
);
await page.getByTestId("hosted-connect-identity").click();
const createSurface = page.getByTestId("hosted-community-create-surface");
const surfaceBoxBeforeFeedback = await createSurface.boundingBox();
const communityNameInput = page.getByTestId("hosted-community-address-input");
Expand Down
34 changes: 34 additions & 0 deletions docs/hosted-community-identity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Hosted communities and Buzz identity

Builderlab (hosted community) accounts are **email logins**. Buzz identities
are **Nostr keypairs** stored in the OS keyring on each device. Connecting
binds the current device key to that Builderlab account — it does **not**
generate a second identity for the email.

## Common confusion (#3880)

Symptom: after signing into Builderlab with a work email, the app asks to
"Finish connecting Buzz" / "Connect this device's Buzz identity," and there
is no "create a new private key" button on that screen.

That is intentional. The bind step always uses the key already on the device.

### Want a different key for this Builderlab email?

1. Back up the current nsec (Settings → Account → private key backup).
2. Sign out of the Buzz identity (Settings → Account → Sign out).
3. Import an nsec or create a fresh identity during onboarding.
4. Return to hosted community setup and connect again.

### Want the same Buzz identity on another machine?

Import the same nsec on that machine (do not generate a new key), then connect
the Builderlab account. Binding a different local key to an account that is
already linked shows the mismatch dialog ("This account uses a different Buzz
identity").

### Want a different Builderlab email with the same key?

Sign out of Builderlab (hosted community flow / settings), sign in with the
other email, then connect — the local Buzz key can be linked to multiple
Builderlab accounts over time, but each account stores one linked npub.