Skip to content

feat(ux): simplify bot creation and personalize first-run experience - #861

Merged
samjulien merged 30 commits into
mainfrom
codex/openbot-ux-review
Oct 28, 2026
Merged

samjulien merged 30 commits into
mainfrom
codex/openbot-ux-review

Conversation

@samjulien

@samjulien samjulien commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This PR simplifies OpenBot's first-run and Bot creation flows, adds an editable display name, and makes explanatory copy more consistent across the app. Built-in Bots can be created from one screen, while custom agents follow a shorter connection flow that preserves entered values when navigating back.

Bot creation

  • Start with a New Bot heading beside the animated orb, followed by Name, optional Instructions, and visibility.
  • Remove the optional Title field from creation. Keep Instructions as the label for both built-in Bots and custom agents, and remove the extra helper text below it.
  • Built-in hosting is the default, with no Run here selector. Connect a custom agent is a separate outlined action immediately left of Create Bot in the footer. Public visibility now says “Everyone in your company can find and use it.”
  • Let users create a built-in Bot directly from this first screen.
  • Clicking Connect a custom agent validates the required details and advances to framework selection. Selecting a framework advances directly to its connection screen, removing the extra Continue click.
  • Put An agent you already run first in the custom-agent list.
  • Preserve the name, instructions, visibility, framework, endpoint, key, and app selections when moving back and forth. Retain endpoint connection testing before creation.

Conversation entry and app chrome

  • Pin New Bot above the scrolling conversation recipient results, with the default orb and “Create a new Bot” preview. It is a separate action, so Enter in the recipient input cannot auto-select it.
  • Open creation in place, preserve existing recipients and the conversation draft, and add the newly created Bot to the recipients.
  • Hide the CopilotKit Inspector by default.

First-run profile and Settings

  • Make name entry the final onboarding step, after the local-evaluation slides when applicable. The animated orb and Let's get to it. heading lead into the form; Get started saves the name and completes onboarding.
  • Remove the global blocking name dialog. Existing users who completed onboarding can set their name in Settings, with a generic greeting until then.
  • Add a Profile form in Settings so users can change their name later.
  • Persist the name and an explicit name-set preference. Startup no longer overwrites a saved name with the local development placeholder.
  • Add an authenticated, name-only profile update endpoint with trimming and length validation. Preserve IDs, email, permissions, other preferences, onboarding state, and conversation ownership.
  • Keep an untouched Settings form in sync when the saved profile changes, while preserving any unsaved edits already entered in Settings.

Restrained name personalization

  • When the conversation list is confirmed empty and a usable display name exists, show Hi [name], what would you like to work on? on the home screen. Otherwise retain the generic heading.
  • Keep this greeting in the UI rather than inserting a message into conversation history.
  • Resolve the current user's saved name for each built-in agent run and provide one bounded profile context entry. Custom agents do not receive this context or trigger a name lookup. Replace previous profile context instead of accumulating it, so edits and cleared names are reflected.
  • Keep the name as JSON data, accompanied by fixed guidance to use it sparingly, avoid repeated greetings or inferred personal details, and never treat it as an instruction. The guidance travels with application context because built-in agents omit incoming system messages by default.
  • Omit optional name context if lookup fails or the value is unsuitable. This does not block the user's conversation.

Copy consistency

  • Replace fragmentary explanatory text with direct, complete sentences across Bot pages, Connections, Capabilities, routines, Settings, and admin screens, including approvals, audit, credentials, people, skills, and enterprise configuration.
  • Update the repository's OpenBot copy guidance to carry the same conventions into future changes. Most of the wider file count consists of these small copy edits.

Scope and review focus

This PR contains the UX work on top of current main. The separate local setup fixes remain in #810 and #811.

Review the Bot creation flow in both hosting modes, including validation and Back navigation; the first-run name prompt and subsequent Settings edits; and the scope and handling of agent profile context. Review follow-up integrates name entry into onboarding, keeps the creation action visible without making it an auto-highlighted recipient, defaults to custom hosting when built-in hosting is unavailable, reuses one profile store, removes obsolete compatibility filters, and restores relevant code comments. Custom-agent auto-advance is intentionally retained after product review. Merge conflicts with current main are resolved.

CI follow-up

  • Update the IME regression test to start on the new details-first screen while retaining assertions that composing Enter never creates a Bot.
  • Main now contains the equivalent AG2 authentication-header test fix. The merge keeps main’s version, removing that unrelated fix from the PR diff.

Validation

  • Formatting and lint passed for all 61 changed TypeScript files.
  • App, server, and shared typechecks passed; test typecheck reported no new errors against its existing baseline.
  • Latest review follow-up: 72 tests passed across nine affected files, covering onboarding/profile saves, recipient preservation, IME input, Bot creation, and built-in-only name context. Earlier validation also covered profile persistence against an isolated PostgreSQL database.
  • App, server, and worker production builds passed. Vite reports an existing chunk-size warning.

Model wording itself has not been evaluated in a live model conversation; sparing name use is guidance, not a guaranteed model behavior.

@guidovizoso guidovizoso left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this. The Settings profile endpoint, the profileNameSet flag, the dev-actor change that stops overwriting the name, and keeping the greeting in the UI rather than in message history all look good.

The main UX points are inline:

  1. Name prompt: move it into the onboarding flow instead of a global modal, which currently stacks on top of /onboarding.
  2. Recipient picker: your own Bots should come before "New Bot", which is currently auto-highlighted.
  3. Bot creation: "Connect a custom agent" should be a selectable card like "Run here", with the footer button switching between Create Bot and Continue.

Also: the PR has merge conflicts with main, and there's some import-reordering noise in server/src/index.ts and app.ts that makes the diff harder to review.

Comment thread app/src/routes/_authed.tsx Resolved
Comment thread server/src/agents/agent-resolver.ts Resolved
Comment thread server/src/people/name-context.ts Resolved
Comment thread server/src/index.ts Resolved
@samjulien
samjulien requested a review from dustywusty as a code owner October 28, 2026 13:59
@samjulien
samjulien merged commit 4bb0c0b into main Oct 28, 2026
19 checks passed
@samjulien
samjulien deleted the codex/openbot-ux-review branch October 28, 2026 18:01
davidmckayv added a commit that referenced this pull request Oct 28, 2026
…home

Home's heading became a personal greeting in #861, so the test that a skin
switch on a skin-only screen lands on a drawn home waited for wording that no
longer exists. It now waits for the home composer.
davidmckayv added a commit that referenced this pull request Oct 28, 2026
#861 turned onboarding into a looping introduction whose computer scene is
labelled "Each Bot has its own computer". Label and heading now say what
every Bot gets, and the check reads the route's words, since the looping
scene cannot be reached under happy-dom.
davidmckayv added a commit that referenced this pull request Oct 28, 2026
* Let each person pick a skin for OpenBot in Settings

Adds app/src/skins: a registry of skins, a per-browser choice stored like
the dark theme and applied before first paint as data-skin, a Skin row in
Preferences, and /s/$screen for screens only a skin has. A skin may replace
the frame around the app's pages and scope its tokens to its own data-skin;
tests hold every skin's stylesheet to its own scope and to defining dark for
every light token. OpenDuet, OpenDots and OpenMuse are registered as stubs.

* Give OpenDots a real skin: its rail, Dots sidebar, top bar and computer pane around OpenBot's pages

The OpenDots stub becomes OpenDots' own frame drawn over OpenBot's data. A 48px rail
(home, sidebar toggle, new chat, Bots, activity, skills, connections, admin, settings,
account) sits beside a 220px sidebar whose DOTS are the Bots from the agent list, each
wearing one of OpenDots' four plush avatars chosen by its id, and whose RECENT CHATS are
OpenBot's conversations with search, pin and delete. A Dot reopens its latest chat or starts
one; its "..." opens the Bot's page. The top bar carries OpenDots' breadcrumbs, a pause and
resume for the Bot on screen, and the computer toggle: on a conversation it drives the
conversation's own computer pane, elsewhere it opens OpenBot's computer panel in OpenDots'
right pane. At phone width the sidebar becomes OpenDots' hamburger drawer.

Every page inside is OpenBot's own, chat included, in OpenDots' tokens for light and dark
(the dark set derived with OpenDots' own lightness flip). Scheduled & activity and Memories
are skin screens that put OpenBot's routines and memory lists under OpenDots' page heading.
Spaces, pages, the Brief and the pause-everything switch are left out: OpenBot has nothing
behind them.

Tests draw the frame against OpenBot's own agent routes and hold it to: every OpenBot
surface reachable, Settings reachable on every page even when nothing loads, DOTS listing
the agent list, a Dot opening a chat with its Bot, the computer toggle driving the
conversation's pane, and per-Bot pause reaching the server.

* Show OpenDots' coworker home on a new conversation with a chosen Bot

OpenDots opens a Dot on its persona: the plush, the name, what it does and a way to
edit it, above an empty conversation. OpenBot's new-conversation page leaves that space
empty, so the frame draws the persona there from the Bot's profile and hides it as soon
as the page shows a message. Also keeps the composer and its notices off the pane's edges
where the column is no wider than the composer, drops the rule under a conversation's
header so it reads as one band with the top bar, and gives the disabled send button
OpenDots' pale disc.

* Dress a conversation's own computer pane as OpenDots' right pane

The top bar's computer toggle opens the conversation's own Computer pane, so it now wears
the same grey ground, ruled header and selected-tab title as the frame's pane elsewhere.

* Add the OpenDuet skin: a phone-width frame and a Tasks screen on OpenBot's data

OpenDuet's look, rebuilt from OpenBot's primitives, Tabler icons and
OpenDuet's tokens, so a person can pick it in Settings and keep everything
OpenBot does.

The frame is one column at most 430px wide. On Chat and Tasks a header
floats at the top with the menu disc, OpenDuet's mic orb and the person's
initial (their Settings), and a frosted tab bar floats at the foot. The orb
presses the composer's own dictation rather than running a second one, so
recording, transcription and where the words land stay OpenBot's; on a
screen with no composer it opens Chat and starts there. Every other page
opens over the app with a back disc and its own heading in a title pill.
The side menu lists Chat, every conversation and group (pinned first, pin
and delete on right-click), New conversation, and under Manage: Bots,
Connections, Skills, Memory, Routines, Responsibilities, Approvals,
Notifications and, for administrators, Admin. Settings is never folded
away. The frame keeps OpenBot's channel socket and the browser notification
the sidebar's Bots badge sent.

Tasks, at /s/tasks, shows only what OpenBot keeps: pending approvals and
Bots' questions, decided and answered on their cards with OpenBot's own
mutations; active responsibilities and switched-on routines; and, under Up
next, background research's suggestions with Start and Hide.

Left out because OpenBot has no backend for them: Make, the morning brief,
triage, the setup checklist, first-day onboarding, reply chips, channel
icons and colours, Archived, the "Match phone" theme and adding tasks.

* Let the OpenDuet orb wake only when the composer starts or stops recording

The orb watched the whole conversation for the composer's recording
controls and set its state on every change to the page, which during a
streamed reply is every word. It now sets state only when recording
actually starts or stops.

* Set OpenDots' composer on the canvas colour, as OpenDots draws it in dark

OpenBot's composer sits on the card colour, which in this skin's dark set is a step above
the canvas; OpenDots' composer is the canvas with a hairline around it.

* Fix what OpenDuet's live pass found: the orb, the approval card's glyph, the composer's edge

Driving the skin against a real OpenBot found three things.

The orb rested while a Bot browsed with its computer: it read only the
roster's busy flag, which arrives over the socket and missed the person's
own run. It now also reads the composer's Stop control, which OpenBot
draws for exactly as long as a turn runs, and waits 700ms before thinking
so the moment Stop shows while a conversation opens is not a flash of
"Thinking" on every open.

A waiting computer_run_command was drawn with the browser's globe,
because the card asked whether the tool was the computer's before asking
whether it was a command. The kind is now worked out once, commands and
files first.

A conversation's composer ran flush to the 430px column's edges with its
focus ring on the screen's edge. The skin insets OpenBot's composer
wrapper by 12px, as OpenDuet floats its own.

* Build the OpenMuse skin: one agent, a phone-shaped column, five tabs

OpenMuse is a personal agent shaped like a phone. This rebuilds it on
OpenBot's own components, Tabler icons and tokens so a person can pick it
in Settings and keep everything OpenBot does.

The frame is a single 760px column: a menu button, the centre Bot as
OpenMuse's capybara with its name and a live status line, a bell for the
approvals and questions waiting on the person, and a floating pill of
Chat, Activity, Ideas, Goals and Apps. The centre Bot follows the
conversation on screen, then the person's choice, then OpenBot's default
Bot; a sheet behind the name switches it.

Chat is OpenBot's own chat route under the frame, restyled through the
skin's tokens and scoped CSS, so the computer, approval and component
tools keep working. Activity, Ideas, Goals and Apps read OpenBot's Bot
activity, approval inbox, suggestions, routines, responsibilities,
connections and memory through the existing query and mutation
factories. The menu reaches every OpenBot surface, Settings and Admin
included. Mail, calendar, page watches, PDF filling and task plans have
no OpenBot backend and are left out.

Light is OpenMuse's palette; dark is a night version in its spirit. The
tests render the frame against OpenBot's API shapes and check that every
surface is reachable and each tab reads and writes the right data.

* Clear a skin this build no longer ships from the page on load

index.html applies the stored skin before first paint without knowing which
skins exist, so a removed skin's name stayed on <html> for the whole visit
while the app drew the default. The store now settles the attribute when it
loads.

* Note the skins in the changelog

* Give the OpenDuet skin OpenBot's identity: the deployment's name, OpenBot's orb and avatars

A skin keeps OpenDuet's look and takes its identity from the OpenBot
deployment. The menu header and the orb's "Talk to …" now read the
product name from brand.yaml (appConfig.brand.productName), as OpenBot's
own sidebar does, and nothing a person reads says OpenDuet; the skin's
picker name stays OpenDuet, since that names the look.

The orb's face is OpenBot's AgentOrb, as sign-in and onboarding draw it,
in place of OpenDuet's mic-orb robot, which is removed. Its behaviour is
unchanged: it presses the composer's dictation, listens while recording
or typing, and thinks while the Bot works.

Conversation avatars are each Bot's own, drawn from its avatarSeed in
OpenBot's ChannelAvatar, and Tasks uses OpenBot's words for decisions:
Allow once, Always allow here, Deny, Start as task, Dismiss.

* Wear the deployment's brand in the OpenDots skin, keeping only OpenDots' look

A skin changes how OpenBot looks, never whose product it is. The wordmark and the home
links now name the product from brand.yaml (appConfig.brand.productName), the rail's
monogram is OpenBot's AgentOrb, and every Bot row and the coworker home draw OpenBot's own
avatar from the Bot's avatarSeed. The plush avatars and their images are gone. The words
follow OpenBot: BOTS, "Bots" in the breadcrumb, "Edit Bot". The rail, sidebar layout, top
bar, computer pane, density, type and palette stay OpenDots'. The skin's own name in the
picker is still OpenDots, since that names the look.

New tests render the frame and hold it to the product name, to never showing "OpenDots" or
"Dots", and to drawing each Bot with OpenBot's avatar from its seed; both fail on the
previous skin.

* Wear the deployment's brand in the OpenMuse skin

Skins keep their look but take their identity from the OpenBot deployment.
The OpenMuse skin now names itself with the brand.yaml product name, the
same one OpenBot's sidebar shows, and never says "OpenMuse" to a person;
only the picker still calls the look OpenMuse.

The capybara is gone. The top bar, the Bot switcher, the Your Bot card,
approval cards and conversation rows draw each Bot with its own OpenBot
avatar, and the deployment's AgentOrb stands in when there is no Bot yet.
Copy uses OpenBot's words: Bots, Connections, Approvals.

A regression test renders the frame on every tab and checks that it shows
the product name, never shows "OpenMuse" in text, labels or alt text, and
draws no capybara.

* Read the Anthropic key from either header in the AG2 test

Anthropic's SDK 2.3.0, which CI now installs for the AG2 harness, sends the
key as Authorization: Bearer instead of x-api-key. The agent's key still
reaches Anthropic; the test only looked for the old header, so it failed on
every pull request. It now accepts either, and passes with Anthropic's SDK
1.17.0 and 2.3.0 alike.

(cherry picked from commit a1391e7)

* Build OpenDuet's Tasks from OpenBot's own lists, and give pages OpenBot's width

From Guido's review of the skins.

Tasks re-implemented OpenBot's approvals, suggestions and routines, and
its copies had drifted: its own tool-name formatter, its own decision
buttons, approval cards that were all regions with the same name. Tasks
now draws OpenBot's components unchanged (WaitingForYou for approvals
and questions, BotResponsibilities, RoutinesList and SuggestionsInbox)
under OpenDuet's Active and Up next switch and section headings. What an
action will send, every choice and every confirmation are OpenBot's. The
skin keeps only the badge's count, and a test renders WaitingForYou and
holds the badge to the rows it draws.

The frame no longer writes an attribute onto a page's own heading. A
page opened over the app has a back disc and keeps its heading as drawn.

Only Chat and Tasks are phone-shaped now. Every other page keeps
OpenBot's width on a wide screen, and a conversation with its computer
or its Bot's details open grows by OpenBot's 400px pane, so the computer
sits beside the conversation as it does in OpenBot.

Every animated control in the frame says what reduced motion does, and a
test holds new ones to it; the orb is AgentOrb, which reads the same
preference. The skin's description no longer calls a Bot an agent.

* Make the OpenDots skin pass AA contrast, still for reduced motion, and reuse OpenBot's parts

Review on #856 found the skin's page label and description below WCAG AA, house-style copy
problems, no reduced-motion handling, and pieces rebuilt that OpenBot already has.

- Contrast: every text colour now reaches 4.5:1 and every icon 3:1 on the surface it sits
  on, in light and dark. Greys that fell short are darkened along their own hue; the
  YOUR WORKSPACE label grows from 8px to 10px.
- Copy: the picker description no longer says "coworkers"; the schedule screen is
  Routines, as OpenBot names it, at /s/routines, without "run on the server"; empty states
  and errors say what will appear and what to do next.
- Reduced motion: the frame's chrome and the menus, tooltips, sheets and dialogs it opens
  stop transitioning and animating under prefers-reduced-motion.
- Reuse: the phone drawer is OpenBot's Sheet (focus trap, Escape, scrim) at OpenBot's own
  768px breakpoint, and older conversations load through OpenBot's ChannelPagination.

New tests measure every colour pair against WCAG in both themes, hold the reduced-motion
rule and the chrome markers in place, and open the phone drawer to reach every surface.

* Save the skin on the account, share one navigation list, and give skins data-slot hooks

The skin was a per-browser choice, so the next person on a shared machine
inherited it. It is now a user preference (`skin`, default "openbot") that
the server validates against SKIN_IDS, which move to shared/. The picker
draws a skin at once and saves it through an optimistic preferences
mutation that puts the skin back and says so when the save fails.
SkinAccountSync, mounted in _authed, applies the account's skin whenever
the preferences load or change, so the account wins over the browser's
cache. localStorage stays only as the pre-paint cache, and the central
sign-out clears it.

The picker names the default skin after brand.yaml's product name and
shows each skin's description.

OpenBot's destinations (Bots, Capabilities, Connections, Admin for admins,
Settings) live in lib/navigation.ts. The sidebar renders its footer and
user menu from that list, so skins can read the same one.

Skins styled OpenBot through Tailwind classes and ARIA copy. The composer,
its input and buttons, the conversation header, the composer column, the
detail pane and the page title now carry data-slot hooks for them to use.

The Connections listing rules move from the route file to
lib/plugins/listed.ts, so OpenMuse's Apps screen stops importing a route.

* Build the OpenMuse skin's tabs from OpenBot's own components

The OpenMuse skin rebuilt approvals, routines, responsibilities,
suggestions, memory and connections, and its copies had already drifted
from OpenBot: a different tool-name formatter, "What it will send" hidden
behind a toggle, and its own routine delete flow. A new approval choice or
routine field would have been missing from the skin with nothing failing.

Each tab now puts OpenBot's own sections for the centre Bot under
OpenMuse's titles. The bell and Activity use WaitingForYou and BotNeedsYou;
Activity adds the Bot's activity sections; Ideas uses SuggestionsInbox and
ProactiveResearchSettings; Goals uses RoutinesList and BotResponsibilities,
with OpenBot's Delete dialog. Apps is OpenBot's Connections page. The
skin's copies and its formatter are gone.

A tab is lit only on its own screen, not on every other page. Pages that
are not a tab, and a conversation with its computer or settings open, take
OpenBot's own width on wide screens; the top bar and tab bar stay centred.
The chosen Bot is remembered per signed-in person, so the next person on a
shared browser starts from OpenBot's default Bot. Buttons, tabs and sheets
respect reduced motion, and copy follows OpenBot's style.

* Draw OpenDuet's menu from OpenBot's navigation list and dress pages by their hooks

The menu's destinations are OpenBot's one navigation list now
(useNavigationItems: Bots, Capabilities, Connections, Admin for admins,
Settings), so a destination added to OpenBot reaches this menu too. Chat,
the conversations and Tasks stay the skin's own. The skin's copy of the
list is gone, and the avatar disc takes Settings from the same list.

Every selector that reached OpenBot's markup by its classes or its words
now uses the data-slot hooks: the composer column for the inset, the
composer's stop control for "working", its input for the caret. Only
the three dictation controls, which have no hook, are still found by the
names OpenBot gives them, and a test holds those to the real composer.

A page opened over the app has its title back in the pill, read from its
page-title hook and never written to; the title stays for screen readers.
Where the page draws its own back link, the chrome's back disc goes where
that link goes and the page's own bar is hidden, so there is one way back.

* Give the composer's dictation buttons their own hooks

A skin that restyles or drives dictation found the three buttons by their
aria-labels, so rewording one would break it without a test failing. They
carry composer-dictate, composer-dictate-cancel and composer-dictate-stop.

* Build OpenDots' destinations from OpenBot's navigation list and style pages through their hooks

The rail and sidebar now draw OpenBot's destinations from useNavigationItems(), the same list
OpenBot's own sidebar renders, so a destination added there reaches this skin too. The skin
keeps only what is its own: BOTS, RECENT CHATS, and its Routines and Memories screens. Bots
sits under the list of Bots; Capabilities and Connections are in the rail and the phone
drawer; Admin and Settings close the sidebar. OpenBot's Bots badge, which also sends the
browser notification, is mounted once: on the rail's Bots button, or on the menu button on a
phone.

skin.css no longer names OpenBot's Tailwind classes. The composer, send button, conversation
header, composer column and detail pane are styled through the data-slot hooks those pages
publish for skins.

Tests hold the rail and sidebar to navigationFor() for a member and an admin, and fail any
selector in skin.css that names a class other than .dark.

* Find the composer's dictation controls by their hooks in the OpenDuet orb

The orb found the composer's dictate, cancel and stop controls by their
accessible names, so rewording one for a screen reader would have broken
it silently. It uses the composer-dictate, composer-dictate-cancel and
composer-dictate-stop hooks now, and a test fails if any selector in the
skin, in its stylesheet or its code, targets an aria-label.

* Hook the OpenMuse skin onto OpenBot's navigation list and data-slots

The menu sheet kept its own list of OpenBot destinations, which would miss
any page OpenBot adds. Its destinations now come from the shared
navigation list OpenBot's sidebar draws, filtered for the signed-in
person; conversations and the skin's tabs stay as they were.

The stylesheet reached OpenBot's components through Tailwind classes and
ARIA labels, so restyling the composer or the conversation header in
OpenBot would have broken the skin without a test failing. It now uses
only the data-slot hooks those components publish: composer,
composer-input, composer-attach/send/stop, conversation-header and
page-title. The system font is set through the font-sans token rather
than by overriding OpenBot's font classes.

* Say in the changelog that the skin follows the account

* Read the Anthropic key and API version the 2.x SDK sends in the LangGraph AG-UI test

anthropic 2.x sends the key as Authorization: Bearer instead of x-api-key and
dates its Messages API version later than 2023-06-01. The provider-boundary
test asserted both by their 1.x values, so it failed once the unpinned
requirements resolved 2.x. It now reads the key from either header and checks
the version is a date; the endpoint, key, model and body it asserts are
unchanged.

(cherry picked from commit 99685ee)

* Launch the Chromium build CI installs in the enter-text test

CI installs Chromium with --no-shell since #829, and enter-text launched
Playwright's default, the separate headless shell, so it failed to start.
It now launches channel "chromium", the build the computer itself launches.

(cherry picked from commit f220198)

* Record isBrokered's new home in the duplicate-definition guard

The Connections page's helpers moved from the route file into
lib/plugins/listed.ts, and the guard's list of known brokered-provenance
sites still named the route file.

* Wait for home's composer, not its greeting, when a skin switch lands home

Home's heading became a personal greeting in #861, so the test that a skin
switch on a skin-only screen lands on a drawn home waited for wording that no
longer exists. It now waits for the home composer.
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.

2 participants