Engel’s notebook

Composer, slash commands and plan mode

F05 · 25 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.

F05 Composer, slash commands and plan mode

25 behaviors · 29 scripts & contracts · Maintained source

Entry points & prerequisites

What this family covers

The composer is the input box at the bottom of the home page and of every conversation. A user types a message (Enter sends, Shift+Enter adds a line), attaches files and images, picks the LLM profile for the running conversation, watches and compacts the context window, stops and resumes the agent, and types / for built-in commands (/btw, /model, /goal, /plan, /code) and skills. /plan hands the next message to a planning agent whose PLAN.md card can be viewed and built; Ctrl/Cmd+Enter builds it.

How a user gets here

  • Home page composer (/) and the composer of any conversation (/conversations/<id>, reached from the sidebar conversation list or by URL).
  • + (More actions, chat-plus-button) inside the composer opens the tools menu; its last item Add Files and Images opens the native file picker (upload-image-input).
  • Model pill (chat-input-llm-profile) next to +; at 320 px it moves into the vertical-dots More input actions button. On the home page it names the default profile (the one Settings → LLM marks as default); in a conversation it names the profile that conversation runs on.
  • Right side of the composer: status text with Stop/Play, context ring (context-window-meter), mic (chat-dictation-button), Send (submit-button).
  • Typing / at the start of a word opens the slash menu (slash-command-menu); /plan and /code are the only mode switches on the local backend (the Code/Plan pill is Cloud only).
  • Keyboard: Enter sends, Shift+Enter newline, Ctrl+Enter / Cmd+Enter builds a plan; Escape closes the slash menu.

Given

Preconditions:

  • Baseline state (launched, doctored, onboard --skip done) and control-openhands llm preset deepseek (profiles deepseek-flash active and deepseek-pro). Every recipe except F05.agent-profile-switch, the home draft, F05.image-only-send and F05.profile-identity needs a model. Without a DeepSeek key, QA_DUMMY_KEY=qa control-openhands llm set --profile qa-zeta --model openai/gpt-4o --api-key-env QA_DUMMY_KEY --no-validate stands in for the active profile: conversations can still be created (the agent errors at once), which is all those two bullets need, and every bullet that reads a reply is blocked.
  • F05.profile-identity needs two profiles on one model: its bullet creates qa-alpha and qa-zeta with llm set --no-validate right before it and deletes them afterwards.
  • A conversation to type into: control-openhands conversation start --prompt "Reply with only: ok" --wait --timeout 240 prints id (<id> below) and leaves the browser on /conversations/<id>.
  • Attachment fixtures: control-openhands fixture image --name qa-image and control-openhands fixture file --name qa-note.txt --content "QA attachment 7731" (both land in $OH_VERIFY_RUN/evidence/_fixtures/).
  • Desktop viewport unless a bullet says otherwise. Microphone dictation is blocked in the sandbox browser (no microphone); + > Git tools needs a conversation on a git workspace (not driven here).
Type and sendF05.send-messageMapped behavior

Scenario F05--type-and-send · Permalink · Source

Given

Use F05’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

  1. Do
    Enter “Reply with only:” in “Message”.
  2. Do
    Press Shift+Enter.
  3. Do
    Enter “ok2” in “Message”.
  4. Do
    Press Enter then --selector then testid=chat-input.
  5. Wait
    Wait for the conversation to finish.
  6. Do
    Reload the page.

Expect

Send is disabled while the field is empty; Shift+Enter inserts a newline; Enter sends, clears the field and the message persists after reload.

Exact CLI recipe & bug checks

On /conversations/<id> run control-openhands browser attr 'testid=submit-button' aria-label (Send message), control-openhands browser enabled 'testid=submit-button' (false), control-openhands browser type 'testid=chat-input' 'Reply with only:', control-openhands browser enabled 'testid=submit-button' (true), control-openhands browser press Shift+Enter, control-openhands browser type 'testid=chat-input' 'ok2' and control-openhands browser eval "document.querySelector('[data-testid=chat-input]').innerText": Reply with only:\nok2. Run control-openhands browser press Enter --selector 'testid=chat-input'; the field is empty and control-openhands browser count 'testid=stop-button' is 1 while the agent runs. Then control-openhands conversation wait <id> --fresh --timeout 180 (a fast model can finish before a separate --until running wait starts, which then times out on finished), control-openhands browser reload and control-openhands browser count 'testid=user-message >> has-text=ok2': 1; control-openhands browser text 'testid=agent-message >> nth=-1' is ok2.

Draft survives navigationF05.draft-persistenceKnown issueBlocked

Scenario F05--draft-survives-navigation · Permalink · Source

Given

Use F05’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

  1. Do
    Enter “QA draft text” in “Message”.
  2. Do
    Choose “Settings”.
  3. Do
    Go back in browser history.
  4. Do
    Reload the page.
  5. Do
    Enter “ plus fast” in “Message”.
  6. Do
    Choose “Settings”.
  7. Do
    Go back in browser history.
  8. Do
    Enter “” in “Message”.

Expect

unsent text is restored per conversation (after navigation and reload) and on the home composer.

Linked known issues

Known issue #15782 (F05.draft-persistence): Prompt disappears when a conversation is stopped. Live prerequisite: Clarify whether prompt means unsent composer text or the already-sent history message, and capture that state before sidebar Stop.

Exact CLI recipe & bug checks

Run control-openhands browser type 'testid=chat-input' 'QA draft text' and wait out the 500 ms save: control-openhands browser eval "new Promise(r=>setTimeout(()=>r(JSON.parse(localStorage.getItem('conversation-state-<id>')).draftMessage),1500))" returns QA draft text. Then control-openhands browser click 'testid=backend-selector-settings-link' --expect-url settings, control-openhands browser back and the innerText eval above: QA draft text. control-openhands browser reload restores it again. A draft typed just before leaving is flushed, not lost: control-openhands browser type 'testid=chat-input' ' plus fast' and at once control-openhands browser click 'testid=backend-selector-settings-link' --expect-url settings, control-openhands browser back: the eval reads QA draft text plus fast. The same holds for an immediate sidebar switch to another conversation and back (that other conversation's composer stays empty). Clear with control-openhands browser fill 'testid=chat-input' '' and wait a second before navigating.

Home draftF05.draft-persistenceKnown issueBlocked

Scenario F05--home-draft · Permalink · Source

Given

Use F05’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

  1. Do
    Open /.
  2. Do
    Enter “QA home draft” in “Message”.
  3. Do
    Open /settings/secrets.
  4. Do
    Open /.
  5. Do
    Use browser storage as specified in the exact recipe.
  6. Do
    Open /automations.
  7. Do
    Choose “Automations add automation”.
  8. Do
    Choose “Automations add automation create”.
  9. Wait
    Wait for “Message” to appear.
  10. Do
    Enter “Reply with only the word ok2. Do not run any tools.” in “Message”.
  11. Do
    Choose “Submit”.
  12. Do
    Choose “Sidebar conversations”.
  13. Do
    Use browser storage as specified in the exact recipe.

Expect

unsent text is restored per conversation (after navigation and reload) and on the home composer.

Linked known issues

Known issue #15782 (F05.draft-persistence): Prompt disappears when a conversation is stopped. Live prerequisite: Clarify whether prompt means unsent composer text or the already-sent history message, and capture that state before sidebar Stop.

Exact CLI recipe & bug checks

Run control-openhands browser goto /, control-openhands browser type 'testid=chat-input' 'QA home draft', control-openhands browser goto /settings/secrets, control-openhands browser goto /, then the innerText eval: QA home draft; control-openhands browser storage --session lists oh:home-prompt-draft. The automation setup page's docked composer (/automations/setup, F22) keeps no draft and never touches the Home one. With QA home draft still in the Home composer, run control-openhands browser goto /automations, control-openhands browser click 'testid=automations-add-automation', control-openhands browser click 'testid=automations-add-automation-create' --expect-url '/automations/setup' and control-openhands browser wait 'testid=chat-input': the innerText eval is empty. control-openhands browser type 'testid=chat-input' 'Reply with only the word ok2. Do not run any tools.', then control-openhands browser eval "new Promise(r=>setTimeout(()=>r(sessionStorage.getItem('oh:home-prompt-draft')),1500))" still returns QA home draft. control-openhands browser click 'testid=submit-button' --expect-url '/conversations/' and control-openhands browser click 'testid=sidebar-conversations-link' --expect-url '/conversations(\?|$)': the Home composer shows QA home draft. Clear it (fill 'testid=chat-input' '', wait a second) and repeat the setup send: New Chat is empty and browser storage --session --values has no oh:home-prompt-draft. Unsent text in the setup composer is lost when the user leaves that page (by design).

Auto-resizeF05.composer-resizeMapped behavior

Scenario F05--auto-resize · Permalink · Source

Given

Use F05’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

  1. Do
    Open /conversations/<id>.
  2. Do
    Press Shift+Enter.
  3. Do
    Enter “lineN” in “Message”.
  4. Do
    Enter “” in “Message”.
  5. Do
    Use browser drag as specified in the exact recipe.
  6. Do
    Use browser drag as specified in the exact recipe.
  7. Do
    Reload the page.

Expect

the field grows with its content and shrinks when cleared; a top-edge grip lets the user drag the height.

Exact CLI recipe & bug checks

On /conversations/<id> (control-openhands browser goto /conversations/<id>; Home draft left /) type line, then eight times control-openhands browser press Shift+Enter and control-openhands browser type 'testid=chat-input' 'lineN' (line2…line9): control-openhands browser bbox 'testid=chat-input' grows by 20 px per line, from height 20 to 180; after control-openhands browser fill 'testid=chat-input' '' it is 20. control-openhands browser count '#resize-grip' is 1. control-openhands browser drag '#resize-grip' --by 0,-200 makes the empty field 220 high and control-openhands browser drag '#resize-grip' --by 0,150 brings it to 70; after control-openhands browser reload it is 20 again (the dragged height is not kept).

Tools menu and macrosF05.plus-menuMapped behavior

Scenario F05--tools-menu-and-macros · Permalink · Source

Given

Use F05’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

  1. Do
    Choose “Chat plus”.
  2. Do
    Hover over “Macros”.
  3. Do
    Choose “Fix readme”.
  4. Do
    Enter “” in “Message”.
  5. Do
    Press Escape.

Expect

+ opens a tools menu (Macros, Show skills/hooks/agent tools, Add Files and Images; Git tools in a repository); a macro fills the composer without sending.

Exact CLI recipe & bug checks

On /conversations/<id> run control-openhands browser click 'testid=chat-plus-button' and control-openhands browser testids 'testid=tools-context-menu': macros-button, show-skills-button, show-hooks-button, show-agent-tools-button, add-files-and-images-button (no git-tools-button outside a repository). control-openhands browser hover 'testid=macros-button' shows macros-submenu with increase-test-coverage-button, fix-readme-button, auto-merge-prs-button, clean-dependencies-button. control-openhands browser click 'testid=fix-readme-button' closes the menu and fills the composer with Please look at the README and make the following improvements…; the testid=user-message count is unchanged. Clear with control-openhands browser fill 'testid=chat-input' ''. Open the menu again and control-openhands browser press Escape: browser count 'testid=tools-context-menu' is 0 and control-openhands browser eval "document.activeElement.dataset.testid" is chat-plus-button.

Show dialogsF05.plus-menuMapped behavior

Scenario F05--show-dialogs · Permalink · Source

Given

Use F05’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

  1. Do
    Choose “Chat plus”.
  2. Do
    Choose “Show hooks”.
  3. Do
    Press Escape.

Expect

+ opens a tools menu (Macros, Show skills/hooks/agent tools, Add Files and Images; Git tools in a repository); a macro fills the composer without sending.

Exact CLI recipe & bug checks

For each of show-skills-button, show-hooks-button, show-agent-tools-button: control-openhands browser click 'testid=chat-plus-button', control-openhands browser click 'testid=show-hooks-button' (etc.), control-openhands browser text 'role=dialog' (starts Available Skills, Available Hooks, Agent Tools & Metadata), then control-openhands browser press Escape and control-openhands browser count 'role=dialog': 0.

Agent profile before startF05.agent-profile-switchMapped behavior

Scenario F05--agent-profile-before-start · Permalink · Source

Given

Use F05’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

  1. Do
    Open /.
  2. Do
    Choose “Chat plus”.
  3. Do
    Hover over “Switch agent profile”.
  4. Do
    Choose “Agent profile submenu” / “Manage agent profiles”.
  5. Do
    Open /conversations/<id>.
  6. Do
    Choose “Chat plus”.

Expect

before a conversation starts, + > Switch agent profile lists agent profiles and links to Manage agent profiles; it is absent in a started conversation.

Exact CLI recipe & bug checks

Run control-openhands browser goto /, control-openhands browser click 'testid=chat-plus-button', control-openhands browser hover 'testid=switch-agent-profile-button' and control-openhands browser text 'testid=agent-profile-submenu': AVAILABLE PROFILES, default (checked; chat-input-agent-profile-option-default), Manage agent profiles. control-openhands browser click 'testid=agent-profile-submenu >> text=Manage agent profiles' --expect-url 'settings/agents' lands on /settings/agents. In a started conversation (control-openhands browser goto /conversations/<id>) control-openhands browser click 'testid=chat-plus-button' then control-openhands browser count 'testid=switch-agent-profile-button' is 0.

Attach a file and an imageF05.attach-filesKnown failureKnown issueBlocked

Scenario F05--attach-a-file-and-an-image · Permalink · Source

Given

Use F05’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

  1. Do
    Use browser upload as specified in the exact recipe.
  2. Do
    Choose “Upload as file”.
  3. Do
    Choose “Interactive chat box” / “Remove image”.
  4. Do
    Enter “Reply with only the content of the attached file.” in “Message”.
  5. Do
    Press Enter then --selector then testid=chat-input.
  6. Setup
    Create the disposable git repo fixture specified in the recipe.
  7. Do
    Open /.
  8. Do
    Open the fixture workspace.
  9. Do
    Choose “Workspace mode selector”.
  10. Do
    Choose “Workspace mode selector option new worktree”.
  11. Do
    Choose “Chat plus”.
  12. Do
    Provide the fixture file or pasted content using “Add files and images”.
  13. Do
    Choose “Home chat launcher” / “Submit”.

Expect

picked files show as chips and images as thumbnails (with an Upload-as-file toggle), each removable; sent files land in the workspace and are named in the message.

Known bug observations

Known failure (reproduced 2026-10-16, SDK 1.55.0, #18421): run control-openhands fixture git-repo --name qa-repo, control-openhands browser goto /, control-openhands workspace open qa-repo, control-openhands browser click 'testid=workspace-mode-selector', control-openhands browser click 'testid=workspace-mode-selector-option-new_worktree', control-openhands browser click 'testid=chat-plus-button', control-openhands browser upload-via 'testid=add-files-and-images-button' "$OH_VERIFY_RUN/evidence/_fixtures/qa-note.txt", type Reply with only the word received. Do not run any tools. and control-openhands browser click 'testid=home-chat-launcher >> testid=submit-button' --expect-url '/conversations/[^/]+$': control-openhands browser toasts --history shows HTTP request failed (422 Unprocessable Entity): {"detail":"path must be inside the conversation workspace"} and browser network --filter upload a 422 for ?path=<run>/workspace/qa-repo/qa-note.txt, while conversation status <id> reports the worktree /tmp/conversation-worktrees/<id>/qa-repo; the message is sent without the file. The same file attached inside that conversation afterwards uploads to the worktree (200). Restore with testid=workspace-mode-selector-option-local_repo.

Linked known issues

Known issue #17788 (F05.attach-files): Cloud attachment upload rejects valid runtime data when cached fields are empty strings. Live prerequisite: A Cloud sandbox whose cached runtime URL/key are blank while the fresh runtime lookup is already ready.

Known issue #16430 (F05.attach-files): File upload does not have an indication of progress. Live prerequisite: A remote or throttled real upload that stays in flight long enough to inspect progress and composer state.

Known issue #16339 (F05.attach-files): Agent not informed of file location for files uploaded via canvas in cloud. Live prerequisite: An authenticated Cloud upload sandbox and working model to inspect the delivered filename/path notification and read the uploaded file.

Known issue OpenHands/software-agent-sdk#5889 (F05.attach-files): a same-name attachment upload that fails part-way can replace the previous workspace file with partial content. Live prerequisite: an owned isolated backend with a controlled mid-upload filesystem failure (the original Linux file-size limit or an equivalent bounded child-process limit), a pre-existing target and a real Canvas overwrite. Never change resource limits on a shared runtime; a normal successful upload does not verify failure atomicity.

Exact CLI recipe & bug checks

On /conversations/<id> run control-openhands browser upload 'testid=upload-image-input' "$OH_VERIFY_RUN/evidence/_fixtures/qa-image.png" "$OH_VERIFY_RUN/evidence/_fixtures/qa-note.txt" and control-openhands browser screenshot 'testid=interactive-chat-box' --feature F05.attach-files --name attached: a qa-note.txt TXT chip and a thumbnail. control-openhands browser count 'testid=interactive-chat-box >> alt=qa-image.png' is 1. control-openhands browser click 'role=button[name="Upload as file"]' turns the image toggle into Do not upload as file (control-openhands browser attr 'role=button[name="Do not upload as file"]' aria-pressed is true); click it again to restore. The remove buttons are named: control-openhands browser snapshot 'testid=interactive-chat-box' lists button "Remove qa-note.txt" and button "Remove image". Remove the image with control-openhands browser click 'testid=interactive-chat-box >> role=button[name="Remove image"]'; the alt=qa-image.png count is 0. Then control-openhands browser type 'testid=chat-input' 'Reply with only the content of the attached file.', control-openhands browser press Enter --selector 'testid=chat-input', wait as in Type and send, and control-openhands browser text 'testid=user-message >> nth=-1': it ends NEW FILES ADDED: qa-note.txt. control-openhands conversation events <id> --kinds MessageEvent --last 3 shows the reply QA attachment 7731, and qa-note.txt sits in the conversation workspace printed by control-openhands conversation status <id>. Attachments added on Home before the conversation exists upload after it is created: with no workspace or a Local Repo workspace they land in it (browser network --filter upload shows 200). Expected: the same in New Worktree mode. Known failure (reproduced 2026-10-16, SDK 1.55.0, #18421): run control-openhands fixture git-repo --name qa-repo, control-openhands browser goto /, control-openhands workspace open qa-repo, control-openhands browser click 'testid=workspace-mode-selector', control-openhands browser click 'testid=workspace-mode-selector-option-new_worktree', control-openhands browser click 'testid=chat-plus-button', control-openhands browser upload-via 'testid=add-files-and-images-button' "$OH_VERIFY_RUN/evidence/_fixtures/qa-note.txt", type Reply with only the word received. Do not run any tools. and control-openhands browser click 'testid=home-chat-launcher >> testid=submit-button' --expect-url '/conversations/[^/]+$': control-openhands browser toasts --history shows HTTP request failed (422 Unprocessable Entity): {"detail":"path must be inside the conversation workspace"} and browser network --filter upload a 422 for ?path=<run>/workspace/qa-repo/qa-note.txt, while conversation status <id> reports the worktree /tmp/conversation-worktrees/<id>/qa-repo; the message is sent without the file. The same file attached inside that conversation afterwards uploads to the worktree (200). Restore with testid=workspace-mode-selector-option-local_repo.

sh known-bug F05.attach-files home-new-worktree

  control-openhands browser viewport desktop
  control-openhands fixture git-repo --name qa-repo
  control-openhands fixture file --name qa-note.txt --content "QA attachment 7731"
  control-openhands browser goto /
  control-openhands browser fill 'testid=chat-input' ''
  control-openhands workspace open qa-repo
  control-openhands browser click 'testid=workspace-mode-selector'
  control-openhands browser click 'testid=workspace-mode-selector-option-new_worktree'
  control-openhands assert --field text --matches 'New Worktree' -- browser text 'testid=home-git-control-bar-preview'
  control-openhands browser click 'testid=chat-plus-button'
  control-openhands browser upload-via 'testid=add-files-and-images-button' "$OH_VERIFY_RUN/evidence/_fixtures/qa-note.txt"
  control-openhands browser type 'testid=chat-input' 'Reply with only the word received. Do not run any tools.'
  control-openhands browser network --clear
  control-openhands browser click 'testid=home-chat-launcher >> testid=submit-button' --expect-url '/conversations/[^/]+$'
  control-openhands browser wait 'testid=user-message' --timeout 30000
  control-openhands browser eval "new Promise(r=>setTimeout(r,5000))"
  control-openhands browser screenshot --feature F05.attach-files --name home-new-worktree
  control-openhands assert --field recent.0.status --equals 200 --bug-shows 422 -- browser network --filter file/upload  # bug
Size limitF05.attach-size-limitMapped behavior

Scenario F05--size-limit · Permalink · Source

Given

Use F05’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

  1. Do
    Use browser upload as specified in the exact recipe.

Expect

a file over 3 MB, or a selection over 3 MB in total, is refused with an error toast.

Exact CLI recipe & bug checks

Arrange head -c 4194304 /dev/zero > "$OH_VERIFY_RUN/evidence/_fixtures/qa-big.bin" (and qa-two-a.bin, qa-two-b.bin with head -c 2097152). Run control-openhands browser upload 'testid=upload-image-input' "$OH_VERIFY_RUN/evidence/_fixtures/qa-big.bin" and control-openhands browser toasts: Error: Files exceeding 3MB are not allowed: qa-big.bin. Uploading qa-two-a.bin and qa-two-b.bin together toasts Error: Total file size would be 4.0MB, exceeding the 3MB limit. Please select fewer or smaller files. control-openhands browser count 'testid=interactive-chat-box >> text=qa-big.bin' is 0.

Image aloneF05.image-only-sendKnown issueBlocked

Scenario F05--image-alone · Permalink · Source

Given

Use F05’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

  1. Do
    Open /.
  2. Do
    Choose “Chat plus”.
  3. Do
    Provide the fixture file or pasted content using “Add files and images”.
  4. Do
    Choose “Submit”.
  5. Wait
    Wait for “User message” to appear.
  6. Wait
    Wait for “Chat message sending” to disappear.
  7. Setup
    Create the disposable image fixture specified in the recipe.

Expect

an attached image alone, with an empty field, enables Send; the sent user message shows the thumbnail and carries the picture as an embedded data URL.

Linked known issues

Known issue OpenHands/software-agent-sdk#5523 (F05.image-only-send): DeepSeek V4.1 Flash images can be sent to another fallback profile because its vision capability is not detected. Live prerequisite: A working DeepSeek V4.1 Flash vision profile and another fallback profile, with an image-bearing turn.

Exact CLI recipe & bug checks

From the home composer: control-openhands browser goto /, control-openhands browser enabled 'testid=submit-button' (false, empty field), control-openhands browser click 'testid=chat-plus-button', control-openhands browser upload-via 'testid=add-files-and-images-button' "$OH_VERIFY_RUN/evidence/_fixtures/qa-image.png", then control-openhands browser count 'testid=home-chat-launcher >> alt=qa-image.png' (1) and control-openhands browser enabled 'testid=submit-button': true while control-openhands browser eval "document.querySelector('[data-testid=chat-input]').innerText" is still empty (control-openhands browser screenshot 'testid=home-chat-launcher' --feature F05.image-only-send --name image-alone-send-enabled). Run control-openhands browser click 'testid=submit-button' --expect-url '/conversations/' and read <image-id> from control-openhands browser url. After control-openhands browser wait 'testid=user-message' and control-openhands browser wait 'testid=chat-message-sending' --state detached --timeout 5000 (the pending bubble carries testid=user-message too, so wait for its Sending... to go, not only for a bubble; the wait returns "state": "detached" at once when the indicator has already gone, the usual case on a local stack), control-openhands browser count 'testid=user-message >> testid=image-preview' is 1, and control-openhands browser count 'testid=chat-message-sending' and control-openhands browser count 'testid=chat-message-retry' are 0. Server side, control-openhands conversation events <image-id> --kinds MessageEvent --grep 'data:image/png;base64' matches the one user row (count 1; its text is a blank " ", the row carries images: 1, and the excerpt shows the "type":"image" block with image_urls), and control-openhands conversation events <image-id> --kinds MessageEvent (default --last) lists the same row with images: 1 and no excerpt. --kinds filters before --last counts, so --kinds MessageEvent --last 1 is that same row. To check that the model is handed the picture, send the image from Home together with Which two colours are the bars in this image? Answer with the colour names only. Do not run any tools. and read control-openhands conversation events <id> --kinds MessageEvent. Expect orange and blue in the agent row and --kinds ActionEvent count 0 (fixture image draws those bars).

Paste textF05.pasteMapped behavior

Scenario F05--paste-text · Permalink · Source

Given

Use F05’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

  1. Do
    Enter “QA paste text” in “Message”.
  2. Do
    Press Control+a.
  3. Do
    Press Control+c.
  4. Do
    Press Delete.
  5. Do
    Press Control+v.
  6. Do
    Provide the fixture file or pasted content using “Message”.
  7. Do
    Provide the fixture file or pasted content using “Message”.
  8. Do
    Provide the fixture file or pasted content using “Message”.
  9. Do
    Choose “Interactive chat box” / “Remove qa-note.txt”.

Expect

pasted clipboard text is inserted as plain text; pasted images and dropped files attach.

Exact CLI recipe & bug checks

Run control-openhands browser type 'testid=chat-input' 'QA paste text', control-openhands browser press Control+a, control-openhands browser press Control+c, control-openhands browser press Delete, control-openhands browser press Control+v, then control-openhands browser eval "document.querySelector('[data-testid=chat-input]').innerHTML": QA paste text, no markup. On a cleared field control-openhands browser paste 'testid=chat-input' --file "$OH_VERIFY_RUN/evidence/_fixtures/qa-image.png" attaches the image (control-openhands browser count 'testid=interactive-chat-box >> alt=qa-image.png' is 1, with an Upload as file toggle) and control-openhands browser paste 'testid=chat-input' --text 'QA pasted plain' inserts plain text (innerHTML is QA pasted plain). control-openhands browser drop-files 'testid=chat-input' "$OH_VERIFY_RUN/evidence/_fixtures/qa-note.txt" --stage over makes control-openhands browser text 'testid=interactive-chat-box' start Drop your files here; the same command without --stage drops it: a qa-note.txt TXT chip appears. Remove the chip with control-openhands browser click 'testid=interactive-chat-box >> role=button[name="Remove qa-note.txt"]' and the image as in Attach; clear the field.

Dictation failureF05.dictationBlocked

Scenario F05--dictation-failure · Permalink · Source

Given

Use F05’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

  1. Do
    Choose “Chat dictation”.

Expect

the mic button dictates into the composer; without a microphone it toasts a failure and resets.

Exact CLI recipe & bug checks

Run control-openhands browser click 'testid=chat-dictation-button' --observe '[role=status]' --observe-ms 3000: the observed toasts include Dictation failed. Check microphone access and your voice input settings. and control-openhands browser attr 'testid=chat-dictation-button' aria-label is back to Start dictation. Real dictation is blocked without a microphone.

Switch LLM profileF05.llm-profile-pickerKnown issueBlocked

Scenario F05--switch-llm-profile · Permalink · Source

Given

Use F05’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

  1. Do
    Choose “Chat input llm profile”.
  2. Do
    Choose “Chat input llm profile option deepseek pro”.
  3. Wait
    Wait for the element identified in the CLI recipe to appear.
  4. Do
    Reload the page.
  5. Do
    Choose “Chat input llm profile”.
  6. Do
    Choose “Chat input llm profile option deepseek flash”.

Expect

the model pill switches the running conversation's LLM profile; the next reply uses the new model.

Linked known issues

Known issue OpenHands/software-agent-sdk#5639 (F05.llm-profile-picker): A profile switched before the first message can be absent from token/cost statistics after its successful turn. Live prerequisite: A working model, a profile switch before the first run, and nonzero usage/cost after that turn.

Known issue #17239 (F05.llm-profile-picker): The reported model/profile picker can open above the viewport with unreachable rows. A frozen-target Local check with eight LLM profiles passed on Home at 1512x720, 1440x1000, 390x844 and 320x700, and in a genuine conversation at 1512x720 and 390x844: internal scrolling and selecting the first/last profile worked. The Cloud screenshot and real ACP multi-model picker remain unverified; they need an approved Cloud session or ACP account/adapter with a multi-row model catalogue. Local profile geometry is not proof of those branches. Run backfill-18309-settings-worker, Agent Server/SDK 1.54.0; evidence includes F05.llm-profile-picker/17239-conversation-1512x720.png and 17239-conversation-phone.png.

Exact CLI recipe & bug checks

Run control-openhands browser click 'testid=chat-input-llm-profile' and control-openhands browser text 'testid=chat-input-llm-profile-popover': AVAILABLE PROFILES, deepseek-flash / deepseek/deepseek-flash, deepseek-pro / deepseek/deepseek-v4-pro, LLM Profiles. Run control-openhands browser click 'testid=chat-input-llm-profile-option-deepseek-pro', control-openhands browser wait-text 'Switched to profile' --timeout 15000, control-openhands browser text 'testid=chat-input-llm-profile' (deepseek-pro) and control-openhands conversation status <id> (model is deepseek/deepseek-v4-pro). Send Reply with only: pro-ok as in Type and send; the reply is pro-ok. After control-openhands browser reload the pill still reads deepseek-pro. Switch back with control-openhands browser click 'testid=chat-input-llm-profile' and control-openhands browser click 'testid=chat-input-llm-profile-option-deepseek-flash'.

Profile identityF05.profile-identityKnown issueBlocked

Scenario F05--profile-identity · Permalink · Source

Given

Use F05’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

  1. Do
    Start a conversation with the prompt “Reply with only: identity-ok”.
  2. Wait
    Wait for “Chat input llm profile” to appear.
  3. Do
    Reload the page.
  4. Do
    Open /settings/llm.
  5. Wait
    Wait for “Add llm profile” to appear.
  6. Do
    Choose the element identified in the CLI recipe.
  7. Do
    Choose “Profile actions menu” / “Profile set active”.
  8. Wait
    Wait for the element identified in the CLI recipe to appear.
  9. Do
    Open /.
  10. Do
    Open /conversations/<zeta-id>.
  11. Setup
    Arrange the prerequisite backend state through the API.
  12. Setup
    Arrange the prerequisite backend state through the API.
  13. Do
    Open /conversations/<id>.

Expect

the pill names the profile the conversation was started with, also after a reload and when another profile uses the same model; changing the default profile in Settings changes the home pill, not an existing conversation's.

Linked known issues

Known issue #16851 (F05.profile-identity): wrong model is displayed when loading existing conversation. Live prerequisite: The original conversation/model-switch history and usage record showing Opus with a Fable selector; a dummy-key conversation has no usage evidence.

Exact CLI recipe & bug checks

Arrange two profiles on one model right before this bullet: QA_DUMMY_KEY=qa control-openhands llm set --profile qa-alpha --model openai/gpt-4o --api-key-env QA_DUMMY_KEY --no-validate --no-activate and QA_DUMMY_KEY=qa control-openhands llm set --profile qa-zeta --model openai/gpt-4o --api-key-env QA_DUMMY_KEY --no-validate (qa-zeta becomes the default: control-openhands api GET /api/profiles --pick active_profile is qa-zeta). Run control-openhands conversation start --prompt "Reply with only: identity-ok" (no --wait; with the dummy key the agent errors at once, which does not matter here) and note its id as <zeta-id>. control-openhands browser wait 'testid=chat-input-llm-profile', then control-openhands browser text 'testid=chat-input-llm-profile' is qa-zeta, not the alphabetically first profile on that model. control-openhands browser reload, the wait and the text again: still qa-zeta. With a DeepSeek key, arrange both profiles on deepseek/deepseek-flash with --api-key-env DEEPSEEK_API_KEY and without --no-validate, and start with --prompt "Reply with only: identity-ok. Do not run any tools." --wait --timeout 180. Then the reply also survives the reload: control-openhands browser text 'testid=agent-message >> nth=-1' is identity-ok before and after it (driven 2026-10-08). The default agent profile still names deepseek-flash here, so the launch runs the pill's profile through agent settings (F13.llm-pill-precedence). The name is stamped on the conversation in this browser: control-openhands browser eval "JSON.parse(localStorage.getItem('openhands-agent-server-conversation-metadata'))['<zeta-id>'].active_profile" is qa-zeta. Change the default in Settings: control-openhands browser goto /settings/llm, control-openhands browser wait 'testid=add-llm-profile', control-openhands browser click '[data-testid=profile-row]:has([title="qa-alpha"]) >> testid=profile-menu-trigger', control-openhands browser click 'testid=profile-actions-menu >> testid=profile-set-active', control-openhands browser wait-text 'Switched to profile "qa-alpha"' (control-openhands api GET /api/profiles --pick active_profile is qa-alpha). The home pill follows the default: control-openhands browser goto /, the wait, and control-openhands browser text 'testid=chat-input-llm-profile' is qa-alpha; the started conversation keeps its own: control-openhands browser goto /conversations/<zeta-id>, the wait, and the text is qa-zeta (control-openhands browser screenshot 'testid=interactive-chat-box' --feature F05.profile-identity --name conversation-keeps-qa-zeta). Restore: make deepseek-flash the default again the same way (its row's profile-menu-trigger, then profile-set-active), then control-openhands api DELETE /api/profiles/qa-alpha --write and control-openhands api DELETE /api/profiles/qa-zeta --write (arrange, not proof) so /model below still counts two profiles. In a model-free run make qa-zeta the default instead and delete only qa-alpha. Return with control-openhands browser goto /conversations/<id>.

Overflow menuF05.overflow-menuKnown failureKnown issue

Scenario F05--overflow-menu · Permalink · Source

Given

Use F05’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

  1. Setup
    Use the narrow viewport.
  2. Do
    Choose “More input actions”.
  3. Do
    Choose “Overflow model”.
  4. Do
    Choose “Chat input llm profile option deepseek pro”.
  5. Wait
    Wait for the element identified in the CLI recipe to appear.
  6. Do
    Use browser record as specified in the exact recipe.
  7. Do
    Press Escape.
  8. Wait
    Wait for “Chat input overflow menu” to disappear.
  9. Do
    Use browser focus as specified in the exact recipe.
  10. Do
    Use browser focus as specified in the exact recipe.
  11. Do
    Use browser record as specified in the exact recipe.
  12. Setup
    Use the desktop viewport.

Expect

at very narrow widths the model pill collapses into a "More input actions" menu whose Model submenu fits the viewport and switches the profile; Escape closes the menu and returns focus to its trigger.

Known bug observations

Known failure (#18063): the submenu opens to the right of the menu, so the profile row starts at x about 270 with width 210 and the LLM Profiles link sits at y about 725, below the 700 px viewport (both insideViewport false); the profile clicks below still work because the first two rows keep a strip of about 50 px on screen (from x about 270 to the 320 px edge), while a click on the LLM Profiles link times out (browser screenshot --feature F05.overflow-menu --name model-submenu-narrow). control-openhands browser click 'testid=chat-input-llm-profile-option-deepseek-pro' and control-openhands browser wait-text 'Switched to profile' --timeout 15000 close the menu (count 0), and control-openhands conversation status <id> shows deepseek/deepseek-v4-pro. Switch back the same way: the trigger, testid=overflow-model-button, then testid=chat-input-llm-profile-option-deepseek-flash (conversation status <id> shows deepseek/deepseek-flash). Open the menu once more; a second click on the trigger closes it (aria-expanded false). Escape closes it too: record it with control-openhands browser record start --feature F05.overflow-menu --name escape-narrow, open the menu, control-openhands browser press Escape and control-openhands browser wait 'testid=chat-input-overflow-menu' --state detached --timeout 3000; browser attr 'role=button[name="More input actions"]' aria-expanded is false and control-openhands browser eval "document.activeElement.getAttribute('aria-label')" is More input actions. Repeat with focus on a menu item (control-openhands browser focus 'testid=overflow-model-button' before Escape) and with the Model submenu open (browser focus 'testid=chat-input-llm-profile-option-deepseek-flash'): the same result. control-openhands browser record stop --gif. Return with control-openhands browser viewport desktop.

Linked known issues

At narrow (320 px) the overflow menu's Model submenu opens to the right of the menu and runs off screen: each profile row starts at x about 270 with width 210 (browser bbox 'testid=chat-input-llm-profile-option-deepseek-flash', insideViewport false), so both names read deepse…. Pick profiles by test id: the click lands on the strip of about 50 px that stays on screen. Known issue: #18063 (filed from the follow-up noted in #18015; the submenu also runs past the bottom edge, so the LLM Profiles link cannot be clicked at narrow) (F05.overflow-menu).

Exact CLI recipe & bug checks

Run control-openhands browser viewport narrow and control-openhands browser snapshot 'testid=interactive-chat-box': the model pill is gone and button "More input actions" appears (at phone and 350x800 the pill stays inline). control-openhands browser click 'role=button[name="More input actions"]' --observe '[data-testid=chat-input-overflow-menu]' --observe-ms 1000: observed goes from <absent> to Model (the menu appears in the observed sequence; its delay varies from run to run, so do not assert a time) and has no later <absent>. control-openhands browser count 'testid=chat-input-overflow-menu' is 1 and control-openhands browser attr 'role=button[name="More input actions"]' aria-expanded is true. Run control-openhands browser click 'testid=overflow-model-button'; control-openhands browser text 'testid=chat-input-overflow-menu' reads Model, AVAILABLE PROFILES, deepseek-flash / deepseek/deepseek-flash, deepseek-pro / deepseek/deepseek-v4-pro, LLM Profiles. Run control-openhands browser bbox 'testid=chat-input-llm-profile-option-deepseek-flash' and control-openhands browser bbox 'role=link[name="LLM Profiles"]'. Expected: both insideViewport true. Known failure (#18063): the submenu opens to the right of the menu, so the profile row starts at x about 270 with width 210 and the LLM Profiles link sits at y about 725, below the 700 px viewport (both insideViewport false); the profile clicks below still work because the first two rows keep a strip of about 50 px on screen (from x about 270 to the 320 px edge), while a click on the LLM Profiles link times out (browser screenshot --feature F05.overflow-menu --name model-submenu-narrow). control-openhands browser click 'testid=chat-input-llm-profile-option-deepseek-pro' and control-openhands browser wait-text 'Switched to profile' --timeout 15000 close the menu (count 0), and control-openhands conversation status <id> shows deepseek/deepseek-v4-pro. Switch back the same way: the trigger, testid=overflow-model-button, then testid=chat-input-llm-profile-option-deepseek-flash (conversation status <id> shows deepseek/deepseek-flash). Open the menu once more; a second click on the trigger closes it (aria-expanded false). Escape closes it too: record it with control-openhands browser record start --feature F05.overflow-menu --name escape-narrow, open the menu, control-openhands browser press Escape and control-openhands browser wait 'testid=chat-input-overflow-menu' --state detached --timeout 3000; browser attr 'role=button[name="More input actions"]' aria-expanded is false and control-openhands browser eval "document.activeElement.getAttribute('aria-label')" is More input actions. Repeat with focus on a menu item (control-openhands browser focus 'testid=overflow-model-button' before Escape) and with the Model submenu open (browser focus 'testid=chat-input-llm-profile-option-deepseek-flash'): the same result. control-openhands browser record stop --gif. Return with control-openhands browser viewport desktop.

Context windowF05.context-window-meterKnown issueBlocked

Scenario F05--context-window · Permalink · Source

Given

Use F05’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

  1. Do
    Choose “Context window meter”.
  2. Do
    Choose “Context window meter bar”.
  3. Do
    Choose “Conversation tab files”.
  4. Do
    Choose “Context window plan usage”.
  5. Wait
    Wait for “Usage panel” to appear.
  6. Do
    Choose “Context window compact”.

Expect

the ring shows context use; its popover opens the Usage tab and compacts the context.

Linked known issues

Known issue #17621 (F05.context-window-meter): Compact context always fails after exactly 60s — client-side timeout aborts a condensation the server then completes. Live prerequisite: A real summarizing model and conversation whose condensation takes longer than 60 seconds.

Known issue #17476 (F05.context-window-meter): Planning socket stats overwrite the main conversation's context meter. Live prerequisite: A real planning sub-conversation and main conversation with distinct nonzero usage stats.

Known issue #17271 (F05.context-window-meter): New chat retains context/state from the previous conversation. Live prerequisite: A completed conversation with nonzero token usage before New Chat; a dummy-key run supplies no genuine context usage.

Known issue #17263 (F05.context-window-meter): Context meter stays pinned after a successful compaction once the condenser has its own usage entry. Live prerequisite: A real successful compaction whose condenser usage remains larger than the default agent usage.

Known issue #16835 (F05.context-window-meter): Agent Canvas sidebar shows "Cache Hit: 0" while backend correctly records nonzero cache_read_tokens. Live prerequisite: A working prompt-caching model/proxy and a real conversation reporting nonzero cache_read_tokens.

Known issue OpenHands/software-agent-sdk#4498 (F05.context-window-meter): Compaction can leave an orphaned tool call/result in the live history and make the next provider request fail. Live prerequisite: A real condensation splitting an action/result pair, followed by the next provider request.

Known issue OpenHands/software-agent-sdk#4382 (F05.context-window-meter): ACP cost can miss cache/thought usage, silently become zero, or inflate after stalled/reset cost updates. Live prerequisite: An authenticated ACP provider emitting cache/thought token usage or reset/stalled cumulative cost updates.

Known issue OpenHands/software-agent-sdk#5820 (F05.context-window-meter): manual compaction on a null/no-op condenser can return500. Verification is blocked by genuine populated usage/context metrics: idle and refused-loopback runs leave usage=null, so neither composer nor Usage panel offers Compact context. A separate direct endpoint check returned500 but is not a Canvas reproduction. Use an existing real conversation with usage and no condenser, or an authorized successful provider run; never fabricate stats to expose the action.

Exact CLI recipe & bug checks

Run control-openhands browser attr 'testid=context-window-meter' aria-label (Context window usage: 1% used (99% left)), control-openhands browser click 'testid=context-window-meter' and control-openhands browser text 'testid=context-window-meter-popover' (Context Window, the percentage, Compact context, tokens such as 11.7k / 1.0M, Usage). control-openhands browser click 'testid=context-window-meter-bar-button' (the progress bar) closes the popover and opens the Usage tab (control-openhands browser testids --filter usage lists conversation-tab-usage, usage-panel). The popover's Usage row does the same: from another tab (control-openhands browser click 'testid=conversation-tab-files'), reopen the ring, control-openhands browser click 'testid=context-window-plan-usage' and control-openhands browser wait 'testid=usage-panel' (the panel mounts a moment later; an immediate count is 0). Reopen the ring, then control-openhands browser click 'testid=context-window-compact-button' --observe '[role=status]' --observe-ms 25000: Context compaction started, then Context compacted; control-openhands conversation events <id> --kinds CondensationRequest,Condensation --last 5 lists both kinds.

Stop and resume with a queued follow-upF05.stop-resume · F05.queued-messageMapped behavior

Scenario F05--stop-and-resume-with-a-queued-follow-up · Permalink · Source

Given

Use F05’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

  1. Wait
    Wait for the conversation to finish.
  2. Wait
    Wait for “Stop” to appear.
  3. Do
    Choose “Stop”.
  4. Wait
    Wait for “Play” to appear.
  5. Do
    Choose “Play”.

Expect

Stop pauses a running agent (status Stopped, Play button); Play resumes it.

a follow-up typed while the agent runs is accepted and answered.

Exact CLI recipe & bug checks

Send Run this shell command: sleep 25 && echo slept. Then reply with only: done (type + Enter as above), control-openhands conversation wait <id> --until running --timeout 30 and control-openhands browser wait 'testid=stop-button'; control-openhands browser attr 'testid=stop-button' aria-label is Stop. While it runs, control-openhands browser enabled 'testid=submit-button' is false with an empty field; type Also reply with: queued-ok (enabled turns true) and press Enter. Run control-openhands browser click 'testid=stop-button' and control-openhands browser wait 'testid=play-button' --timeout 30000; control-openhands browser text 'testid=interactive-chat-box' ends Stopped, control-openhands browser attr 'testid=play-button' aria-label is Resume the agent task and control-openhands conversation status <id> is paused. Run control-openhands browser click 'testid=play-button', wait for running then the terminal state: the last agent message is done queued-ok and testid=user-message >> has-text=queued-ok counts 1.

Slash menuF05.slash-menuMapped behavior

Scenario F05--slash-menu · Permalink · Source

Given

Use F05’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

  1. Do
    Enter “/” in “Message”.
  2. Do
    Press ArrowDown.
  3. Do
    Press Escape.
  4. Do
    Press Tab.
  5. Do
    Press Enter.

Expect

/ opens a filtered command list (built-ins and skills) with arrow, Tab/Enter and Escape handling.

Exact CLI recipe & bug checks

On a cleared composer run control-openhands browser type 'testid=chat-input' '/', control-openhands browser count 'testid=slash-command-menu >> role=option' (37 with the bundled skills) and control-openhands browser text 'testid=slash-command-menu': Commands, then /btw, /model, /goal, /plan, /code with descriptions, then skills (/agent-creator, …); no /new on the local backend. Type mo: the count drops (descriptions match too). control-openhands browser attr 'testid=slash-command-menu >> role=option >> nth=0' aria-selected is true; after control-openhands browser press ArrowDown the selected option is /plan (read it with control-openhands browser text 'testid=slash-command-menu >> [aria-selected=true]'). control-openhands browser press Escape closes the menu and keeps /mo. On /btw, control-openhands browser press Tab leaves /btw in the field; on /model (trailing space) the menu lists /model deepseek-flash and /model deepseek-pro, and control-openhands browser press Enter inserts /model deepseek-flash instead of sending.

`/model`F05.slash-modelMapped behavior

Scenario F05--model · Permalink · Source

Given

Use F05’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

  1. Do
    Press Escape.
  2. Do
    Press Enter then --selector then testid=chat-input.
  3. Do
    Choose “Model messages” / “Expand”.
  4. Do
    Choose “Toggle details for deepseek-pro”.

Expect

/model lists saved profiles; /model <name> switches profile.

Exact CLI recipe & bug checks

Type /model deepseek-pro, control-openhands browser press Escape (close the menu), control-openhands browser press Enter --selector 'testid=chat-input': Switched to profile appears, the pill reads deepseek-pro and conversation status <id> shows deepseek/deepseek-v4-pro. Bare /model (Escape, Enter) adds Available profiles (2) to testid=model-messages; control-openhands browser click 'testid=model-messages >> role=button[name="Expand"]' and control-openhands browser click 'role=button[name="Toggle details for deepseek-pro"]' show model: deepseek/deepseek-v4-pro, base_url: —, api_key: set. /model qa-nope (Escape, Enter) toasts Profile 'qa-nope' not found (control-openhands browser toasts) and the pill keeps deepseek-pro. Restore with /model deepseek-flash.

`/btw`F05.slash-btwKnown issueBlocked

Scenario F05--btw · Permalink · Source

Given

Use F05’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

  1. Do
    Choose “Btw messages” / “Expand”.
  2. Do
    Choose “Btw messages” / “Got it”.

Expect

/btw <question> answers a side question in a dismissible card without adding to the main stream; a bare /btw toasts that a question is needed.

Linked known issues

Known issue #17429 (F05.slash-btw): 500 error with /btw. Live prerequisite: The exact pending tool/streaming state that triggers the generator-pickle error, plus a working model for the side question.

Known issue OpenHands/software-agent-sdk#5330 (F05.slash-btw): A /btw side question can prevent reuse of the normal conversation prompt cache. Live prerequisite: A working caching provider and comparable ordinary-message versus /btw prompt/cache records.

Exact CLI recipe & bug checks

Note control-openhands conversation events <id> --kinds MessageEvent count, type /btw Reply with only: side-ok, Escape, Enter. control-openhands browser text 'testid=btw-messages' is BTW: + the question and testid=btw-spinner counts 1; after the answer the card shows Got it. control-openhands browser click 'testid=btw-messages >> role=button[name="Expand"]' reveals side-ok; control-openhands browser click 'testid=btw-messages >> role=button[name="Got it"]' removes the card (count 0). The MessageEvent count is unchanged. Bare /btw (Escape, Enter) clears the field and control-openhands browser toasts shows Please provide a question — e.g. /btw <question>; control-openhands browser count 'testid=btw-messages' stays 0.

`/goal`F05.slash-goalKnown issueBlocked

Scenario F05--goal · Permalink · Source

Given

Use F05’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

  1. Wait
    Wait for “Goal done” to appear.
  2. Do
    Choose “Goal status” / nth=-1 / “Goal stop”.
  3. Wait
    Wait for “Goal resume” to appear.
  4. Do
    Choose “Goal resume”.
  5. Do
    Reload the page.

Expect

/goal [--max N] <objective> runs a judged goal loop with a status banner, Stop and Resume; only the newest goal status offers Resume.

Linked known issues

Known issue OpenHands/software-agent-sdk#5627 (F05.slash-goal): After backend restart the goal chip can remain Running while the conversation is paused, and Stop does not clear it. Live prerequisite: A working model goal loop active during graceful backend restart, then goal-status and resume readback.

Known issue OpenHands/software-agent-sdk#5492 (F05.slash-goal): A goal can stop as Complete when its judge replies with complete as the string false. Live prerequisite: A real goal judge response containing complete as the string false rather than a JSON boolean.

Known issue OpenHands/software-agent-sdk#5824 (F05.slash-goal): resuming after a failed judge audit can show iteration 2 of a maximum of 1 and run beyond the selected goal cap. Live prerequisite: an agent/judge run whose audit fails, followed by a successful incomplete judge verdict after Resume; a controller-only test does not establish the Canvas banner outcome.

Exact CLI recipe & bug checks

Bare /goal + Enter: control-openhands browser toasts shows Please provide an objective — e.g. /goal <objective>. Send /goal --max 1 Reply with only: goal-ok: control-openhands browser text 'testid=goal-status' reads Goal: … Round 0/1 running Stop; control-openhands browser wait 'testid=goal-done' --timeout 150000, then Round 1/1 complete score 100%. Send /goal --max 2 Reply with only: goal-two and at once control-openhands browser click 'testid=goal-status >> nth=-1 >> testid=goal-stop'; control-openhands browser wait 'testid=goal-resume' and the banner reads Round 0/2 interrupted Resume. control-openhands browser click 'testid=goal-resume' sets it running; poll control-openhands browser text 'testid=goal-status >> nth=-1' until a new row ends Round 1/2 complete score 100%. The old Round 0/2 interrupted row no longer offers Resume: control-openhands browser count 'testid=goal-resume' is 0. After control-openhands browser reload, control-openhands browser count 'testid=goal-status' is 3 and the goal-resume count is still 0.

`/plan` and `/code`F05.slash-plan-codeMapped behavior

Scenario F05--plan-and-code · Permalink · Source

Given

Use F05’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

  1. Do
    Send bare /plan (Escape, Enter): control-openhands browser attr 'testid=chat-input' data-placeholder turns Let’s work on a plan; control-openhands conversation list gains a planner conversation (title null at first, <planner-id>). Bare /code turns it back to What do you want to build?. control-openhands browser count 'role=button[name="Code"]' is 0 on local (the pill is Cloud only). /plan sent while the agent runs should be refused with feedback; today it is dropped silently: the field clears, no toast, the placeholder stays What do you want to build? (fail row; use-plan-mode-interceptor.ts swallows it by design but tells the user nothing).

Expect

/plan switches to plan mode (a planner sub-conversation), /code switches back.

Exact CLI recipe & bug checks

Send bare /plan (Escape, Enter): control-openhands browser attr 'testid=chat-input' data-placeholder turns Let’s work on a plan; control-openhands conversation list gains a planner conversation (title null at first, <planner-id>). Bare /code turns it back to What do you want to build?. control-openhands browser count 'role=button[name="Code"]' is 0 on local (the pill is Cloud only). /plan sent while the agent runs should be refused with feedback; today it is dropped silently: the field clears, no toast, the placeholder stays What do you want to build? (fail row; use-plan-mode-interceptor.ts swallows it by design but tells the user nothing).

Plan cardF05.plan-previewMapped behavior

Scenario F05--plan-card · Permalink · Source

Given

Use F05’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

  1. Wait
    Wait for the conversation to finish.
  2. Wait
    Wait for the conversation to finish.
  3. Wait
    Wait for “Plan preview content” to appear.
  4. Do
    Choose “Plan preview view”.

Expect

the planner's Plan.md card shows the plan with Read more, View (Planner tab) and Build.

Exact CLI recipe & bug checks

In plan mode send Plan creating a file hello.txt containing hi. Keep the plan to three short steps., then control-openhands conversation wait <planner-id> --until running --timeout 60, control-openhands conversation wait <planner-id> --timeout 240 and control-openhands browser wait 'testid=plan-preview-content' --timeout 60000. control-openhands browser text 'testid=plan-preview-content' starts 1. OBJECTIVE and ends Read more; control-openhands browser enabled 'testid=plan-preview-build-button' is true. Use --fresh instead of the --until running wait if the planner is fast. control-openhands browser click 'testid=plan-preview-view-button' (Read more does the same) opens the Planner tab: control-openhands browser testids --filter planner lists conversation-tab-planner and planner-tab-build-button (Build ⌘↩).

Build shortcutF05.build-plan-shortcutMapped behavior

Scenario F05--build-shortcut · Permalink · Source

Given

Use F05’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

  1. Do
    Press Control+Enter.
  2. Wait
    Wait for the conversation to finish.

Expect

Ctrl/Cmd+Enter in plan mode builds the plan with the code agent.

Exact CLI recipe & bug checks

With the plan card shown and the agent idle, control-openhands browser press Control+Enter: the placeholder returns to What do you want to build?, control-openhands conversation wait <id> --until running --timeout 60 then --timeout 240 finishes, control-openhands browser text 'testid=user-message >> nth=-1' is Execute the plan based on the .agents_tmp/PLAN.md file. (the agent's reply wording varies, e.g. Executed the plan in .agents_tmp/PLAN.md), and hello.txt exists in the workspace from control-openhands conversation status <id>.

`/plan <task>` and `/code <task>`F05.slash-plan-code-taskMapped behavior

Scenario F05--plan-task-and-code-task · Permalink · Source

Given

Use F05’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

  1. Wait
    Wait for the conversation to finish.
  2. Wait
    Wait for the conversation to finish.

Expect

/code <task> switches to code mode and sends <task> to the code agent at once; /plan <task> switches to plan mode and sends <task> to the existing planner.

Exact CLI recipe & bug checks

With the agent idle, send bare /plan, then /code Reply with only: code-ok (Escape, Enter): the placeholder turns What do you want to build? at once, control-openhands conversation wait <id> --fresh --timeout 180, control-openhands browser text 'testid=user-message >> nth=-1' is Reply with only: code-ok (no /code prefix) and the last agent message is code-ok. Then send /plan Plan writing bye.txt containing bye. One step only.: the placeholder turns Let’s work on a plan, control-openhands conversation wait <planner-id> --fresh --timeout 240, control-openhands conversation events <planner-id> --kinds MessageEvent --last 100 ends with the user text Plan writing bye.txt containing bye. One step only. and a planner reply, and control-openhands conversation list still has only the two conversations (the existing planner is reused).

Build buttonF05.plan-previewMapped behavior

Scenario F05--build-button · Permalink · Source

Given

Use F05’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

  1. Do
    Choose “Plan preview build” / nth=-1.
  2. Wait
    Wait for the conversation to finish.

Expect

the planner's Plan.md card shows the plan with Read more, View (Planner tab) and Build.

Exact CLI recipe & bug checks

With the newer plan card from /plan Plan writing bye.txt containing bye. One step only. (above) shown and the agent idle, control-openhands browser click 'testid=plan-preview-build-button >> nth=-1' does the same as the shortcut: placeholder What do you want to build?, control-openhands conversation wait <id> --fresh --timeout 240, the same last user message, and bye.txt (content bye) in the workspace.

PhoneF05.phoneMapped behavior

Scenario F05--phone · Permalink · Source

Given

Use F05’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

  1. Setup
    Use the phone viewport.
  2. Setup
    Use the desktop viewport.

Expect

the composer fits a 390 px viewport with every control inline.

Exact CLI recipe & bug checks

On /conversations/<id> run control-openhands browser viewport phone, control-openhands browser bbox 'testid=interactive-chat-box' (insideViewport true, pageHorizontalOverflow false) and control-openhands browser screenshot --feature F05.phone --name composer (+, model pill, ring, mic and Send on one row). Return with control-openhands browser viewport desktop.

Home file re-pickF05.attach-filesKnown failureKnown issueBlocked

Scenario F05--home-file-re-pick · Permalink · Source

Given

Use F05’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

  1. Do
    Open /.
  2. Do
    Use browser upload as specified in the exact recipe.
  3. Do
    Choose “Remove qa-note.txt”.
  4. Do
    Reload the page.

Expect

picked files show as chips and images as thumbnails (with an Upload-as-file toggle), each removable; sent files land in the workspace and are named in the message.

Known bug observations

Known failure (reproduced 2026-10-12, #17471): the second pick is ignored and the count is 0. End with browser reload to clear the file input.

Linked known issues

Known issue #17788 (F05.attach-files): Cloud attachment upload rejects valid runtime data when cached fields are empty strings. Live prerequisite: A Cloud sandbox whose cached runtime URL/key are blank while the fresh runtime lookup is already ready.

Known issue #16430 (F05.attach-files): File upload does not have an indication of progress. Live prerequisite: A remote or throttled real upload that stays in flight long enough to inspect progress and composer state.

Known issue #16339 (F05.attach-files): Agent not informed of file location for files uploaded via canvas in cloud. Live prerequisite: An authenticated Cloud upload sandbox and working model to inspect the delivered filename/path notification and read the uploaded file.

Known issue OpenHands/software-agent-sdk#5889 (F05.attach-files): a same-name attachment upload that fails part-way can replace the previous workspace file with partial content. Live prerequisite: an owned isolated backend with a controlled mid-upload filesystem failure (the original Linux file-size limit or an equivalent bounded child-process limit), a pre-existing target and a real Canvas overwrite. Never change resource limits on a shared runtime; a normal successful upload does not verify failure atomicity.

Exact CLI recipe & bug checks

As a separate check after the conversation recipes, run control-openhands browser goto /, upload the file fixture with control-openhands browser upload 'testid=upload-image-input' "$OH_VERIFY_RUN/evidence/_fixtures/qa-note.txt", remove it with control-openhands browser click 'role=button[name="Remove qa-note.txt"]', upload that same path again, then control-openhands browser count 'role=button[name="Remove qa-note.txt"]'. Expected: 1. Known failure (reproduced 2026-10-12, #17471): the second pick is ignored and the count is 0. End with browser reload to clear the file input.

Unmatched failed-conversation profileF05.profile-identityKnown failureKnown issueBlocked

Scenario F05--unmatched-failed-conversation-profile · Permalink · Source

Given

Use F05’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

  1. Setup
    Configure or inspect the model profiles specified in the recipe.
  2. Setup
    Configure or inspect the model profiles specified in the recipe.
  3. Do
    Start with a fresh browser profile.
  4. Setup
    Configure or inspect the model profiles specified in the recipe.
  5. Setup
    Arrange the prerequisite backend state through the API.

Expect

the pill names the profile the conversation was started with, also after a reload and when another profile uses the same model; changing the default profile in Settings changes the home pill, not an existing conversation's.

Known bug observations

Known failure (reproduced 2026-10-12, #16263): once the loopback turn errors, the pill reads Select a model despite a loaded active profile and the persisted conversation model. This check covers the missing browser stamp and unmatched-model case, not successful provider output. Reactivate the original profile with control-openhands api POST /api/profiles/<original-profile>/activate --write, then delete the disposable conversation and profile afterwards.

Linked known issues

Known issue #16851 (F05.profile-identity): wrong model is displayed when loading existing conversation. Live prerequisite: The original conversation/model-switch history and usage record showing Opus with a Fable selector; a dummy-key conversation has no usage evidence.

Exact CLI recipe & bug checks

Separate disposable check: record the original active profile with control-openhands llm show, then create an empty Local conversation with a new dummy profile pointing to closed loopback http://127.0.0.1:9 (llm set --no-validate, as F06's dummy-profile precondition does); give it model openai/gpt-4o. After browser reset and onboard --skip, reopen it and send Reply with only QA. Do not run any tools.. Change the same saved profile to openai/gpt-4o-mini with llm set --no-validate, then reload and read browser text 'testid=chat-input-llm-profile' and conversation status <id>. Known failure (reproduced 2026-10-12, #16263): once the loopback turn errors, the pill reads Select a model despite a loaded active profile and the persisted conversation model. This check covers the missing browser stamp and unmatched-model case, not successful provider output. Reactivate the original profile with control-openhands api POST /api/profiles/<original-profile>/activate --write, then delete the disposable conversation and profile afterwards.

Family notes, prerequisites for known issues & limits Known failureKnown issueBlocked
  • Always export your own OH_VERIFY_RUN. launch --new repoints the shared current symlink, and another agent relying on current drove and then stopped this family's stack mid-run. If the URL jumps to a page you never opened or fetch failed appears, run control-openhands status before blaming the product.
  • conversation wait <id> right after sending returns at once with the previous finished status. Use conversation wait <id> --fresh; --until running then a terminal wait only works for turns longer than the poll interval (a Reply with only turn on deepseek-flash can finish first, and --until running then times out).
  • The slash menu stays open while you type a command; press Escape before Enter or Enter selects the highlighted option instead of sending.
  • Conversation drafts are saved 500 ms after the last keystroke and flushed on navigation and unmount, so text typed just before leaving comes back.
  • Escape closes the + tools menu (browser count 'testid=tools-context-menu' is 0) and returns focus to chat-plus-button, whether focus was on the trigger or on a menu item. A menu left open covers attachments in screenshots. Escape also closes the narrow-width "More input actions" overflow menu (browser count 'testid=chat-input-overflow-menu' is 0, the trigger's aria-expanded is false) and returns focus to the trigger, whether focus was on the trigger, on overflow-model-button or on a profile row of the open Model submenu (#18174).
  • After a client-side switch between conversations (a sidebar row, or a user-message branch in F06.branch-from-here) Send keeps the previous conversation's state (Known failure, #18202; draft fix PR #18203). Switching from an empty composer to one with a saved draft restores the text next to a disabled Send; this is a race (Send came up enabled in 1 of 7 tries), so one enabled reading does not show the bug is gone. Switching from a composer with text to an empty one leaves Send enabled, and clicking it does nothing. Typing or browser reload fixes it, and Enter in the field sends the restored text anyway. Read browser enabled 'testid=submit-button' after a reload, or after typing.
  • Expected: a prompt that a suggestion chip (testid=chat-suggestions) or a + > Macros item writes into the composer enables Send at once. Known failure (reproduced 2026-10-09, #18202): on a new No workspace conversation, browser click 'testid=chat-suggestions >> text=Fix README' (or browser click 'testid=chat-plus-button', browser hover 'testid=macros-button', browser click 'testid=fix-readme-button') fills the field, but browser enabled 'testid=submit-button' is false (5 of 5 tries at desktop; a race at phone) until a character is typed. Both paths call setMessageToSend, which writes the text without an input event.
  • Uploaded chips and thumbnails have no test ids. Their remove buttons are named Remove <file name> (file chip) and Remove image (thumbnail), and Send, Stop and Play read Send message, Stop and Resume the agent task (#18033); select by those names, or by text/alt.
  • browser upload feeds the hidden input directly. To drive the real path, + > Add Files and Images, use control-openhands browser upload-via 'testid=add-files-and-images-button' <file>, which answers the native file chooser.
  • The home composer has no interactive-chat-box wrapper: scope its chips and thumbnails with testid=home-chat-launcher.
  • conversation events rows show a message's text and its attachment count (images: 1 for the image-only message, whose text is a blank); --grep 'data:image/png;base64' searches whole events and quotes the image content block in excerpts.
  • A user row with images: 1 proves that the image reached the Agent Server, not the model. Only the reply proves that the model saw it. On agent-server 1.53.0 and older, deepseek/* profiles drop the image before the LLM call (F05.image-only-send). An image sent with no text then leaves deepseek-flash with an empty task. On 2026-10-08 it ran env, read the run directory and other files on the host, and decoded the picture from the event store with PIL to answer. Pause such a conversation (control-openhands conversation pause <id>), and use the question-plus-image send for the model check.
  • The pill resolves the conversation's stamped profile before the user-level default, so profiles that share a model are told apart by name. The stamp lives in this browser's localStorage (openhands-agent-server-conversation-metadata), not on the server (api GET /api/conversations/<id> has no profile name): read it with browser eval, not api GET.
  • The Switched to profile notes are client-side and gone after reload; assert the pill and conversation status.
  • /plan messages go to a separate planner conversation; the browser stays on the parent /conversations/<id>, so wait on the planner id from conversation list.
  • Only the newest goal status offers Resume (#18036): once a resumed goal has posted a newer status, the old interrupted row shows no button, also after a reload. Count testid=goal-resume after the resumed goal ends; while it runs the count is 0 anyway.
  • Opening the context popover logs a 404 for /api/llm/balance on the local backend in browser errors --app-only; it does not break the popover.
  • --observe takes the verbs' selector syntax: testid= and plain CSS segments are watched by an in-page MutationObserver (observedBy mutation), while role=, text= and other engines are polled every 20 ms (poll-20ms), which misses a state shorter than that; prefer a testid= or CSS form for anything brief.
  • At narrow (320 px) the overflow menu's Model submenu opens to the right of the menu and runs off screen: each profile row starts at x about 270 with width 210 (browser bbox 'testid=chat-input-llm-profile-option-deepseek-flash', insideViewport false), so both names read deepse…. Pick profiles by test id: the click lands on the strip of about 50 px that stays on screen. Known issue: #18063 (filed from the follow-up noted in #18015; the submenu also runs past the bottom edge, so the LLM Profiles link cannot be clicked at narrow) (F05.overflow-menu).
  • Known issue #17788 (F05.attach-files): Cloud attachment upload rejects valid runtime data when cached fields are empty strings. Live prerequisite: A Cloud sandbox whose cached runtime URL/key are blank while the fresh runtime lookup is already ready.
  • Known issue #17621 (F05.context-window-meter): Compact context always fails after exactly 60s — client-side timeout aborts a condensation the server then completes. Live prerequisite: A real summarizing model and conversation whose condensation takes longer than 60 seconds.
  • Known issue #17476 (F05.context-window-meter): Planning socket stats overwrite the main conversation's context meter. Live prerequisite: A real planning sub-conversation and main conversation with distinct nonzero usage stats.
  • Known issue #17429 (F05.slash-btw): 500 error with /btw. Live prerequisite: The exact pending tool/streaming state that triggers the generator-pickle error, plus a working model for the side question.
  • Known issue #17271 (F05.context-window-meter): New chat retains context/state from the previous conversation. Live prerequisite: A completed conversation with nonzero token usage before New Chat; a dummy-key run supplies no genuine context usage.
  • Known issue #17263 (F05.context-window-meter): Context meter stays pinned after a successful compaction once the condenser has its own usage entry. Live prerequisite: A real successful compaction whose condenser usage remains larger than the default agent usage.
  • Known issue #16851 (F05.profile-identity): wrong model is displayed when loading existing conversation. Live prerequisite: The original conversation/model-switch history and usage record showing Opus with a Fable selector; a dummy-key conversation has no usage evidence.
  • Known issue #16835 (F05.context-window-meter): Agent Canvas sidebar shows "Cache Hit: 0" while backend correctly records nonzero cache_read_tokens. Live prerequisite: A working prompt-caching model/proxy and a real conversation reporting nonzero cache_read_tokens.
  • Known issue #16430 (F05.attach-files): File upload does not have an indication of progress. Live prerequisite: A remote or throttled real upload that stays in flight long enough to inspect progress and composer state.
  • Known issue #16339 (F05.attach-files): Agent not informed of file location for files uploaded via canvas in cloud. Live prerequisite: An authenticated Cloud upload sandbox and working model to inspect the delivered filename/path notification and read the uploaded file.
  • Known issue #15782 (F05.draft-persistence): Prompt disappears when a conversation is stopped. Live prerequisite: Clarify whether prompt means unsent composer text or the already-sent history message, and capture that state before sidebar Stop.
  • Known issue OpenHands/software-agent-sdk#5639 (F05.llm-profile-picker): A profile switched before the first message can be absent from token/cost statistics after its successful turn. Live prerequisite: A working model, a profile switch before the first run, and nonzero usage/cost after that turn.
  • Known issue OpenHands/software-agent-sdk#5627 (F05.slash-goal): After backend restart the goal chip can remain Running while the conversation is paused, and Stop does not clear it. Live prerequisite: A working model goal loop active during graceful backend restart, then goal-status and resume readback.
  • Known issue OpenHands/software-agent-sdk#5523 (F05.image-only-send): DeepSeek V4.1 Flash images can be sent to another fallback profile because its vision capability is not detected. Live prerequisite: A working DeepSeek V4.1 Flash vision profile and another fallback profile, with an image-bearing turn.
  • Known issue OpenHands/software-agent-sdk#5492 (F05.slash-goal): A goal can stop as Complete when its judge replies with complete as the string false. Live prerequisite: A real goal judge response containing complete as the string false rather than a JSON boolean.
  • Known issue OpenHands/software-agent-sdk#5330 (F05.slash-btw): A /btw side question can prevent reuse of the normal conversation prompt cache. Live prerequisite: A working caching provider and comparable ordinary-message versus /btw prompt/cache records.
  • Known issue OpenHands/software-agent-sdk#4498 (F05.context-window-meter): Compaction can leave an orphaned tool call/result in the live history and make the next provider request fail. Live prerequisite: A real condensation splitting an action/result pair, followed by the next provider request.
  • Known issue OpenHands/software-agent-sdk#4382 (F05.context-window-meter): ACP cost can miss cache/thought usage, silently become zero, or inflate after stalled/reset cost updates. Live prerequisite: An authenticated ACP provider emitting cache/thought token usage or reset/stalled cumulative cost updates.
  • Known issue #17239 (F05.llm-profile-picker): The reported model/profile picker can open above the viewport with unreachable rows. A frozen-target Local check with eight LLM profiles passed on Home at 1512x720, 1440x1000, 390x844 and 320x700, and in a genuine conversation at 1512x720 and 390x844: internal scrolling and selecting the first/last profile worked. The Cloud screenshot and real ACP multi-model picker remain unverified; they need an approved Cloud session or ACP account/adapter with a multi-row model catalogue. Local profile geometry is not proof of those branches. Run backfill-18309-settings-worker, Agent Server/SDK 1.54.0; evidence includes F05.llm-profile-picker/17239-conversation-1512x720.png and 17239-conversation-phone.png.
  • Known issue OpenHands/software-agent-sdk#5824 (F05.slash-goal): resuming after a failed judge audit can show iteration 2 of a maximum of 1 and run beyond the selected goal cap. Live prerequisite: an agent/judge run whose audit fails, followed by a successful incomplete judge verdict after Resume; a controller-only test does not establish the Canvas banner outcome.
  • Known issue OpenHands/software-agent-sdk#5889 (F05.attach-files): a same-name attachment upload that fails part-way can replace the previous workspace file with partial content. Live prerequisite: an owned isolated backend with a controlled mid-upload filesystem failure (the original Linux file-size limit or an equivalent bounded child-process limit), a pre-existing target and a real Canvas overwrite. Never change resource limits on a shared runtime; a normal successful upload does not verify failure atomicity.
  • Known issue OpenHands/software-agent-sdk#5820 (F05.context-window-meter): manual compaction on a null/no-op condenser can return500. Verification is blocked by genuine populated usage/context metrics: idle and refused-loopback runs leave usage=null, so neither composer nor Usage panel offers Compact context. A separate direct endpoint check returned500 but is not a Canvas reproduction. Use an existing real conversation with usage and no condenser, or an authorized successful provider run; never fabricate stats to expose the action.

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.