App shell, sidebar and command menu
F02 · 28 mapped behaviors in the Self-Healing Codebase Project. Follow the prerequisites, actions and expected results; expand the original CLI recipe to replay it.
778 behavior IDs · 28 families · 844 named recipes & support steps
16 October 2026 · PR #18334 at 9a3c3a69
Canvas 1.27.1 · Agent Server 1.55.0 · automation 1.20.0
This is the map at the revision above, including its open bug notes. It does not incorporate later changes on main or claim a fresh verification run. Setup & reading guide · Download the scenario inventory
All scenarios & marker key · Open a script to read Given / Do / Expect. Expand the exact recipe for replayable commands.
No scenarios match. Try a different word or reset.
F02 App shell, sidebar and command menu
28 behaviors · 31 scripts & contracts · Maintained source
Entry points & prerequisites
What this family covers
Every page inside the root layout shares one shell. On desktop it is a left rail with the logo, Search commands, New Chat, Customize, Automate (when the automation interface is present), the conversation list, the Getting started checklist, an update tile (only when a newer release exists) and the backend selector with a settings gear. The rail collapses to icons and remembers that choice. Below 768 px the rail turns into a drawer that opens from a top bar or the chat header. A user can pin Customize or Automate as the page / opens. A Ctrl/Cmd+K command menu searches pages, settings and actions. Failed requests show error toasts.
How a user gets here
- Any page in the app: the left rail (desktop) or the hamburger (phone,
browser viewport phone). - Direct URLs:
/(the default home, or a redirect to the pinned page),/conversations,/customize,/automations,/settings. - Command menu: press
Control+korMeta+kanywhere, or click Search commands (command-menu-trigger) in the rail or drawer. Type a page or setting name, then press Enter or click the row. - Hover a sidebar row to reveal its pin. Hover the collapsed rail's logo to reveal the expand chevron.
- Settings → Application (
/settings/app): the Show Getting Started checklist switch. - The Getting started card: click an item row to go to its page, or hover it for the preview; hover the card for the X that dismisses it.
- Keyboard:
Control+kalso works while the composer has focus; Tab moves from the search input into the option list.
Given
Preconditions:
- Baseline state (launched, doctored,
onboard --skipdone), desktop viewport, sidebar expanded, no home pin, checklist shown. F02.checklist-progress(LLM and chat items) needscontrol-openhands llm preset deepseekand one conversation (control-openhands conversation start --prompt "Reply with only the word: ok" --wait --timeout 180). Run both before theF02.conversation-listbullet. The preset writes through the API, socontrol-openhands browser reloadbefore you read the LLM item. The conversation-header hamburger check inF02.mobile-drawerreuses that conversation.F02.update-tile(the sidebar tile) is blocked unless the installed version is older than npmlatestand the browser can reachregistry.npmjs.org. The Settings → Application check runs either way.F02.alert-banneris blocked on the local backend, whose config always reports no alerts; it needs a Cloud backend that publishes them.F02.settings-404-modalis blocked: it needs a backend whose settings endpoint returns 404.F02.checklist-all-completeneeds an automation and an MCP server on top of the four items above. Both are added through the UI from two fixtures (see that bullet) and deleted again afterwards.
Sidebar linksF02.nav-linksMapped behavior
Scenario F02--sidebar-links · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /conversations.
- DoChoose “Sidebar skills”.
- WaitWait for the element identified in the CLI recipe to appear.
- DoOpen the URL in the recipe.
- DoChoose “Sidebar automations”.
- DoChoose “Sidebar conversations”.
- DoChoose the element identified in the CLI recipe.
Expect
the logo and New Chat open /conversations. Customize opens /customize, which redirects to /mcp on desktop, and stays highlighted and marked aria-current="page" on /skills, /plugins, /apps and /mcp. Automate opens /automations. Canvas extension pages add their own rows (sidebar-canvas-extension-<ext>-<id>).
Exact CLI recipe & bug checks
Run control-openhands browser goto /conversations, control-openhands browser click 'testid=sidebar-skills-link', then control-openhands browser wait-url '/mcp$'. The URL ends in /mcp because desktop /customize redirects there. Run control-openhands browser attr 'testid=sidebar-skills-link' class; the class contains bg-tertiary (the active style), and control-openhands browser attr 'testid=sidebar-skills-link' aria-current is page. Repeat browser goto with /skills, /plugins and /apps; each time the class still contains bg-tertiary and aria-current is still page. Run control-openhands browser click 'testid=sidebar-automations-link', control-openhands browser url (ends in /automations) and control-openhands browser attr 'testid=sidebar-automations-link' aria-current (page); control-openhands browser attr 'testid=sidebar-skills-link' aria-current is now null. Then run control-openhands browser click 'testid=sidebar-conversations-link' and control-openhands browser click 'aside[data-collapsed] >> role=link[name="OpenHands Logo"]'; both leave the URL at /conversations.
Pin as homeF02.pin-as-homeMapped behavior
Scenario F02--pin-as-home · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoHover over “Sidebar skills”.
- DoChoose “Sidebar pin home toggle customize”.
- DoOpen /.
- WaitWait for the element identified in the CLI recipe to appear.
- DoHover over “Sidebar automations”.
- DoChoose “Sidebar pin home toggle automations”.
- DoOpen /.
- DoChoose “Sidebar pin home toggle automations”.
- DoOpen /.
- DoUse browser storage as specified in the exact recipe.
Expect
hovering Customize or Automate reveals a pin. Pinning makes / redirect to that page, pinning the other one moves the pin, and unpinning restores the default home. The pin is stored per backend and org.
Exact CLI recipe & bug checks
From /conversations run control-openhands browser visible 'testid=sidebar-pin-home-toggle-customize' (false), control-openhands browser hover 'testid=sidebar-skills-link', the same visible (true), then control-openhands browser click 'testid=sidebar-pin-home-toggle-customize' and control-openhands browser attr 'testid=sidebar-pin-home-toggle-customize' aria-pressed (true). Run control-openhands browser goto / and control-openhands browser wait-url '/mcp$'; the URL ends in /mcp. Run control-openhands browser screenshot 'aside[data-collapsed]' --feature F02.pin-as-home --name customize-pinned; the screenshot shows a filled pin on the Customize row with no hover. Move the pin: run control-openhands browser hover 'testid=sidebar-automations-link' and control-openhands browser click 'testid=sidebar-pin-home-toggle-automations'. The Customize pin's aria-pressed becomes false, and control-openhands browser goto / lands on /automations. Unpin with control-openhands browser click 'testid=sidebar-pin-home-toggle-automations', then run control-openhands browser goto / and control-openhands browser count 'testid=home-screen'. The URL stays / and the count is 1. control-openhands browser storage --values shows oh:pinned-home-route:<backend>:<org> as null.
Collapse and expandF02.sidebar-collapseMapped behavior
Scenario F02--collapse-and-expand · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Sidebar collapse toggle”.
- DoReload the page.
- DoUse browser storage as specified in the exact recipe.
- DoHover over “Sidebar automations”.
- DoHover over “Sidebar skills”.
- WaitWait for the tooltip to appear.
- DoHover over “Collapsed backend selector”.
- DoChoose the element identified in the CLI recipe.
- DoHover over the element identified in the CLI recipe.
- DoChoose “Sidebar collapse toggle”.
Expect
the chevron collapses the rail to a 60 px icon rail with hover tooltips, a Settings icon and a backend icon with a status dot that opens a backend popover. The checklist is hidden while collapsed. The state survives a reload. To expand, click the chevron that appears when you hover the logo, or click empty rail space.
Exact CLI recipe & bug checks
Run control-openhands browser click 'testid=sidebar-collapse-toggle' and control-openhands browser attr 'aside[data-collapsed]' data-collapsed (true). Run control-openhands browser reload; the attribute is still true, browser storage --values shows openhands-sidebar with "collapsed":true, and control-openhands browser bbox 'aside[data-collapsed]' reports width 60. control-openhands browser count 'testid=sidebar-onboarding-checklist' is 0. For the tooltip, hover one icon, then another: control-openhands browser hover 'testid=sidebar-automations-link', control-openhands browser hover 'testid=sidebar-skills-link', then control-openhands browser wait 'role=tooltip' and control-openhands browser text 'role=tooltip' (Customize). For the backend popover, run control-openhands browser hover 'testid=collapsed-backend-selector-link'; its aria-expanded is true, browser testids --filter backend lists add-backend-menu-item and manage-backends-menu-item, and control-openhands browser screenshot --feature F02.sidebar-collapse --name backend-popover shows the popover. Expand by clicking empty rail space with control-openhands browser click 'aside[data-collapsed]' (data-collapsed becomes false). Collapse again, then run control-openhands browser hover 'aside[data-collapsed] >> role=link[name="OpenHands Logo"]'; the toggle's class has opacity-100 and its aria-label is Expand sidebar. control-openhands browser click 'testid=sidebar-collapse-toggle' expands the rail.
Settings gearF02.settings-linkMapped behavior
Scenario F02--settings-gear · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Sidebar collapse toggle”.
- DoChoose “Collapsed settings”.
- WaitWait for the element identified in the CLI recipe to appear.
- DoChoose “Sidebar collapse toggle”.
- DoOpen /conversations.
- DoChoose “Settings”.
Expect
the gear next to the backend selector, and the collapsed Settings icon, open /settings in the same tab for a local backend. On desktop that redirects to /settings/agents.
Exact CLI recipe & bug checks
The previous bullet expanded the rail: collapse it with control-openhands browser click 'testid=sidebar-collapse-toggle', then run control-openhands browser click 'testid=collapsed-settings-link' and control-openhands browser wait-url '/settings'. Expand it again with control-openhands browser click 'testid=sidebar-collapse-toggle', then run control-openhands browser goto /conversations, control-openhands browser click 'testid=backend-selector-settings-link' and control-openhands browser url; the URL ends in /settings/agents. control-openhands browser attr 'testid=backend-selector-settings-link' target is null (same tab).
Conversation listF02.conversation-listMapped behavior
Scenario F02--conversation-list · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoStart a conversation as specified in the recipe.
- DoOpen /conversations.
Expect
the expanded rail embeds the conversation list (conversation-panel). The list itself belongs to the conversations family.
Exact CLI recipe & bug checks
After conversation start (preconditions), run control-openhands browser goto /conversations and control-openhands browser testids 'testid=conversation-panel'. The list includes conversation-card.
Toggle sidebarF02.command-menu-toggle-sidebarMapped behavior
Scenario F02--toggle-sidebar · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoPress Control+k.
- DoEnter “toggle” in “Command menu” / the combobox.
- DoPress Enter.
Expect
the Toggle sidebar action collapses or expands the desktop rail.
Exact CLI recipe & bug checks
Run control-openhands browser press Control+k, control-openhands browser type 'testid=command-menu >> role=combobox' toggle, control-openhands browser press Enter, then control-openhands browser attr 'aside[data-collapsed]' data-collapsed (true). Repeat with the term sidebar; the value returns to false.
Search, empty state, keyboardF02.command-menu-searchMapped behavior
Scenario F02--search-empty-state-keyboard · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoPress Control+k.
- DoEnter “theme” in “Command menu” / the combobox.
- DoPress Enter.
- DoChoose “Command menu” / “Clear search”.
- DoPress ArrowUp.
- DoHover over “Command menu” / “Secrets settings”.
Expect
every search term must match the title, description or keywords. No commands found is the empty state. The X button clears the query. Arrow keys wrap around the list, hovering an item selects it, Enter runs the selected item, and Enter does nothing when nothing matches.
Exact CLI recipe & bug checks
The Toggle sidebar action closed the menu: open it with control-openhands browser press Control+k, then run control-openhands browser fill 'testid=command-menu >> role=combobox' theme and control-openhands browser count 'testid=command-menu >> role=option' (1, Application, matched by its keywords). The term settings secret leaves 1 option, secret automations leaves 0 (all terms must match) and model leaves 3 (MCP servers, LLM profiles, Model Router). Fill qa-zzz-nothing, then run control-openhands browser text 'testid=command-menu >> role=listbox' (No commands found / Try a page, action, or setting name.) and control-openhands browser screenshot --feature F02.command-menu-search --name no-results. Run control-openhands browser press Enter; the menu stays open and the URL does not change. Run control-openhands browser click 'testid=command-menu >> role=button[name="Clear search"]'; the value is "" and the count is back to 14. Keyboard: control-openhands browser attr 'testid=command-menu >> role=combobox' aria-activedescendant starts at command-menu-option-new-chat. control-openhands browser press ArrowUp wraps to command-menu-option-toggle-sidebar, and ArrowDown returns to new-chat, then moves to customize. control-openhands browser hover 'testid=command-menu >> role=option[name=/Secrets settings/]' sets the value to command-menu-option-secrets-settings.
Open in a new tabF02.command-menu-new-tabMapped behavior
Scenario F02--open-in-a-new-tab · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Command menu” / “Secrets settings”.
- DoUse browser tabs as specified in the exact recipe.
- DoUse browser close tab as specified in the exact recipe.
- DoChoose “Command menu” / “Secrets settings”.
- DoPress Escape.
Expect
a middle-click or modifier-click on a Go item opens the route in a new tab and leaves the menu open.
Exact CLI recipe & bug checks
With the menu open and secrets typed, control-openhands browser attr 'testid=command-menu >> role=option[name=/Secrets settings/]' href is /settings/secrets. Run control-openhands browser click 'testid=command-menu >> role=option[name=/Secrets settings/]' --button middle and control-openhands browser tabs; tab 1 is /settings/secrets, tab 0 keeps its URL, and browser count 'testid=command-menu' is still 1. Run control-openhands browser close-tab 1. The modifier path works the same: control-openhands browser click 'testid=command-menu >> role=option[name=/Secrets settings/]' --modifiers Control opens tab 1 with the menu still open; close that tab too. The click leaves focus on the option; control-openhands browser press Escape still closes the menu (count 0).
Keyboard focusF02.command-menu-focusMapped behavior
Scenario F02--keyboard-focus · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Message”.
- DoPress Control+k.
- DoPress Tab.
- DoPress Escape.
Expect
the shortcut works while typing in another field (the composer) and moves focus to the search input. Tab moves focus to the first option. Escape closes the menu from any focused element inside it and returns focus to the composer.
Exact CLI recipe & bug checks
From /conversations run control-openhands browser click 'testid=chat-input', control-openhands browser press Control+k, browser count 'testid=command-menu' (1) and control-openhands browser eval "document.activeElement && document.activeElement.id" (command-menu-search): the shortcut opens the menu from inside the composer. Run control-openhands browser press Tab; the same eval returns command-menu-option-new-chat. control-openhands browser press Escape closes the menu from the option (count 0), and control-openhands browser eval "document.activeElement.dataset.testid" returns chat-input: focus is back in the composer.
Phone drawerF02.mobile-drawerMapped behavior
Scenario F02--phone-drawer · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- SetupUse the phone viewport.
- DoOpen /conversations.
- DoChoose “Sidebar mobile menu toggle”.
- WaitWait for “Sidebar mobile drawer” to appear.
- WaitWait for “Sidebar mobile drawer” to disappear.
- DoChoose “Sidebar mobile drawer close”.
- DoPress Escape.
- DoChoose “Sidebar mobile drawer” / “Sidebar automations”.
- DoUse browser mouse click as specified in the exact recipe.
- DoChoose “Submit”.
- DoOpen the URL in the recipe.
- DoStart a conversation as specified in the recipe.
- SetupUse the desktop viewport.
Expect
at phone width the rail is hidden and a hamburger (sidebar-mobile-menu-toggle) opens a 300 px drawer. The hamburger is in the top bar, or in the chat header on conversation pages. The drawer closes on its chevron, Escape, a backdrop click or any route change.
Exact CLI recipe & bug checks
Run control-openhands browser viewport phone and control-openhands browser goto /conversations. control-openhands browser visible 'aside[data-collapsed]' is false. Run control-openhands browser click 'testid=sidebar-mobile-menu-toggle' and control-openhands browser wait 'testid=sidebar-mobile-drawer'. control-openhands browser bbox 'testid=sidebar-mobile-drawer' gives width 300, insideViewport true and pageHorizontalOverflow false, and control-openhands browser screenshot --feature F02.mobile-drawer --name open shows the full rail. Close paths, each followed by control-openhands browser wait 'testid=sidebar-mobile-drawer' --state detached: control-openhands browser click 'testid=sidebar-mobile-drawer-close'; control-openhands browser press Escape; control-openhands browser click 'testid=sidebar-mobile-drawer >> testid=sidebar-automations-link' (route change; the URL becomes /automations); and a backdrop click to the right of the drawer, control-openhands browser mouse-click 350 400 (on /conversations, control-openhands browser click 'testid=submit-button' --force also lands on the backdrop, because the empty composer's send button sits at x≈326 under it). On a conversation page (browser goto the URL from conversation start), control-openhands browser bbox 'testid=sidebar-mobile-menu-toggle' is at the top-left of the chat header. control-openhands browser screenshot --feature F02.mobile-drawer --name conversation-header shows it beside the title, and clicking it opens the drawer. Return with control-openhands browser viewport desktop.
Back chevronF02.mobile-top-barMapped behavior
Scenario F02--back-chevron · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- SetupUse the phone viewport.
- DoOpen /settings/llm.
- DoChoose “Sidebar mobile back”.
Expect
at phone width, settings sub-pages and Customize detail pages (/skills, /mcp, /plugins, /apps) show a Back chevron that returns to /settings or /customize.
Exact CLI recipe & bug checks
The Phone drawer bullet returned to desktop: run control-openhands browser viewport phone, control-openhands browser goto /settings/llm and control-openhands browser attr 'testid=sidebar-mobile-back-button' aria-label (Settings). Then run control-openhands browser click 'testid=sidebar-mobile-back-button' and control-openhands browser url; the URL is /settings, and on that page browser count 'testid=sidebar-mobile-back-button' is 0. control-openhands browser screenshot --feature F02.mobile-top-bar --name settings-root shows only the hamburger above the settings menu. Do the same from /skills: the label is Customize and the click lands on /customize, which on phone is the hub (extensions-mobile-hub).
Checklist cardF02.checklistMapped behavior
Scenario F02--checklist-card · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- SetupUse the desktop viewport.
- DoOpen /conversations.
Expect
after onboarding, the expanded rail shows a Getting started card with N complete and six items. They link to /settings/llm, /conversations, /automations, /settings/agents, /mcp and the external Slack invite.
Exact CLI recipe & bug checks
The phone bullets above leave the phone viewport on /settings/secrets: run control-openhands browser viewport desktop, control-openhands browser goto /conversations, then control-openhands browser count 'testid=sidebar-onboarding-checklist >> role=listitem' (6) and control-openhands browser text 'testid=sidebar-onboarding-checklist'. The first lines are Getting started and N complete. control-openhands browser snapshot 'aside[data-collapsed]' shows the six links: /settings/llm, /conversations, /automations, /settings/agents, /mcp and https://openhands.dev/joinslack.
Item linksF02.checklist-item-linksMapped behavior
Scenario F02--item-links · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Sidebar onboarding checklist item schedule task”.
- DoChoose “Sidebar onboarding checklist item configure llm”.
- DoUse browser tabs as specified in the exact recipe.
Expect
clicking an item's row navigates in the same tab to its route (for example Schedule a task opens /automations) without marking the item done.
Exact CLI recipe & bug checks
Run control-openhands browser click 'testid=sidebar-onboarding-checklist-item-schedule-task' --expect-url '/automations(\?|$)' and control-openhands browser click 'testid=sidebar-onboarding-checklist-item-configure-llm' --expect-url '/settings/llm(\?|$)'; both pass, browser tabs still lists one tab, and browser count 'testid=sidebar-onboarding-checklist-item-schedule-task >> css=span.line-through' stays 0 (visiting is not completing).
ProgressF02.checklist-progressMapped behavior
Scenario F02--progress · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /settings/agents.
- DoChoose “Sidebar onboarding checklist item join slack”.
- DoUse browser tabs as specified in the exact recipe.
- DoUse browser close tab as specified in the exact recipe.
- SetupConfigure or inspect the model profiles specified in the recipe.
- DoReload the page.
- WaitWait for the element identified in the CLI recipe to appear.
- DoStart a conversation as specified in the recipe.
Expect
items get a check and a strikethrough when done. The LLM item completes when a profile is configured, Start your first chat when a conversation exists, Customize your agent after a visit to /settings/agents, and Join Slack on click.
Exact CLI recipe & bug checks
Each completed item renders a struck-through label, so control-openhands browser count 'testid=sidebar-onboarding-checklist-item-<id> >> css=span.line-through' is 1. Run control-openhands browser goto /settings/agents, then come back; customize-agent is done. Run control-openhands browser click 'testid=sidebar-onboarding-checklist-item-join-slack'; join-slack is done and browser tabs shows an external Slack tab, which you close with control-openhands browser close-tab 1. After llm preset deepseek, run control-openhands browser reload (the open page does not refetch settings written through the API), then control-openhands browser wait 'testid=sidebar-onboarding-checklist-item-configure-llm >> css=span.line-through' --timeout 15000. After conversation start, start-conversation is done. The header count rises each time (4 complete after these four).
Item previewF02.checklist-previewMapped behavior
Scenario F02--item-preview · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoHover over “Sidebar onboarding checklist item join slack”.
- DoHover over “Sidebar onboarding checklist item connect mcp”.
- WaitWait for “Sidebar onboarding checklist preview connect mcp” to appear.
- DoChoose “Sidebar onboarding checklist preview action connect mcp”.
- WaitWait for the element identified in the CLI recipe to appear.
Expect
hovering an item shows a preview with a description, a Documentation link and an action button that navigates.
Exact CLI recipe & bug checks
Run control-openhands browser hover 'testid=sidebar-onboarding-checklist-item-join-slack', control-openhands browser hover 'testid=sidebar-onboarding-checklist-item-connect-mcp' and control-openhands browser wait 'testid=sidebar-onboarding-checklist-preview-connect-mcp' --timeout 5000. Then run control-openhands browser text 'testid=sidebar-onboarding-checklist-preview-connect-mcp'; it reads the title, the description, Documentation and Connect. control-openhands browser attr 'testid=sidebar-onboarding-checklist-preview-docs-connect-mcp' href is https://docs.openhands.dev/overview/model-context-protocol. Take control-openhands browser screenshot --feature F02.checklist-preview --name connect-mcp, then run control-openhands browser click 'testid=sidebar-onboarding-checklist-preview-action-connect-mcp' and control-openhands browser wait-url '/mcp$'.
MinimizeF02.checklist-minimizeMapped behavior
Scenario F02--minimize · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Sidebar onboarding checklist toggle”.
- DoReload the page.
Expect
the card header minimizes and expands the card, and the state survives a reload.
Exact CLI recipe & bug checks
Run control-openhands browser click 'testid=sidebar-onboarding-checklist-toggle', control-openhands browser attr 'testid=sidebar-onboarding-checklist' data-minimized (true) and browser count 'testid=sidebar-onboarding-checklist >> role=listitem' (0). After control-openhands browser reload the attribute is still true and the toggle's aria-label is Expand checklist. Click the toggle again to restore false.
DismissF02.checklist-dismissMapped behavior
Scenario F02--dismiss · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoHover over “Search commands”.
- DoHover over “Sidebar onboarding checklist toggle”.
- WaitWait for “Dismiss checklist” to appear.
- DoChoose “Dismiss checklist”.
- DoReload the page.
- DoUse browser storage as specified in the exact recipe.
- DoChoose “Show Getting Started checklist”.
- DoChoose “Sidebar onboarding checklist toggle”.
Expect
hovering or focusing the card (expanded or minimized) reveals an X (Dismiss checklist) in its header; touch devices always show it. Clicking it hides the card for good (it stays hidden after a reload) and turns off the Show Getting Started checklist switch in Settings → Application, which brings the card back in its previous expanded or minimized state.
Exact CLI recipe & bug checks
On /conversations, control-openhands browser count 'role=button[name="Dismiss checklist"]' is 0 (the X is opacity-0 and invisible until the card is hovered). Run control-openhands browser hover 'testid=command-menu-trigger', control-openhands browser hover 'testid=sidebar-onboarding-checklist-toggle' and control-openhands browser wait 'role=button[name="Dismiss checklist"]' --state visible --timeout 5000 (browser screenshot 'aside[data-collapsed]' --feature F02.checklist-dismiss --name hover-close). Run control-openhands browser click 'role=button[name="Dismiss checklist"]': browser count 'testid=sidebar-onboarding-checklist' is 0, still 0 after control-openhands browser reload, and browser storage lists openhands-sidebar-onboarding-checklist-dismissed. On /settings/app, control-openhands browser eval "document.querySelector('[data-testid=show-getting-started-checklist-switch]').checked" is false; control-openhands browser click 'text=Show Getting Started checklist' brings the card back. Minimized: control-openhands browser click 'testid=sidebar-onboarding-checklist-toggle' (data-minimized true), hover as above, click the X (count 0), click the switch text again: the card returns with data-minimized true; click the toggle to expand it. At phone width the X shows in the drawer's card the same way.
Hide from settingsF02.checklist-hideMapped behavior
Scenario F02--hide-from-settings · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /settings/app.
- DoChoose “Show Getting Started checklist”.
- DoReload the page.
Expect
the Show Getting Started checklist switch in Settings → Application hides the card (it stays hidden after a reload) and can show it again.
Exact CLI recipe & bug checks
Run control-openhands browser goto /settings/app and control-openhands browser click 'text=Show Getting Started checklist'; browser count 'testid=sidebar-onboarding-checklist' is 0. After control-openhands browser reload the count is still 0, and control-openhands browser eval "document.querySelector('[data-testid=show-getting-started-checklist-switch]').checked" is false. Click the same text again; the count is 1.
All completeF02.checklist-all-completeMapped behavior
Scenario F02--all-complete · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- SetupCreate the disposable file fixture specified in the recipe.
- SetupCreate the disposable file fixture specified in the recipe.
- DoOpen /mcp.
- DoChoose “Mcp add custom server”.
- DoChoose “Server type dropdown”.
- DoChoose “STDIO”.
- DoEnter “qa_f02_mcp” in “Name”.
- DoEnter “python3” in “Command”.
- DoEnter “$OH_VERIFY_RUN/evidence/_fixtures/qa-f02-mcp.py” in “Args”.
- DoChoose “Mcp custom editor” / “Submit”.
- WaitWait for “Mcp custom editor” to disappear.
- DoOpen /automations.
- DoChoose “Automations add automation”.
- DoChoose “Automations import automation”.
- DoUse browser upload as specified in the exact recipe.
- DoChoose “Import automation confirm”.
- WaitWait for “Import automation modal” to disappear.
- DoReload the page.
- DoChoose the element identified in the CLI recipe.
- DoChoose the list / containing “Export” / “Delete”.
- DoChoose “Delete automation” / its containing control / “Delete”.
- DoReload the page.
- DoOpen /mcp.
- DoChoose “Mcp server detail qa f02 mcp”.
- DoChoose “Mcp custom editor delete”.
- DoChoose “Confirmation dialog” / “Confirm”.
- DoReload the page.
Expect
the card disappears once all six items are complete. Completion is recomputed from current data, so deleting the automation or the MCP server brings the card back.
Exact CLI recipe & bug checks
Start with the four items above done (5 complete would mean one fixture is left over). Arrange two fixtures: a minimal stdio MCP server, control-openhands fixture file --name qa-f02-mcp.py --content "$(printf '%s\n' 'import sys,json' 'for line in sys.stdin:' ' m=json.loads(line)' ' if "id" not in m: continue' ' r={}' ' if m.get("method")=="initialize": r={"protocolVersion":m["params"].get("protocolVersion","2024-11-05"),"capabilities":{"tools":{}},"serverInfo":{"name":"qa","version":"1"}}' ' elif m.get("method")=="tools/list": r={"tools":[]}' ' sys.stdout.write(json.dumps({"jsonrpc":"2.0","id":m["id"],"result":r})+"\n"); sys.stdout.flush()')", and control-openhands fixture file --name qa-f02.automation.json --content '{"version":1,"kind":"automation","spec":{"name":"QA_F02 Done","trigger":{"type":"cron","schedule":"0 0 1 1 *","timezone":"UTC"},"enabled":false,"prompt":"Reply with the single word: pong. Do not run any tools."}}'. Add the server in the UI: control-openhands browser goto /mcp, control-openhands browser click 'testid=mcp-add-custom-server', control-openhands browser click 'testid=server-type-dropdown', control-openhands browser click 'role=option[name="STDIO"]', control-openhands browser fill 'testid=name-input' qa_f02_mcp, control-openhands browser fill 'testid=command-input' python3, control-openhands browser fill 'testid=args-input' "$OH_VERIFY_RUN/evidence/_fixtures/qa-f02-mcp.py", control-openhands browser click 'testid=mcp-custom-editor >> testid=submit-button' and control-openhands browser wait 'testid=mcp-custom-editor' --state detached. The header reads 5 complete. Import the automation: control-openhands browser goto /automations, control-openhands browser click 'testid=automations-add-automation', control-openhands browser click 'testid=automations-import-automation', control-openhands browser upload 'testid=automations-import-file' "$OH_VERIFY_RUN/evidence/_fixtures/qa-f02.automation.json", control-openhands browser click 'testid=import-automation-confirm' and control-openhands browser wait 'testid=import-automation-modal' --state detached. Now browser count 'testid=sidebar-onboarding-checklist' is 0, still 0 after control-openhands browser reload, and control-openhands browser screenshot 'aside[data-collapsed]' --feature F02.checklist-all-complete --name rail shows the rail without the card. Restore and prove it comes back: open the card's kebab with control-openhands browser click '[data-testid^="automation-card-"] >> has-text=QA_F02 Done >> role=button[name="Automation actions"]', then control-openhands browser click 'role=list >> has-text=Export >> role=button[name="Delete"]', control-openhands browser click 'role=heading[name="Delete automation"] >> xpath=.. >> role=button[name="Delete"]' and control-openhands browser reload; the card count is 1 again (5 complete). Then control-openhands browser goto /mcp, control-openhands browser click 'testid=mcp-server-detail-qa_f02_mcp', control-openhands browser click 'testid=mcp-custom-editor-delete', control-openhands browser click 'testid=confirmation-modal >> testid=confirm-button' and control-openhands browser reload; testid=mcp-installed-empty is back and the card reads 4 complete.
Setup guideF02.super-admin-setup-guideBlocked
Scenario F02--setup-guide · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoLocal:
control-openhands browser count 'testid=super-admin-setup-guide'is0atdesktopandphone,browser count 'testid=sidebar-onboarding-checklist'is1, andcontrol-openhands browser network --filter setup-statereportstotal0. The positive path is blocked locally: it needs an OHE backend withENABLE_SUPER_ADMINwhose/api/admin/setup-statereturns aguide_org_id,guide_dismissedfalseand at least one unfinished required step, signed in as the first Super Admin.
Expect
on an OpenHands Enterprise (cloud) backend with ENABLE_SUPER_ADMIN, the first Super Admin (/me permissions include manage_super_admins) sees a floating Setup guide panel in the lower-right corner with n/4 progress, the steps Add an LLM, Choose an automation template, Add an integration, Invite users and Optional: SAML / instance, a Next: <step> status and a Start link for that step (the positive Enterprise path remains unverified here). Close collapses it to a pill that reopens it. While the guide loads or shows, the Getting started card is hidden. Local backends never show it and make no /api/admin/setup-state request (#17969).
Exact CLI recipe & bug checks
Local: control-openhands browser count 'testid=super-admin-setup-guide' is 0 at desktop and phone, browser count 'testid=sidebar-onboarding-checklist' is 1, and control-openhands browser network --filter setup-state reports total 0. The positive path is blocked locally: it needs an OHE backend with ENABLE_SUPER_ADMIN whose /api/admin/setup-state returns a guide_org_id, guide_dismissed false and at least one unfinished required step, signed in as the first Super Admin.
Setup tourF02.super-admin-setup-tourBlocked
Scenario F02--setup-tour · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /?setup_tour=first-automation.
Expect
for the two setup steps done in Canvas (Choose an automation template, Add an integration), the guide walks the Super Admin through the page with a guided tour (.oh-setup-tour-popover with Back / Next / Done): the template step points at the recommended-automations section (a stop with no footer: no Back, Next or 1/2, #18243), then the setup dialog; the integration step at the MCP library on /mcp (mcp-marketplace-section, "Pick a server from the library"), then the install dialog (#18261). A plain click on a Canvas step's row in the guide starts that step's tour and closes the panel (a modifier click follows the link), and while the tour waits for its next stop's element it hides its popover and overlay, so it never covers another dialog (#18261). Finishing the guide's next step in Canvas opens the step after it the way Start does (a Canvas step's tour or page; an enterprise step reopens the guide to point at Start, or navigates on a locked-Cloud canvas). An enterprise page that links back with ?setup_tour=<step id> starts that step's tour once and drops the parameter. Local backends ignore ?setup_tour= (no tour, no guide, the parameter stays) (#18138). The positive path is blocked here, with the same Enterprise prerequisite as the setup guide above.
Exact CLI recipe & bug checks
Local, at desktop and phone: run control-openhands browser network --clear, control-openhands browser goto '/?setup_tour=first-automation', wait about 6 s, then control-openhands browser count '.oh-setup-tour-popover' and browser count 'testid=super-admin-setup-guide' are 0, browser count 'testid=home-screen' is 1, browser url still ends in ?setup_tour=first-automation, and browser network --filter setup-state reports total 0. The tour itself is blocked with the same Enterprise prerequisite as the guide.
Update tileF02.update-tileMapped behavior
Scenario F02--update-tile · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /settings/app.
- DoChoose “Agent canvas update toggle”.
- DoChoose “Agent canvas update check”.
- DoChoose “Close agent canvas update modal”.
Expect
when npm latest is newer than the running version, a New version tile (agent-canvas-version-tile) opens an update modal with the npm and Docker commands. The tile is never shown in locked-Cloud mode.
Exact CLI recipe & bug checks
The tile is blocked in an up-to-date checkout or without registry access. Check with control-openhands browser count 'testid=agent-canvas-version-tile'. When the count is 1, click it; the modal has agent-canvas-update-command-npm, agent-canvas-update-command-docker and agent-canvas-update-check-button. The manual check runs either way: on /settings/app (control-openhands browser goto /settings/app; the previous bullet ends on /mcp), testid=agent-canvas-update-badge reads Up to date (or New version), control-openhands browser click 'testid=agent-canvas-update-toggle' opens agent-canvas-update-modal, and control-openhands browser click 'testid=agent-canvas-update-check-button' reports the result in agent-canvas-update-status (You're running the latest version. What's new when current). Close it with control-openhands browser click 'testid=close-agent-canvas-update-modal'.
Error toastF02.error-toastsMapped behavior
Scenario F02--error-toast · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /conversations/00000000-0000-0000-0000-000000000001.
- WaitWait for the element identified in the CLI recipe to appear.
- WaitWait for “This conversation does not exist” to disappear.
- DoChoose “App settings screen” / “Sound Notifications”.
- DoChoose “Submit”.
Expect
failed requests show a top-right error toast with the product or server message, and the toast closes by itself. Toasts stay readable in every colour theme.
Exact CLI recipe & bug checks
Run control-openhands browser goto /conversations/00000000-0000-0000-0000-000000000001 and control-openhands browser wait-text 'This conversation does not exist'. The URL becomes /conversations, and control-openhands browser screenshot --feature F02.error-toasts --name missing-conversation shows a top-right error toast. It is the only toast: control-openhands browser toasts lists just the "This conversation does not exist, or you do not have permission to access it…" text, and control-openhands browser toasts --history has no entry containing this UI does not understand. control-openhands browser wait 'text=This conversation does not exist' --state hidden passes within 30 s. Light theme: arrange control-openhands browser eval "localStorage.setItem('openhands-color-theme','light-plus')", repeat the goto, and read control-openhands browser eval "(()=>{const t=[...document.querySelectorAll('[role=status]')].find(e=>e.textContent.includes('does not exist'));return getComputedStyle(t).color+' on '+getComputedStyle(t.closest('div[style]')).backgroundColor})()": rgb(31, 31, 31) on rgb(229, 229, 229): every toast uses the theme's high-emphasis ink (--oh-contrast) on its surface (the default theme reads rgb(255, 255, 255) on rgb(49, 49, 49)). A success toast reads the same: save any change on /settings/app (for example control-openhands browser click 'testid=app-settings-screen >> text=Sound Notifications', control-openhands browser click 'testid=submit-button', then toggle it back and save again) and read the Settings saved toast the same way: rgb(31, 31, 31) on rgb(229, 229, 229). Solarized Light (solarized-light) gives rgb(0, 43, 54) on rgb(230, 223, 204) for both toasts. Restore with browser eval "localStorage.removeItem('openhands-color-theme')".
Check for errorsF02 · setup / cleanupSupport step
Scenario F02--check-for-errors · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoRun
control-openhands browser errors --app-onlyafter each group; it reportspageErrors0andappErrors0. Externalregistry.npmjs.organdcdn.simpleicons.orgfailures are sandbox noise.
Expect
Complete this support step before continuing to the next scenario.
Exact CLI recipe & bug checks
Run control-openhands browser errors --app-only after each group; it reports pageErrors 0 and appErrors 0. External registry.npmjs.org and cdn.simpleicons.org failures are sandbox noise.
RestoreF02 · setup / cleanupSupport step
Scenario F02--restore · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- SetupUse the desktop viewport.
Expect
Complete this support step before continuing to the next scenario.
Exact CLI recipe & bug checks
Leave the sidebar expanded, unpinned, with the checklist shown and expanded, at browser viewport desktop.
Existing conversations while collapsedF02.sidebar-collapseKnown failure
Scenario F02--existing-conversations-while-collapsed · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Sidebar collapse toggle”.
- DoHover over “OpenHands Logo”.
- DoChoose “Sidebar collapse toggle”.
Expect
the chevron collapses the rail to a 60 px icon rail with hover tooltips, a Settings icon and a backend icon with a status dot that opens a backend popover. The checklist is hidden while collapsed. The state survives a reload. To expand, click the chevron that appears when you hover the logo, or click empty rail space.
Known bug observations
Known failure (reproduced 2026-10-12, #15662): the count is 0, and the rail has no chooser for existing conversations; expansion is required. Restore with control-openhands browser hover 'role=link[name="OpenHands Logo"]' and control-openhands browser click 'testid=sidebar-collapse-toggle'.
Exact CLI recipe & bug checks
With at least one sidebar conversation, run control-openhands browser click 'testid=sidebar-collapse-toggle', control-openhands browser snapshot and control-openhands browser count 'testid=conversation-panel'. Known failure (reproduced 2026-10-12, #15662): the count is 0, and the rail has no chooser for existing conversations; expansion is required. Restore with control-openhands browser hover 'role=link[name="OpenHands Logo"]' and control-openhands browser click 'testid=sidebar-collapse-toggle'.
Alert bannerF02.alert-bannerBehavior contract
Scenario F02--contract-f02-alert-banner · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do
This behavior has no separately named recipe in this snapshot. Use the family’s entry points and the contract below; the page does not invent a replay.
Expect
when the server config reports maintenance, faulty models or an error message, a dismissible banner (alert-banner) appears at the top of the content area.
Settings 404 modalF02.settings-404-modalBehavior contract
Scenario F02--contract-f02-settings-404-modal · Permalink · Source
Given
Use F02’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do
This behavior has no separately named recipe in this snapshot. Use the family’s entry points and the contract below; the page does not invent a replay.
Expect
if the backend's settings return 404, the LLM settings modal opens by itself. Other settings fetch errors show a toast.
Family notes, prerequisites for known issues & limits
- The rail animates its width for 200 ms. A
bboxtaken right after the collapse click reads an intermediate width (about 70); measure afterbrowser reload. browser urlstraight after clicking Customize can still read/customize; desktop redirects to/mcpa moment later. Usebrowser wait-url '/mcp$'./settingsredirects to/settings/agentson desktop but shows the settings menu on phone. That redirect also marks the checklist's Customize your agent item done, so visiting Settings by any route completes it. The sidebar Customize link (/customize) does not.- The pin toggles are hidden until hover (
visibleisfalse), except a pinned row's toggle, which stays visible. They exist only on the expanded rail. - The two desktop elements share the label
Sidebar navigation, and settings pages add a secondcomplementarylandmark, sorole=complementaryis ambiguous. Useaside[data-collapsed]for the desktop rail andtestid=sidebar-mobile-drawerfor the drawer. - HeroUI tooltips (the collapsed rail and checklist previews) often stay closed on the first
browser hoverafter a navigation. Hover a neighbor first, then the target, andbrowser waitfor the tooltip. Nevercountit right away. - When collapsed, the expand chevron is
opacity-0 pointer-events-noneuntil the rail is hovered. A forced click on it lands on the logo link and does nothing; hover the logo first. - With the full list open, the command-menu panel covers the viewport center, so clicking the backdrop button by selector only works after a filter shortens the list (type
secrfirst).control-openhands browser mouse-click 1300 500hits the desktop backdrop with any list length. - The new-tab path works with
browser click ... --button middleand with--modifiers Control(orMeta). The phone drawer's backdrop has no handle;browser mouse-click 350 400clicks it. - Escape closes one layer at a time (#18044): with the command menu open over the phone drawer, the first Escape closes the menu and the second closes the drawer. Focus goes back to whatever had it when the menu opened: right after
browser goto /conversationsthat is the composer (chat-inputtakes focus on load), and on/settings/appit is<body>. - Toggle sidebar at phone width flips the stored desktop state without any visible change. Expand the rail again after returning to desktop.
- Typing does not reset the command menu's selection. The active option keeps its index, cut down to the shorter list, from the last ArrowUp/ArrowDown or hover, and a pointer resting where the list opens hovers the option under it. A term with several matches can then run a later one on Enter: after two
ArrowDownpresses, typingLLM profiles(LLM profiles and Model Router) selects Model Router. Before opening the menu for an Enter check, rest the pointer withbrowser hover 'testid=command-menu-trigger', and readaria-activedescendantbefore Enter when a term matches several items. Repro candidate, not yet filed. - The command menu's LLM profiles item uses a magnifier icon (
lucide-search, the same icon as the menu's search field). - Dismissing the checklist with its X and the App settings switch write the same browser-local flag, so either one undoes the other. Clicking Join the OpenHands Slack counts as joining and opens an external tab you must close.
- Registry access depends on the sandbox. Where the browser cannot reach
registry.npmjs.org(ERR_CERT_AUTHORITY_INVALID), the update check reportsCouldn't check for updates; that is the environment, not the product. Where it can, the badge readsUp to dateand the check saysYou're running the latest version. - Adding a custom MCP server tests the connection first and refuses an unreachable one (
Could not reach the server..., orConnection failed: McpError: Connection closedforuvx mcp-server-timehere), so the all-complete recipe uses the local stdio fixture.
Before you start
Use an OpenHands checkout at the source revision, with Node 24+, installed npm dependencies, uv / uvx, and a supported Chromium browser. The verification skill is the complete setup contract.
export PATH="$PWD/.agents/skills/verify-openhands/scripts:$PATH"
export OH_VERIFY_RUN=$(control-openhands launch --new --print-run)
control-openhands doctor
control-openhands onboard --skip
# Configure a model only for a scenario that needs one:
control-openhands llm preset deepseek
# When the run is complete:
control-openhands stop
F01 walks onboarding instead of skipping it. No-model checks run before model configuration. Keep OH_VERIFY_RUN set so commands address your own run. Desktop is 1440 × 1000; phone is 390 × 844. Model-backed checks need the configured provider key and budget.
Recipes run in source order within each family and can share fixtures. The page preserves that order; “as above” is a dependency on an earlier case. Setup commands and API writes arrange state. They do not prove a UI path. Follow the family cleanup steps.
A known failure preserves the intended expectation beside the observed defect. Executable known-bug blocks use xfail for a reproduced symptom and xpass when it stops reproducing. Cloud accounts, enterprise capabilities and other unavailable prerequisites remain explicit. “Not run” is different from “blocked”.
The maintained map describes application behavior at its pinned revision. Once a fix is verified in the application version under test, remove the obsolete failure note and keep the normal expectation. Dated evidence belongs in the backfill ledger.
Read the full map index and coverage boundaries, the CLI guide, or the earlier illustrated edition. The verification approach adapts Lauren Tan’s (@poteto) pstack verification-skill generators; attribution and adaptation.