Skip to content

Onboarding: a first-run tour on every client - #39

Merged
i2cjak merged 5 commits into
mainfrom
backplane/agent-onboarding-flow
Oct 3, 2026
Merged

i2cjak merged 5 commits into
mainfrom
backplane/agent-onboarding-flow

Conversation

@i2cjak

@i2cjak i2cjak commented Oct 3, 2026

Copy link
Copy Markdown
Owner

A short, skippable first-run tour (9 steps) on the window, web, iOS and Android, driven by src/core/onboard.bend (laws onboard_*, held_*, tour_scroll_*):

  • Covers: projects and Scratch (with its expiry), threads and worktrees, the header buttons, bots, using your own Claude Code / Codex / Grok CLIs, keys and voice, other machines and phones (QR pairing over Tailscale).
  • When it shows: once per hub, after this connection's state is live, not cached. Skip or Done sets onboard.done for every client. Settings › "Show the tour" reopens it.
  • Modal: keys pressed during the tour stay quarantined until released, by physical keycode via XQueryKeymap in the window and by e.code + e.repeat on the web. Focus goes back to whatever field is visible.
  • Phones: wait until nothing else is presented. The tour text is chosen per client in Bend.
  • Tailscale in Settings: the hub now reports its real state as info tailscale (off / checking / unavailable / reachable), and Settings shows it on all four clients.

Review process

  • Sonnet 5.5 built it.
  • Screen-only trials by a Sonnet 5.5 and two Sol 6.1 first-time users.
  • Four adversarial Sol 6.1 reviews, all findings fixed. The last one says MERGEABLE.

Tests

  • scripts/check.sh: All terms check.
  • scripts/test.sh: 76 files ok.
  • build/backplane, the web client and bridge.js build.
  • Android compileReleaseKotlin passes, and iOS builds for the Simulator on the Mac.
  • Real held-key runs under Xvfb, plus key runs on the web in headless Chromium.

Out of scope, found in the trials:

  • The bot form loses what you typed on a validation error.
  • Toolbar and message-box controls overlap in a narrow window.
  • Settings notes are cut off.

Co-Authored-By: Claude noreply@anthropic.com

i2cjak and others added 5 commits October 2, 2026 13:02
Pure steps and moves in core/onboard.bend, the hub setting onboard.done
keeps it finished or skipped, laws and a test; the window, web and both
phone apps show it, and Settings shows it again.

Co-Authored-By: Claude <noreply@anthropic.com>
Input stays in the tour on every client (web dialog is inert behind, traps
focus and eats other keys, paste and drop; the window routes paste and drop
through the modal check, ignores key repeat and eats the key that closed
it, and clears or restores focus). Words say what is true (Scratch expiry,
no key guarantee, CLI signed in on the hub, worktrees, Tailscale, settle
and snooze from tools.bend) and differ by client. An auto-shown tour waits
for this connection's state and closes when done elsewhere; no outline on
an absent target; cards fit short windows; iOS presents after Settings
dismisses and Android dismiss means skip. Laws and tests extended.

Co-Authored-By: Claude <noreply@anthropic.com>
…view

- Native: every key pressed while the tour is up stays in quarantine until
  released, whichever way it closes; a blur starts a new generation. win.c
  checks XkbSetDetectableAutoRepeat's answer, falls back to dropping the
  release of a same-keycode, same-time release+press pair, and reports a
  release with its press's keysym. xpoke gains hold/holdx/down/up/blur/focus.
- Return focus and the head outline come from the view on screen (room,
  remote chat, bot, Settings), not from a stale thread selection.
- A cached state (web saved log, phone saved state) no longer counts as
  synced (Ui.unsync, App.unsync, Hubs.stale).
- Native card: the words scroll under the wheel inside a bounded area, the
  buttons stay on the card, a compact card below that.
- iOS and Android show the tour only when no other presenter is up.
- Settings' Tailscale row says off, not connected or on (Tail.*, all four
  clients); the tour says the other device needs Tailscale too.
- Worktree sentence true for local mode and non-git projects; the thread
  buttons read as plain sentences; steps trimmed.

Co-Authored-By: Claude <noreply@anthropic.com>
…s tailnet state

- Native: the quarantine is the set of keycodes pressed while the tour is up
  (WKey carries the keycode; @q.<keycode>), left on the key's release. win.c
  ignores a release while XQueryKeymap still shows the key down (no detectable
  repeat) and reports the releases it missed when the focus returns; a blur
  keeps the quarantine. The generation machinery is gone. xpoke gains
  xdown/xup/xhold (XTest: the server's own key state and repeat).
- Web: every KeyboardEvent.code pressed while the tour is up, modified ones
  included, has its repeats (and their keypress/input) dropped after it closes,
  until keyup or a fresh keydown.
- Phones: Bend leaves the tour out of the screen model while another overlay is
  up (Mob.covered); iOS also waits until nothing is presented over the root
  (Presented.none); Android until its own dialogs, the lightbox and the diff
  sheet are gone (Overlay/Overlaid).
- The hub reports its tailnet state (info "tailscale": off, checking,
  unavailable, reachable, also when the main listener covers the address);
  Tail.* read it and fall back to the pairing link for an old hub.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@i2cjak
i2cjak merged commit 4629481 into main Oct 3, 2026
2 checks passed
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