Skip to content

Setup: migrate role/addon selection to an in-app first-run flow for macOS and Linux #81

Description

@KrisPowers

Windows currently handles onboarding through a separate setup executable that runs before the app is even installed. macOS and Linux do not have an equivalent install-time hook, so role selection and addon pre-install need to move inside the main app itself, gated to first launch only.

Problem

Today, role selection (which drives addon pre-install) only happens through Binder-setup-windows.exe, a custom WebView2 installer with its own persona-selection UI. That flow does not exist for macOS or Linux:

  • macOS ships as a .dmg. Users drag Binder.app into Applications. There is no installer process to run custom UI before first launch.
  • Linux currently ships as a direct tarball download, and will soon also support a curl install script. Neither gives us a place to show a GUI mid-install.

Both platforms need role selection and addon pre-install moved into the main app, shown once on first launch, with explicit rules so it never reappears once a user has made a choice, including choosing not to pick a role.

Current state (for reference)

  • Persona/role selection UI lives in setup/windows/frontend/src/App.tsx (lines 7-26 define PERSONA_APPS, lines 56-77 render the grid, line 179 calls Install() with seed_apps).
  • On install, the Windows setup app writes ~\AppData\Local\Binder\.first-run-apps.json with the selected apps (cpp/setup/installer.cpp:328-337).
  • The main app consumes that marker file once, on first launch, in Config::load() (cpp/src/config.cpp:103-120 for ApplyFirstRunAppsSeed(), lines 122-166 for the load/first-run logic), merges the apps into installed_apps in config.json, then deletes the marker so it is never re-applied.
  • Platform paths are already branched with #ifdef _WIN32 / #ifdef __APPLE__ / Linux fallback in both cpp/setup/installer.cpp:69-95 and cpp/src/config.cpp:21-51.
  • macOS and Linux packaging (.github/workflows/release.yml:115-194 for macOS .dmg, lines 196-262 for Linux tarball) only produce a binary or app bundle. There is no installer-time hook on either platform, and no in-app onboarding currently exists at all for them.

Goal

Move role selection and addon pre-install into the main app's UI for macOS and Linux, shown only on first launch, using the same underlying addon-seeding logic that already exists for Windows. Windows keeps its current installer-driven flow unchanged.

Non-goals

  • No changes to the Windows setup app or its installer flow.
  • No changes to macOS .dmg or Linux tarball/curl packaging itself. This is purely an in-app UI and config change.
  • No redesign of the persona grid's visual design. Reuse the existing options and addon mappings.

Proposed plan

  1. Add a new in-app onboarding screen to the main app's frontend that renders the same persona grid currently defined in setup/windows/frontend/src/App.tsx. Reuse the component and PERSONA_APPS mapping if the build setup allows sharing it between the setup frontend and the main app frontend. Otherwise, port it into the main app's frontend directly.
  2. Add an explicit persisted flag to config.json, for example "onboarding_completed": true. This flag, not just "is this the first launch," is what decides whether the screen shows. It must be set the moment the user either selects a role or explicitly skips, so a skip is permanent and does not re-prompt on the next launch.
  3. Decide and document the exact behavior when a user closes the onboarding window without clicking either "select" or "skip." Recommendation: closing without an explicit choice should NOT set the flag, so onboarding reappears on the next launch. Only an explicit "Skip" action and an explicit role selection should set onboarding_completed.
  4. Branch the startup logic in Config::load() (cpp/src/config.cpp) by platform:
    • On _WIN32, behavior is unchanged. The installer already seeds .first-run-apps.json and should also set onboarding_completed: true at that point, so the in-app screen never shows on Windows.
    • On macOS and Linux, if onboarding_completed is false or missing, show the new in-app onboarding screen before the rest of the UI renders.
  5. Reuse the existing addon merge logic from ApplyFirstRunAppsSeed() (cpp/src/config.cpp:103-120) directly in-process for macOS and Linux, rather than writing and re-reading a marker JSON file. There is no separate installer process on these platforms, so the file-based handoff is unnecessary there.
  6. No changes needed to .github/workflows/release.yml packaging steps for macOS or Linux.

Open questions to resolve before or during implementation

  • Should "Skip" have any visible way to restart onboarding later from settings, in case a user skips by mistake?
  • Does the existing PERSONA_APPS to addon mapping need to become a single source of truth, for example a shared JSON or shared module, now that two frontends will use it, to avoid drift between the Windows setup frontend and the new in-app version?

Files likely involved

  • setup/windows/frontend/src/App.tsx, source for the persona grid to reuse or port
  • cpp/src/config.cpp, first-run/onboarding flag, startup branch, addon seeding
  • cpp/setup/installer.cpp, set onboarding_completed alongside the existing .first-run-apps.json write, Windows only
  • Main app frontend, new onboarding screen component, exact path to be determined based on existing frontend structure

Acceptance criteria

  • On a fresh macOS or Linux install, the role/addon selection screen appears on first launch.
  • Selecting a role pre-installs the same addons as the equivalent Windows flow.
  • Explicitly skipping the screen never shows it again on subsequent launches.
  • Closing the window without an explicit choice shows it again on the next launch.
  • Windows behavior is unchanged.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions