Skip to content

feat(web): first-run welcome wizard with agent setup and project import - #459

Merged
rynfar merged 20 commits into
pylonfrom
upstream/2026-09-10-web-onboarding
Sep 11, 2026
Merged

feat(web): first-run welcome wizard with agent setup and project import#459
rynfar merged 20 commits into
pylonfrom
upstream/2026-09-10-web-onboarding

Conversation

@rynfar

@rynfar rynfar commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

New Pylon installs opened on an empty "What should we work on?" hero with no guided way to connect computers, check that Claude Code or Codex are ready, or bring in the projects and conversations people already have in those agents. This ports upstream's first-run welcome wizard and its eight follow-ups (tracking issue #414, frozen upstream head 6c583620ff7ad3235b135af7107c0543467eecfa).

What changes

  • /welcome setup overlay over the workspace, gated by FirstRunGate. It picks one or more computers (this server, saved computers, Pylon Connect discoveries, or a pairing link), checks Claude Code and Codex on each (install terminals using the vendors' standalone installers, Pylon's sign-in dialog for Claude Code, a terminal for codex login), then offers project import grouped by repository.
  • Transcript import on the server: agentSessions.scan / agentSessions.import RPCs scan Codex and Claude homes, create projects, and import recent conversations as settled, turnless history (thread.history.import, import: message ids) with the provider resume cursor installed first, so the first prompt resumes the native session. Imports are bounded and retryable, skip completed transcripts and non-project folders, and (#10430) stream past large tool payloads such as screenshots so oversized transcripts still import.
  • Settings hydration hardening: client settings track pending/ready/failed/retrying; storage or settings-file access failures reject instead of silently saving defaults or opening a browser with the wrong profile. Schema decode problems do not lock the app (see Pylon adaptations).
  • Reopening setup: the command palette offers Set up computers and import projects, which opens /welcome again after onboarding is finished.
  • Terminal provider environments: terminal open/attach/restart accept providerInstanceId and resolve that instance's environment and home directory.
  • Follow-ups: imported custom-provider threads lock to the right driver (#10184), hosted connection prerequisites copy (#10129), light/dark handling (#10432, then following the app theme in #10465), shared WizardSteps/WizardPanel components also used by Add provider.

FirstRunGate does not force existing users into the wizard: a set onboardingCompletedAt opens the app immediately; otherwise more than one project or thread, or any project/thread not created by this startup's cwd auto-bootstrap, opens the app and persists completion. An existing install with zero projects and zero threads sees the wizard once. The gate relies on state Pylon already has (client settings, environment shells, projects, threads, and the server welcome event, whose new bootstrapStatus fields are optional for older servers).

Sources

Upstream commit PR Outcome
09aac71563c66a4f65f6fbe701aa9596cb677767 #5362 Adopted with Pylon adaptations (below)
d92dca74eb7b7c6068619752f5b9a55c0e36f352 #10184 Adopted; tests drive Pylon's composer instance selection
82689782eee0f0cf27d5601e1d533381587b64f8 #10129 Adopted; copy names Pylon and Pylon Connect
c2c4185e175daea86f8fd6336fd8839a81cc616e #10402 Adopted
ec36176e4f25fac7e3c380f6a4b646116e4ccf3d #10432 Adopted (theme ownership later superseded by #10465, as upstream)
95f9b14f873c7b119f0ffb6dbd194c7063293aa2 #10430 Adopted (streams past large tool payloads); lockfile regenerated from Pylon's with vp i
f729e8fd837e4d6de86781351c3aee5a4ea19ab3 #10465 Adopted with Pylon adaptations (below)
8b2838e0e8a73d3fa6476940445c372e47b99db4 #10493 Adopted
62fbbe08aa854fcbd8044cd971a45a54edafcb98 #10547 Adopted

Pylon adaptations

  • Provider lifecycle: ProviderSessionDirectory.upsert keeps Pylon's session-incarnation commitGuard and removeExact; upstream's onConflict: "ignore" and recordImportedTranscript sit beside them. The directory tests now run as it.effect (they previously returned an unexecuted Effect), including Pylon's Prime commit-guard test.
  • Decider invariants: thread.history.import uses Pylon's openRequests scan (approvals, user input and interactions). The importer also treats Pylon-only thread state — projected branch PR, manual Active placement, rollback status and handoff parent — as modifications that block re-import. Imported history survives Pylon's rollback revision compare-and-set (test adapted from upstream's revert-to-baseline).
  • Settings compare-and-set: server-settings and terminal tests register provider secrets through mutateProviderInstances, since Pylon rejects whole-map updateSettings({ providerInstances }).
  • Link opening: Pylon's preview fallback in useOpenLink and terminal links is kept; only a BrowserSettingsReadError rejects without opening a browser. Pylon's getUserMedia screencast recording keeps its flow with upstream's sequential settings read. Terminal links keep feat: open PR links in panels, drop files on sidebar threads, and measure turn tokens #458's Cmd/Ctrl-click system-browser override; feat: open PR links in panels, drop files on sidebar threads, and measure turn tokens #458 deferred upstream's settings-read rejection and drawer error toast until #5362 landed, and this PR adopts both.
  • Branding: the wizard header renders PylonMark with "Pylon" (upstream's T3 wordmark does not exist in Pylon); dialog title, Pylon Connect section, pairing hints, recovery copy and docs/user/welcome-wizard.md name Pylon. npx t3 … commands stay as compatibility names, matching Pylon's other docs.
  • Scanner: besides the configured worktrees dir and .t3/worktrees, project import skips worktrees under Pylon runtime homes (.pylon-code/worktrees, including channel homes such as .pylon-code-nightly), so Pylon's own sandboxes are never offered as projects. Covered by the scanner test.
  • Add provider dialog adopts the shared WizardPanel while keeping Pylon's multiple-instance blocking and Prime guidance.
  • Project defaults: imported projects keep resolving a default model from their computer's providers; upstream's defaultModelSelection: null comes with shared project defaults (#9754), which lands in a separate lane.
  • Saved settings do not lock the app: Pylon and T3 Code both default to port 3773 and share the t3code:client-settings:v1 browser key, and T3 Code now writes confirmQuit as "hold" | "direct" | "double-click". Upstream's fail-closed decode would have shown "Could not read settings" forever. Only storage or settings-file access failures fail closed now; settings decode one value at a time, undecodable values use their defaults, and writes leave those stored values in place until that setting changes, so automatic writes such as onboarding completion do not overwrite them. A document that is not settings JSON reads as no saved settings, as before this PR. Desktop reads its settings file the same way, and an unreadable file keeps the default hold-to-quit instead of quitting on one press.
  • Shared scanner: the websocket route builds one AgentSessionScanner for all connections, like the pull request service, so clients share its import read lock and memory budget instead of each holding their own.
  • Providers in the wizard: like upstream, the agent step lists only Claude Code and Codex. Prime Agent is treated the same way as Antigravity, Cursor, Grok and OpenCode — added from Settings → Providers, where Pylon already presents Prime and its managed install guidance — so the wizard does not grow a Pylon-only install path. The import scanner reads only Codex and Claude transcripts, as upstream.
  • The first-run recovery screen uses the shared RefreshIcon Pylon already adopted from #9561.

Duplicated feature: Claude Code sign-in

Upstream's wizard signs Claude Code in by opening a terminal with claude auth login. Pylon already has ProviderSignInDialog (server.startProviderLogin, shown from the provider card in Settings): it needs no terminal scope, offers subscription/Console/SSO, and prefills the known email, so on a client paired without terminal access the terminal path fails where Settings works. Setup now opens Pylon's dialog for Claude Code's signed-out state. Installs and codex login keep the setup terminal, because Pylon has no terminal-free Codex login (its other sign-in flow is Antigravity-only).

Exclusions

  • 3faeee49ac67dfd9534369f1e1c627c0356b75ac (#10832, consolidating setup wizards) is not in this lane; it depends on the window-capture lane and is sequenced later.
  • #9754 will later add its WelcomeWizard hunk (project defaults) from the project-defaults lane.
  • After the frozen head, upstream afb84898be (#10839, multiple linked PRs) touches AgentSessionImporter.test.ts; it belongs to the next cycle.

No server migration. PRIME_AGENT_DRIVER_KIND usages are unchanged versus origin/pylon.

Verification

  • Tests (1,703 across 68 files): server 908 (importer, scanner, decider import, projection pipeline/snapshot, directory including commit guard with insert-ignore, registry, server RPC with the shared scanner, startup, settings, terminal, checkpoint, relay, maintenance, adapters), web 388 (client settings storage including a T3 Code "confirmQuit":"hold" document that hydrates and survives writes, settings hydration, onboarding logic, browser and preview helpers, link opening, ChatView logic, command palette logic, terminal drawer, Connect list, provider status, wizard steps), desktop 96 (settings file reads/writes, quit hold fallback, window), contracts 176, client-runtime 83, shared 52.
  • One scanner test ("excludes sandboxes reached through a symlink into the worktrees dir") fails only with macOS's default TMPDIR, whose /var is itself a symlink; all scanner tests pass with a realpath temp dir, and Ubuntu CI is unaffected.
  • Typechecks: @t3tools/contracts, @t3tools/client-runtime, @t3tools/shared, t3, @t3tools/web, @t3tools/desktop, @t3tools/mobile.
  • After rebasing onto 16a99685d8 (feat: open PR links in panels, drop files on sidebar threads, and measure turn tokens #458): the seven typechecks again, 274 web tests for the rebase-touched terminal drawer, terminal link, ChatView, command palette, settings and onboarding files, and 449 server tests for the Codex/OpenCode adapters, ProviderService and server RPC.
  • vp fmt --check and vp lint on changed files (one pre-existing warning in Manager.test.ts); vp run knip:check passes.
  • No local client pass was run; the orchestrator does one integrated pass later. Upstream evidence (T3 branding in these captures is replaced by Pylon's mark here):

Ported by Claude Opus 5 in Claude Code.

@vercel

vercel Bot commented Sep 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
pylon-marketing Ready Ready Preview Sep 11, 2026 1:32am UTC

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Sep 11, 2026
@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 14.1 KiB 13.9 KiB −155 B (−1.1%) 15.1 KiB
Codex Thread snapshot wire 7.2 KiB 7.2 KiB +6 B (+0.1%) 7.3 KiB
Codex Live turn WebSocket wire 6.9 KiB 6.7 KiB −161 B (−2.3%) 7.8 KiB
Codex Live turn WebSocket decoded 58.8 KiB 58.0 KiB −910 B (−1.5%) 66.4 KiB
Codex Live turn messages 10 8 −2 (−20.0%) 21
Claude Total thread wire 14.1 KiB 13.9 KiB −171 B (−1.2%) 15.1 KiB
Claude Thread snapshot wire 7.2 KiB 7.2 KiB 0 B (0.0%) 7.3 KiB
Claude Live turn WebSocket wire 6.9 KiB 6.7 KiB −171 B (−2.4%) 7.8 KiB
Claude Live turn WebSocket decoded 59.7 KiB 58.8 KiB −928 B (−1.5%) 66.4 KiB
Claude Live turn messages 10 8 −2 (−20.0%) 21

Baseline: 16a9968 · PR result: 7573162 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 115.6 KiB
  • Claude decoded thread snapshot: 116.3 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

t3dotgg and others added 20 commits September 10, 2026 19:26
Adopted from 09aac71563c66a4f65f6fbe701aa9596cb677767 (#5362)

Pylon adaptations:
- Keep ProviderSessionDirectory's commit guard and exact removal beside the
  new insert-ignore option and imported transcript records.
- Build the import invariant on Pylon's open-request scan, and treat Pylon's
  PR tracking, manual Active placement, rollback status and handoff parent
  as modifications that block a re-import.
- Keep Pylon's RPC consts private and its hub reset credit, Prime managed
  binding and commit-guard tests; convert the directory tests to it.effect so
  they execute.
- Register provider secrets through Pylon's provider instance
  compare-and-set in the terminal environment tests, and prove imported
  history survives Pylon's rollback revision compare-and-set.
- Keep Pylon's screencast recording, preview fallback and markdown link
  handling while failed settings reads reject instead of opening a browser;
  Pylon's link-opening tests cover that rejection.

(cherry picked from commit 09aac71563c66a4f65f6fbe701aa9596cb677767)
Adopted from d92dca74eb7b7c6068619752f5b9a55c0e36f352 (#10184)

Pylon adaptation: the regression tests drive Pylon's
resolveComposerInstanceSelection, which replaced upstream's
resolveComposerProviderSelection in the composer.

(cherry picked from commit d92dca74eb7b7c6068619752f5b9a55c0e36f352)
Adopted from 82689782eee0f0cf27d5601e1d533381587b64f8 (#10129)

Pylon adaptation: the hosted prerequisites copy names Pylon and Pylon Connect.

(cherry picked from commit 82689782eee0f0cf27d5601e1d533381587b64f8)
…402)

Adopted from c2c4185e175daea86f8fd6336fd8839a81cc616e (#10402)

(cherry picked from commit c2c4185e175daea86f8fd6336fd8839a81cc616e)
Adopted from ec36176e4f25fac7e3c380f6a4b646116e4ccf3d (#10432)

(cherry picked from commit ec36176e4f25fac7e3c380f6a4b646116e4ccf3d)
Adopted from 95f9b14f873c7b119f0ffb6dbd194c7063293aa2 (#10430)

The lockfile was regenerated from Pylon's with vp i for the new stream-json
and stream-chain server dependencies.

(cherry picked from commit 95f9b14f873c7b119f0ffb6dbd194c7063293aa2)
Adopted from f729e8fd837e4d6de86781351c3aee5a4ea19ab3 (#10465)

Pylon adaptations:
- The Add provider dialog adopts the shared WizardPanel while keeping
  Pylon's multiple-instance blocking and Prime guidance.
- Imported projects keep resolving a default model from their computer's
  providers until shared project defaults (#9754) land.
- The first-run recovery screen uses the shared refresh icon Pylon already
  adopted from #9561 and names Pylon.
- The wizard header renders PylonMark with the Pylon name instead of T3's
  wordmark, and its dialog title, Connect section and pairing hints name
  Pylon and Pylon Connect; `npx t3` commands stay as compatibility names.

(cherry picked from commit f729e8fd837e4d6de86781351c3aee5a4ea19ab3)
Onboarding listed every directory Claude Code or Codex had ever run in as one flat list of paths, with everything from the last 30 days preselected. On my machine that was 270 rows and 80 preselected. Most of them were Codex scratch folders, worktrees, and one-off questions. I wanted two or three projects and had no fast way to get there.
The scanner now reads each candidate's `.git/config` directly, so the client can group clones by origin and show the GitHub `owner/name`. Linked worktrees, Codex scratch directories under `~/Documents/Codex`, `~/Downloads`, and temp roots are no longer offered. Folders that are not git repositories collapse under "Other folders". The default selection requires a git repository with at least three threads. Select all and Select none sit above the list, and each row shows the source icons, thread count, and last activity.
On the same machine this drops the list to 162 rows and the default selection to 16.
Mobile has no project import step, so there is no mobile change.

Adopted from 8b2838e0e8a73d3fa6476940445c372e47b99db4 (#10493)

(cherry picked from commit 8b2838e0e8a73d3fa6476940445c372e47b99db4)
…t (#10547)

Adopted from 62fbbe08aa854fcbd8044cd971a45a54edafcb98 (#10547)

(cherry picked from commit 62fbbe08aa854fcbd8044cd971a45a54edafcb98)
…wizard for Pylon

Pylon adaptations for the onboarding sources:
- Project import skips transcripts from worktrees under Pylon runtime homes
  (`.pylon-code/worktrees`, including channel homes such as
  `.pylon-code-nightly`) alongside T3 Code's `.t3/worktrees`.
- docs/user/welcome-wizard.md is written for Pylon, keeps `npx t3` commands
  as compatibility names, and points other providers, including Prime Agent
  and Antigravity, at Settings → Providers.
- The relay target test names Pylon Connect.
knip rejects the unused export; upstream's frozen head keeps serverWelcomeStateChanges module-private as well.
…a newer value

Saved client settings no longer fail closed on schema decode errors. Pylon
and T3 Code share the browser storage key when served from the same origin,
and T3 Code now writes `confirmQuit` as "hold" | "direct" | "double-click";
a strict decode replaced the whole app with "Could not read settings".

- Settings are decoded one value at a time: readable values load, values
  this build cannot decode fall back to their defaults, and a document that is
  not settings JSON reads as no saved settings. Storage and file access
  failures still reject so hydration can retry.
- Writes leave an undecoded stored value in place until that setting changes,
  so an automatic write such as onboarding completion does not overwrite it.
- Desktop reads the settings file the same way, and an unreadable file keeps
  the default hold-to-quit instead of quitting on one press.
Setup opened a terminal with `claude auth login` even though Pylon's provider sign-in dialog already signs Claude Code in through server.startProviderLogin, without terminal access, with subscription, Console or SSO choices and email prefill. Claude Code's signed-out state now opens that dialog. Installs and `codex login` keep the setup terminal because Pylon has no terminal-free Codex login.
Finished setup had no way back in to add computers or import more projects. The command palette now offers Set up computers and import projects, which opens /welcome.
The scanner was built inside each connection's RPC layer, so concurrent clients each held their own import read lock and memory budget. The websocket route now builds it once, like the pull request service.
Import reads up to 4 GiB per project and per conversation file, streams past large tool output, and caps kept history at 32 MiB per conversation. The doc also covers Claude Code sign-in, reopening setup from the command palette, and an existing install with no projects or threads; the scan candidate contract comment names Pylon.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants