镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

fix(identity): never strand first run on a key another account holds - #2996

Merged
loganj merged 7 commits into
mainfrom
loganj/first-run-foreign-key
Nov 7, 2026
Merged

loganj merged 7 commits into
mainfrom
loganj/first-run-foreign-key

Conversation

@loganj

@loganj loganj commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

First-run setup could trap people on Couldn't finish setup, with only Try again, which repeated the same failure forever. The common path: sign in to Buzz, sign out, then sign in with a different Builderlab account. Buzz then tried to link a key that belongs to the first account to the second one. Builderlab refused, and nothing on screen led anywhere else.

This PR removes the trap in three places:

  • Key from an older Buzz install. Buzz no longer saves that key before it knows the account can use it. If the account accepts it, Buzz saves it as before. If it belongs to another account, Buzz makes a new key and continues.
  • Another account's key already on this computer. Buzz now always asks Replace or Cancel. Before, it sent people to the dead-end page. When that key has a confirmed backup, the dialog says so and tells the person how to get it back: sign in to that account again. Cancel returns to the start page with the key kept.
  • Any setup failure after a Builderlab sign-in. The failure page now offers Use a different account. It signs out of Builderlab, keeps any key on this computer, and returns to the start page. The next sign-in asks for credentials again, so the person can choose another account. Before, some of these failures offered only Back, which kept the Builderlab session, so signing in again reached the same account. Back remains only for failures before any sign-in.
  • Try again only where it can help. When Builderlab refuses the link because the key or the account is already bound elsewhere, the page no longer offers Try again, which would get the same answer every time. Use a different account is the only button.

No key is removed without the person choosing Replace.

Linking the old Buzz key before saving it opens one narrow gap: Buzz links the key, then quits or fails to save it. On the next sign-in, the account holds a key this computer lacks, and with no backup, Welcome back could offer only "paste your private key" or "start over". Buzz now checks old Buzz's key first. When it is the account's key, Buzz saves it, backs it up and continues. Old Buzz's own storage is never changed.

Screenshots

1. Key from an older Buzz install belongs to another account

Before: failure Before: after Try again After: setup continues with a new key

2. Another account's key is already on this computer

Before: the same refusal, and Try again repeats it.

Before: failure Before: after Try again

After: Buzz asks. The wording depends on whether that key has a confirmed backup.

No confirmed backup Confirmed backup
Cancel: back to start, key kept Replace: Buzz restarts Setup continues with a new key

3. The account is already connected to another Buzz identity

Before: only Try again After: Use a different account, and no Try again After: back to start, key kept

Details

  • Older Buzz key. Native code signs Builderlab's link challenge with the old key, but only while no key is saved, and saves nothing. It reads the old storage once and keeps that key in memory. The key it saves is then the same key that signed, even if the old storage changes in between. If the key is missing or malformed, or the person denies the macOS Keychain prompt, Buzz makes a new key. Any other failure, such as an expired link challenge or a busy or locked Keychain, stops setup with Try again, which tries old Buzz's key again.
  • Recovering a linked old Buzz key. This runs only after a first run on this computer noted that it was linking old Buzz's key and never saved it, and only when the account holds a key that is neither on this computer nor backed up. Other sign-ins never bring up the macOS prompt for old Buzz's storage. Native code saves old Buzz's key only when its public key matches the account's key. Otherwise it saves nothing, reports no error, and Welcome back shows as before.
  • Refusals that lead to the replace dialog. Builderlab can refuse a link because the key is bound to another account, or because the account is bound to another key. Both now lead to the replace dialog.
  • "Confirmed backup". This uses the same local check as the rest of the app: a saved, decrypted backup record for this key. It does not call Builderlab. The check only changes the dialog wording. Buzz still asks either way.
  • Use a different account shows on any setup failure after a Builderlab sign-in, including the sign-in a relaunch waits on. The next sign-in asks for credentials again instead of reusing the browser's session, which would sign in to the same account.
  • docs/identity.md describes the new behavior.

🤖 Generated with Claude Code

loganj and others added 2 commits November 7, 2026 12:56
Signing in to a Builderlab account with no linked key could end on
"Couldn't finish setup" with only Try again, which repeated the same
refused link forever:

- Setup silently saved installed old Buzz's key for an account with no
  key. When that key was already linked to another account (as after
  Sign out of Buzz and signing in as someone else), Builderlab refused
  the link, and the key stayed on the device, so every later sign-in met
  the same refusal.
- A key already on the device was linked the same way, with the same
  dead end when it belonged to another account.

Old Buzz's key is now linked before it is saved: native signs the link
challenge with it from one read of old Buzz's storage, only while no key
is saved, and keeps that key in memory so the save uses the same key.
First run saves it once the account holds it, and otherwise makes a new
key.

A device key Builderlab refuses as another account's (pubkey or identity
already bound) goes to the replace decision, which now always asks. When
that key has a confirmed backup, the dialog says so and tells the user
to sign in to that account again to restore it.

A setup that fails after the key exists now offers Use a different
account next to Try again. It signs out of Builderlab and returns to the
landing with the key kept, and the next sign-in asks the account again.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
…one exit

A first run that linked old Buzz's key and then stopped before saving it
(a failed save, or Buzz quit in between) left the account holding a key
this device lacked. The next sign-in rested on Welcome back, which could
only take the nsec or start over. When the linked key isn't backed up,
setup now checks old Buzz's key first: native saves it only when it is
the account's key, and setup then backs it up and continues as a
returning account would.

The setup failure page offered Back or Use a different account depending
on whether this run had made the key. Back kept the Builderlab session,
so the next sign-in reached the same account. After any Builderlab
sign-in the page now offers Use a different account; Back stays for
failures before one.

Try again is no longer offered when Builderlab refuses a link because the
key or the account is already bound elsewhere: asking again gets the same
answer.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
loganj

This comment was marked as resolved.

loganj

This comment was marked as resolved.

loganj

This comment was marked as resolved.

@loganj
loganj marked this pull request as ready for review November 7, 2026 18:36
@loganj
loganj requested a review from a team as a code owner November 7, 2026 18:36
@tellaho

tellaho commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

🤖 Design review at b2935e953f7a74054d113d50547fdbc7da4989b5: no design blockers found in the source and supplied light-theme screenshots.

The change gives people a way out of account conflicts while keeping replacement an explicit choice. The shared confirmation retains Cancel before destructive Replace; the failure page replaces an ineffective retry with an account-switch action.

Not checked: native sign-in, keychain/backup/restart behavior, live keyboard or screen-reader use, dark theme, narrower windows, enlarged text or long copy. No tests run.

wesbillman

This comment was marked as resolved.

First run fell back to a new key on any native refusal to sign with old
Buzz's key, including a challenge that expired before native signed it.
Setup then saved a new key and lost the existing identity.

Native now answers null only when old Buzz's key can't be read (absent,
denied or malformed), which still makes a new key. Any other failure
fails setup with Try again, which links old Buzz's key again.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
baxen

This comment was marked as resolved.

wesbillman

This comment was marked as resolved.

loganj and others added 2 commits November 7, 2026 15:45
- A busy or locked store reading old Buzz's key is now an error, so Try
  again reads it again. Only an absent, denied or malformed key makes a
  new key. The earlier app's read reports which with LegacyHumanError.
- The first-run save of old Buzz's key is pinned to the key the account
  now holds.
- Recovering a linked but unsaved old Buzz key now runs only after a first
  run on this device noted it was linking that key. Other sign-ins no longer
  bring up the OS prompt for old Buzz's storage.
- Linking this device's key to an account with none no longer opens the
  app straight away, as before this change.
- The replace dialog says the key "was" backed up: the check is a local
  receipt.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.com>
@loganj
loganj merged commit fc2dd27 into main Nov 7, 2026
60 checks passed
@loganj
loganj deleted the loganj/first-run-foreign-key branch November 7, 2026 21:19
tlongwell-block added a commit that referenced this pull request Nov 8, 2026
* origin/main: (47 commits)
  fix(relay): report a community's membership refusal once, not as raw 403s (#3012)
  test(browser): fix red main and two cross-PR flakes (#3015)
  feat(agent-activity): keep remote agent outcomes readable (#2913)
  test(solo): cover agent tagging behind a background read-state snapshot (#2941)
  fix(desktop): quit on SIGTERM, SIGINT and SIGHUP so agents stop with Buzz (#2905)
  feat(unread): opening a channel quiets its sidebar row (#2998)
  fix(goose): end the turn when a final send succeeds (#2997)
  fix(relay): report a community's refusal once, not as raw 403s (#2978)
  Give fast Builderlab models their own section and a bolt in the model picker (#2592)
  feat(dev): `just desktop me` keeps Keychain approvals across rebuilds (#3002)
  fix(relay): show one quiet reconnect toast after 30 s, above the composer (#2968)
  feat(memory): render rich markdown and navigable buzz links (#2981)
  fix(identity): never strand first run on a key another account holds (#2996)
  Let agent_create propose instructions (#2332)
  fix(unread): raise a local read floor over dropped marks, and halve save validation (#2977)
  Add Codex huddle auto-join and thinking presence (#2927)
  feat(claude): set up Claude from a button beside Harness (#2975)
  docs(plugins): document the decisions API in the authoring guide (#2994)
  fix(agent-harness): stop telling agents to use GitHub-flavored Markdown (#2639)
  feat(identity): brand federated sign-in and return to the app (#2982)
  ...

Signed-off-by: Tyler Longwell <tlongwell@squareup.com>
Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>

# Conflicts:
#	src/bundled/codex/voice.ts
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.

4 participants