Skip to content

Update bb from inside the app - #4135

Merged
SawyerHood merged 4 commits into
mainfrom
bb/run-bb-in-interactive-mode-thr_skkan422n6
Sep 23, 2026
Merged

SawyerHood merged 4 commits into
mainfrom
bb/run-bb-in-interactive-mode-thr_skkan422n6

Conversation

@SawyerHood

@SawyerHood SawyerHood commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Human comments

What was wrong

bb could tell you an update was available, but it couldn't install it. A server started with npx bb-app or pnpm start, especially a headless one reached through bb Connect, had to be updated by hand in a terminal. The launcher already restarts the server and daemon when they exit, but it starts them from its own package directory. Under npx that directory belongs to one fixed version, so a restart just brings the same version back. Nothing stayed running above the launcher that could switch versions, and nothing could undo a bad update.

What changed

Off by default. Everything below only runs when bb is started with --in-app-updates (npx bb-app start --in-app-updates or pnpm start --in-app-updates). Without the flag, both commands run the launcher in-process as they do on main. The server then reports in-app updates as off, and Settings → Updates shows the upgrade command. This is a launch flag rather than an experiment because the shim has to be the parent process from the start, before the server or its database settings exist. Two changes ship regardless of the flag: the nightly update check fix, and the separate "bb server"/"bb desktop" rows in the desktop app.

Shim and versioned installs (packages/bb-app/src/app-update/)

  • With the flag, bb-app start (npx or a global install) and pnpm start run a small shim. It spawns the real launcher and relaunches it when the launcher exits with code 75.
  • The shim and launcher coordinate through two env vars, exit code 75, and <dataDir>/bb-app-update.json (schema in packages/config/src/app-update.ts). The schema passes unknown fields through, and bb refuses to overwrite a state file it can't read, because an older npx copy may launch a newer launcher.
  • The desktop app, pnpm dev, pnpm dev --worktree, bb-server, and standalone host daemons don't use the shim.
  • npm updates install into <dataDir>/app-versions/<version>/ through a staging dir, using the bundled npm. The staging package.json lists the three native packages in allowScripts, because npm 11 rejects --allow-scripts for installs like this. A native-module load check runs before anything switches.
  • On each start the shim runs the newer of the installed version and the npx copy. --bundled forces the npx copy. An install built under a different Node.js ABI falls back to the npx copy.
  • Source mode updates only from a clean main that fast-forwards to origin/main. It fast-forwards, runs pnpm install --frozen-lockfile, rebuilds, and relaunches. scripts/start-bb.mjs now runs the launcher as a child process (scripts/start-bb-launcher.mjs).
  • One shim manages a data directory at a time, through a lock file. A second bb-app start on the same directory runs with in-app updates off. bb-app stop stops the managing shim.

Launcher controller (launcher-controller.ts, wired into launcher.ts)

  • The server child now gets an IPC channel. The launcher stages the update while bb keeps running, then waits for the server's restart decision.
  • After the children stop, it records the new version as current, plus a pending record, and exits 75. The shim relaunches whatever the state file selects.
  • Once the new version is healthy, it records updated. If a different version starts instead (for example with --bundled), it records the update as failed.
  • There is no automatic rollback. Most releases add migrations and about half drop or rename a column or table, so rolling back only the code is unsafe. A safe rollback needed a database copy and a probation window. If the new version fails to start, bb exits, as it would after a manual upgrade. Download, install and fast-forward failures happen before bb stops, so the current version keeps running. A source checkout whose rebuild fails stays on the new commit.

Server, SDK and CLI

  • New routes: GET /system/app-update, POST /system/app-update/apply (returns 409 threads_running unless the caller confirms), and POST /system/app-update/acknowledge. Machine credentials get 403 on the two POST routes and can't force a check.
  • The restart decision is re-checked after the download finishes. If threads started in the meantime and the caller hadn't confirmed, the update is cancelled.
  • New system change kind: app-update-changed.
  • app-version.ts: nightly builds now check the nightly dist-tag, and also latest in case it's newer. Before this change, nightly users were never offered an update.
  • SDK: sdk.system.appUpdate, applyAppUpdate, acknowledgeAppUpdate.
  • CLI: bb updates app [status|apply|dismiss]. apply confirms before interrupting threads and follows the update through the restart.

Web app

  • Settings → Updates gets an Update button that shows progress, failure details and Retry, and explains why a source checkout can't update.
  • A restarting overlay times out and can be dismissed.
  • Success and failure toasts, plus a details dialog with the output from a failed download.
  • Pages reload once the server comes back on a new version.
  • In the desktop app, a server the desktop didn't start gets its own "bb server" row next to "bb desktop".
  • The sidebar badge counts npm server updates.

Docs: docs/configuration.md (In-App Updates), the bb-app README, the machines guide, and the bb-cli skill references. No host-daemon wire change, so HOST_DAEMON_PROTOCOL_VERSION is unchanged.

Open question: the three new SDK methods reach plugins through the bundled plugin SDK types, so a plugin could restart bb. I left them unprefixed, since the experimental_ rule doesn't clearly cover SDK area methods and precedent is mixed. I'm happy to rename them to experimental_* and add docs/api_to_audit.md entries if you'd prefer.

How you verified

  • pnpm exec turbo run typecheck passes for bb-app, config, server, sdk, cli, app, server-contract, domain and scripts.
  • pnpm exec turbo run test passes in full for bb-app, config, cli, sdk and server-contract. The server's test/system and public app-update tests (199) and the app's app-update, Updates settings and update inventory tests (54) pass.
  • New tests cover the shim, launcher controller, npm staging, git checkout inspection, the server service and routes, CLI output, and the web states. They cover these failure modes:
    • a new version that fails to start (the shim passes the failure through and does not switch back);
    • a stop during the restart, and a source rebuild that fails;
    • a pending update settled as failed when a different version starts;
    • a switch that cannot be recorded, which keeps the current version;
    • a second shim on the same data dir, and a state file written by a newer bb;
    • a symlinked data dir, and a Node ABI mismatch;
    • threads that start during the download, and a stale source check;
    • the page reloading on a new version.
  • Real processes, with scratch data dirs and ports:
    • An npm update from 0.43.3 to 0.43.4 went through the server's restart decision and recorded updated; the CLI returned once it did.
    • A 0.43.4 whose server throws at startup: bb exited and stayed on 0.43.4 with the update pending. Starting the npx copy with --bundled brought 0.43.3 back and recorded "Update to 0.43.4 failed: bb started 0.43.3 instead of 0.43.4."
    • A pnpm start source update in a clone fast-forwarded, reinstalled, rebuilt, relaunched, and recorded updated.
    • bb-app stop stopped the managing shim in both modes.
    • Without --in-app-updates, npx bb-app and pnpm start ran the server and daemon directly under the launcher, wrote no update state, and bb updates app reported in-app updates as off. With the flag, the shim started and the update applied.
    • Before rollback was removed, runs also covered a second instance on the same data dir (updates off, state untouched), Ctrl+C on the process group, and handing off from an older npx copy. Those shim paths did not change.
  • A real npm install bb-app@0.43.4 into the staging dir succeeded with the native check.
  • packages/bb-app tarball smoke passes with pi off PATH. The plugin SDK surface check and npm version guard pass.
  • Not verified: the Electron desktop app itself, macOS, and Node 22.

🤖 Generated with Claude Code

AGENT GENERATED

SawyerHood and others added 4 commits September 23, 2026 19:07
`npx bb-app` and `pnpm start` now run under a small update shim, so
Settings → Updates, `bb updates app apply`, and the SDK can download a new
bb, restart into it, and roll back automatically if it fails.

- npm installs stage into <dataDir>/app-versions/<version> while bb keeps
  running; source checkouts fast-forward a clean main to origin/main,
  reinstall, and rebuild.
- The launcher backs up bb.db (only when the target adds migrations) before
  recording the switch, confirms the new version over a three-minute
  probation, and the shim restores the backup and previous version when it
  fails to start or keeps crashing.
- The server asks the launcher to restart only after the download finishes
  and no unconfirmed threads started meanwhile.
- One shim manages a data directory; a second start runs with updates off.
- The web app shows progress, a restarting overlay, and success/rollback
  results; inside the desktop app a server it did not start gets its own
  "bb server" row next to "bb desktop".
- Nightly builds now check the nightly dist-tag (and latest when it is newer).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The npm shim now records the Node ABI it was given instead of reading
process.versions.modules, so its tests no longer assume Node 24. The
integration test harness builds the new appUpdate server dependency.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Rolling back only the code is unsafe because most bb releases add
migrations and about half drop or rename a column or table, so an older
bb often cannot read a database the new version migrated. Making
rollback safe needed a pre-update database copy, a probation window,
and restore paths in both shims. That was most of the complexity and
most of the data-loss risk, for a failure that manual upgrades and the
desktop app already handle by updating again.

The launcher now records the new version as current when it exits for
the restart, and the shim relaunches whatever the state file selects.
The new launcher records "updated" once the stack is healthy, or
"failed" when a different version starts instead. A source checkout
whose rebuild fails stays on the new commit and exits.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The shim changes how bb-app start and pnpm start run bb, so it now only
starts when bb is launched with --in-app-updates. Without the flag both
commands run the launcher in-process exactly as before, the server
reports in-app updates as off, and Settings → Updates shows the upgrade
command. A launch flag fits better than an experiment because the shim
has to be the parent process from the start, before the server or the
database settings exist.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@SawyerHood
SawyerHood force-pushed the bb/run-bb-in-interactive-mode-thr_skkan422n6 branch from 515f4d2 to 4810c49 Compare September 23, 2026 19:11
@SawyerHood
SawyerHood merged commit a8ce7a3 into main Sep 23, 2026
18 checks passed
@SawyerHood
SawyerHood deleted the bb/run-bb-in-interactive-mode-thr_skkan422n6 branch September 23, 2026 19:20
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