Secrets
F14 · 12 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.
F14 Secrets
12 behaviors · 16 scripts & contracts · Maintained source
Entry points & prerequisites
What this family covers
Secrets are named values the agent can use during conversations. A user lists, adds, edits and deletes them under Settings → Secrets; saved values are never shown again, and every new conversation receives them as environment variables.
How a user gets here
- Sidebar settings gear (
backend-selector-settings-link), then Secrets in the settings navigation (sidebar-settings-/settings/secrets). - Direct URL
/settings/secrets. - Command menu (
Control+korMeta+k, orcommand-menu-triggerin the sidebar): search "Secrets", choose Secrets settings. - The agent itself, in a conversation: its
request_secretclient tool opens the request dialog (testid=secret-request-modal) on/conversations/<id>(F14.agent-request).
Given
Preconditions:
- Baseline state (launched, doctored,
onboard --skipdone). - No secret named
QA_TMP_SECRET,QA_AGENT_SECRET,QA_RENAMED_SECRETorQA_BACK_SECRETexists (control-openhands api GET /api/settings/secrets). F14.agent-access,F14.rename,F14.edit-valueandF14.agent-requestneed an active LLM profile (control-openhands llm preset deepseek).- No secret named
QA_REQ_SECRETorQA_REQ_CANCELexists, forF14.agent-request.
Open the listF14.listMapped behavior
Scenario F14--open-the-list · Permalink · Source
Given
Use F14’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 “Settings”.
- DoChoose “Secrets settings”.
Expect
the Secrets page lists each secret's name and description with Edit and Delete actions; the launcher-seeded OPENHANDS_AUTOMATION_API_KEY is always present.
Exact CLI recipe & bug checks
Navigate from the sidebar. Run control-openhands browser click 'testid=backend-selector-settings-link', control-openhands browser click 'testid=sidebar-settings-/settings/secrets', then control-openhands browser count 'testid=secret-item >> has-text=OPENHANDS_AUTOMATION_API_KEY'. The count is 1 and the URL is /settings/secrets.
CreateF14.createMapped behavior
Scenario F14--create · Permalink · Source
Given
Use F14’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 “Add secret”.
- DoEnter “QA_TMP_SECRET” in “Add secret form” / “Name”.
- DoEnter “dummy-value-123” in “Add secret form” / “Value”.
- DoEnter “QA dummy” in “Add secret form” / “Description”.
- DoChoose “Add secret form” / “Submit”.
- DoReload the page.
Expect
adding a secret persists it; it is listed after a reload.
Exact CLI recipe & bug checks
Run control-openhands browser click 'testid=add-secret-button', control-openhands browser fill 'testid=add-secret-form >> testid=name-input' QA_TMP_SECRET, control-openhands browser fill 'testid=add-secret-form >> testid=value-input' dummy-value-123, control-openhands browser fill 'testid=add-secret-form >> testid=description-input' 'QA dummy', control-openhands browser click 'testid=add-secret-form >> testid=submit-button', then control-openhands browser reload and control-openhands browser count 'testid=secret-item >> has-text=QA_TMP_SECRET'. The count is 1 after the reload.
Duplicate nameF14.create-validationMapped behavior
Scenario F14--duplicate-name · Permalink · Source
Given
Use F14’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 “Add secret”.
Expect
duplicate names, names that break ^[a-zA-Z][a-zA-Z0-9_]{0,63}$ and empty values are refused with a message.
Exact CLI recipe & bug checks
Run control-openhands browser click 'testid=add-secret-button', fill name-input with QA_TMP_SECRET and value-input with other as above, click testid=add-secret-form >> testid=submit-button, then control-openhands browser snapshot 'testid=add-secret-form'. The snapshot shows the paragraph Secret already exists and the form stays open. The paragraph uses the theme's danger colour (#18199): control-openhands browser eval "getComputedStyle([...document.querySelectorAll('[data-testid=add-secret-form] p')].find(e=>e.innerText==='Secret already exists')).color" is rgb(231, 106, 94) on OpenHands-Neutral and rgb(209, 52, 56) on Light+ (F16.color-theme).
Invalid nameF14.create-validationMapped behavior
Scenario F14--invalid-name · Permalink · Source
Given
Use F14’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
- DoEnter “bad name!” in “Add secret form” / “Name”.
- DoChoose “Add secret form” / “Cancel”.
Expect
duplicate names, names that break ^[a-zA-Z][a-zA-Z0-9_]{0,63}$ and empty values are refused with a message.
Exact CLI recipe & bug checks
In the same form run control-openhands browser fill 'testid=add-secret-form >> testid=name-input' 'bad name!', click submit, then control-openhands browser eval "document.querySelector('[data-testid=add-secret-form] [data-testid=name-input]').validationMessage". The value is the browser's pattern message (Please match the requested format. in Chromium) and no secret is created (api GET /api/settings/secrets). Close with control-openhands browser click 'testid=add-secret-form >> testid=cancel-button'.
Empty valueF14.create-validationMapped behavior
Scenario F14--empty-value · Permalink · Source
Given
Use F14’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 “Add secret”.
Expect
duplicate names, names that break ^[a-zA-Z][a-zA-Z0-9_]{0,63}$ and empty values are refused with a message.
Exact CLI recipe & bug checks
Run control-openhands browser click 'testid=add-secret-button', fill testid=add-secret-form >> testid=name-input with QA_EMPTY_VALUE and leave value-input empty. control-openhands browser enabled 'testid=add-secret-form >> testid=submit-button' is false, and control-openhands browser eval "document.querySelector('[data-testid=add-secret-form] [data-testid=value-input]').validationMessage" is Please fill out this field. Close with testid=add-secret-form >> testid=cancel-button; api GET /api/settings/secrets lists no QA_EMPTY_VALUE.
Edit keeps the valueF14.editKnown issue
Scenario F14--edit-keeps-the-value · Permalink · Source
Given
Use F14’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 “Secret row” / containing “QA_TMP_SECRET” / “Edit secret”.
- DoReload the page.
Expect
editing the description with the value left blank keeps the stored value; Save stays disabled until something changes.
Linked known issues
Known issue #17710: On the Cloud backend, deleting a secret reportedly adds a suffixed duplicate and leaves the original. Reproduction needs a disposable writable OpenHands Cloud account at the affected service; Local secret CRUD exercises a different transport. (F14.delete, F14.edit).
Exact CLI recipe & bug checks
Run control-openhands browser click 'testid=secret-item >> has-text=QA_TMP_SECRET >> testid=edit-secret-button', control-openhands browser value 'testid=edit-secret-form >> testid=value-input' (empty) and control-openhands browser enabled 'testid=edit-secret-form >> testid=submit-button' (false). Fill testid=edit-secret-form >> testid=description-input with QA dummy edited; enabled turns true. Click testid=edit-secret-form >> testid=submit-button, control-openhands browser reload, then control-openhands browser text 'testid=secret-item >> has-text=QA_TMP_SECRET'. The row text is QA_TMP_SECRET and QA dummy edited separated by a tab ("QA_TMP_SECRET\tQA dummy edited" in the JSON output).
Delete with confirmationF14.deleteKnown issue
Scenario F14--delete-with-confirmation · Permalink · Source
Given
Use F14’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 “Secret row” / containing “QA_TMP_SECRET” / “Delete secret”.
- DoChoose “Confirmation dialog” / “Cancel”.
- DoChoose “Confirmation dialog” / “Confirm”.
- DoReload the page.
Expect
deleting asks for confirmation; Cancel keeps the row, Confirm removes it for good.
Linked known issues
Known issue #17710: On the Cloud backend, deleting a secret reportedly adds a suffixed duplicate and leaves the original. Reproduction needs a disposable writable OpenHands Cloud account at the affected service; Local secret CRUD exercises a different transport. (F14.delete, F14.edit).
Exact CLI recipe & bug checks
Run control-openhands browser click 'testid=secret-item >> has-text=QA_TMP_SECRET >> testid=delete-secret-button'; the dialog testid=confirmation-modal reads Are you sure you want to delete this key?. Run control-openhands browser click 'testid=confirmation-modal >> testid=cancel-button'; the row count stays 1. Repeat the delete click, then control-openhands browser click 'testid=confirmation-modal >> testid=confirm-button', control-openhands browser reload and control-openhands browser count 'testid=secret-item >> has-text=QA_TMP_SECRET'. The count is 0.
Agent receives the secretF14.agent-accessMapped behavior
Scenario F14--agent-receives-the-secret · Permalink · Source
Given
Use F14’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 with the prompt “Run exactly this command and reply with only its output: python3 -c "import os; print(os.environ.get('QA_AGENT_SECRET') == 'qa-dummy-4821')"”.
Expect
a conversation started after the secret was saved sees it as an environment variable.
Exact CLI recipe & bug checks
Create QA_AGENT_SECRET with value qa-dummy-4821 through the form as in Create. Run control-openhands conversation start --prompt "Run exactly this command and reply with only its output: python3 -c \"import os; print(os.environ.get('QA_AGENT_SECRET') == 'qa-dummy-4821')\"" --wait --timeout 240, then control-openhands conversation events <id> --kinds ObservationEvent. The terminal observation's text is True. Assert the observation, not the agent's reply: deepseek-flash often declines to echo anything about a secret (see Gotchas). Keep QA_AGENT_SECRET for Rename and Replace value below; they delete it.
Phone layoutF14.phoneMapped behavior
Scenario F14--phone-layout · Permalink · Source
Given
Use F14’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/secrets.
- DoStart a conversation as specified in the recipe.
- SetupUse the phone viewport.
- DoChoose “Add secret”.
- SetupUse the desktop viewport.
Expect
the page and its forms fit a 390 px viewport without horizontal overflow.
Exact CLI recipe & bug checks
Run control-openhands browser goto /settings/secrets (conversation start left the browser on the conversation), control-openhands browser viewport phone, control-openhands browser bbox 'testid=secrets-settings-screen' and control-openhands browser screenshot --feature F14.phone --name list. insideViewport is true and pageHorizontalOverflow is false; the screenshot shows the table with Edit and Delete icons. Then control-openhands browser click 'testid=add-secret-button', control-openhands browser bbox 'testid=add-secret-form' (insideViewport true, no page overflow) and control-openhands browser screenshot --feature F14.phone --name add-form; cancel the form. Return with control-openhands browser viewport desktop.
Back discards the draftF14.form-backMapped behavior
Scenario F14--back-discards-the-draft · Permalink · Source
Given
Use F14’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 “Add secret”.
- DoChoose “Back to secrets”.
Expect
the Add and Edit forms replace the list with an Add a Secret / Edit a Secret title and a Back button; Back (like Cancel) returns to the list and discards the draft.
Exact CLI recipe & bug checks
On /settings/secrets run control-openhands browser click 'testid=add-secret-button' and control-openhands browser text 'testid=secret-editor-title' (Add a Secret). Fill testid=add-secret-form >> testid=name-input with QA_BACK_SECRET and value-input with dummy, then control-openhands browser click 'testid=back-to-secrets'. control-openhands browser count 'testid=add-secret-form' is 0, the list is back (browser count 'testid=secret-item' > 0) and control-openhands api GET /api/settings/secrets lists no QA_BACK_SECRET. Reopening Add shows an empty name-input (browser value); leave with testid=back-to-secrets. The Edit form shows Edit a Secret in the same secret-editor-title.
Rename keeps the valueF14.renameMapped behavior
Scenario F14--rename-keeps-the-value · Permalink · Source
Given
Use F14’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/secrets.
- DoChoose “Secret row” / containing “QA_AGENT_SECRET” / “Edit secret”.
- DoReload the page.
- DoStart a conversation with the prompt “Run exactly this command and reply with only its output: python3 -c "import os; print(os.environ.get('QA_RENAMED_SECRET') == 'qa-dummy-4821', 'QA_AGENT_SECRET' in os.environ)"”.
Expect
the Edit form's name is editable; renaming with the value left blank keeps the stored value under the new name, and renaming onto an existing name is refused with Secret already exists.
Exact CLI recipe & bug checks
Needs QA_AGENT_SECRET from Agent receives the secret. Run control-openhands browser goto /settings/secrets, control-openhands browser click 'testid=secret-item >> has-text=QA_AGENT_SECRET >> testid=edit-secret-button', fill testid=edit-secret-form >> testid=name-input with OPENHANDS_AUTOMATION_API_KEY and click testid=edit-secret-form >> testid=submit-button: control-openhands browser snapshot 'testid=edit-secret-form' shows the paragraph Secret already exists and the form stays open. Fill name-input with QA_RENAMED_SECRET (value left blank), click submit, control-openhands browser reload; browser count 'testid=secret-item >> has-text=QA_RENAMED_SECRET' is 1, the QA_AGENT_SECRET count is 0, and api GET /api/settings/secrets lists only the new name. Then run control-openhands conversation start --prompt "Run exactly this command and reply with only its output: python3 -c \"import os; print(os.environ.get('QA_RENAMED_SECRET') == 'qa-dummy-4821', 'QA_AGENT_SECRET' in os.environ)\"" --wait --timeout 240 and control-openhands conversation events <id> --kinds ObservationEvent: the observation is True False.
Replace the valueF14.edit-valueMapped behavior
Scenario F14--replace-the-value · Permalink · Source
Given
Use F14’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/secrets.
- DoChoose “Secret row” / containing “QA_RENAMED_SECRET” / “Edit secret”.
Expect
typing a value in the Edit form (labelled "Secret Value (leave blank to preserve the existing value)") replaces the stored value for new conversations.
Exact CLI recipe & bug checks
Run control-openhands browser goto /settings/secrets, control-openhands browser click 'testid=secret-item >> has-text=QA_RENAMED_SECRET >> testid=edit-secret-button' and control-openhands browser snapshot 'testid=edit-secret-form' (the value textbox is named Secret Value (leave blank to preserve the existing value)). Fill testid=edit-secret-form >> testid=value-input with qa-dummy-7350; browser enabled 'testid=edit-secret-form >> testid=submit-button' is true. Click submit; browser count 'testid=edit-secret-form' is 0. Start a conversation with the prompt Run exactly this command and reply with only its output: python3 -c "import os; print(os.environ.get('QA_RENAMED_SECRET') == 'qa-dummy-7350')" (quoted as above) and read its ObservationEvent: True.
Agent requests a secretF14.agent-requestKnown failure
Scenario F14--agent-requests-a-secret · Permalink · Source
Given
Use F14’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 /.
- DoStart a conversation with the prompt “Call the request_secret tool with name QA_REQ_SECRET and reason 'QA check: a dummy token for verification.' Do not run any other tools. After calling it, end your turn and wait.”.
- DoPress Tab.
- DoPress Escape.
- DoUse browser mouse click as specified in the exact recipe.
- DoReload the page.
- DoEnter “qa-dummy-5190” in “Secret request modal” / “Value”.
- DoChoose “Secret request modal” / “Submit”.
- WaitWait for the conversation to finish.
- DoSend a follow-up with the prompt “Run exactly this command and reply with only its output: python3 -c "import os; print(os.environ.get('QA_REQ_SECRET') == 'qa-dummy-5190')"”.
- DoOpen /.
- DoChoose “Secret request modal” / “Cancel”.
- SetupUse the desktop viewport.
Expect
in a local conversation the agent's request_secret tool opens The agent needs a secret over the chat with its reason and the name prefilled; Add secret saves it, attaches it to the running conversation and reports saved to the agent, Cancel reports not_saved, and a name that is already saved is attached without a dialog. The value never reaches the agent's events.
Known bug observations
Known failure (reproduced 2026-10-14, #18432): at 390×844 browser bbox 'testid=secret-request-modal' is 520 px wide at x -65, insideViewport false, so the title, the field labels and Cancel are cut off on the left (and 65 px on the right); run the block below. Return with browser viewport desktop. QA_REQ_SECRET is deleted in the cleanup below.
Exact CLI recipe & bug checks
Run control-openhands browser goto /, then control-openhands conversation start --prompt "Call the request_secret tool with name QA_REQ_SECRET and reason 'QA check: a dummy token for verification.' Do not run any other tools. After calling it, end your turn and wait." --wait --timeout 240 (prints <req-id>; it leaves the browser on the conversation). control-openhands conversation events <req-id> --kinds ActionEvent,ObservationEvent shows the request_secret action and the observation Tool call dispatched to client.; control-openhands browser snapshot 'role=dialog' reads dialog "The agent needs a secret", the reason QA check: a dummy token for verification., textbox Name holding QA_REQ_SECRET, Value, Description Optional, Cancel and Add secret [disabled] (browser screenshot --feature F14.agent-request --name modal). Focus starts in name-input and Tab cycles Name, Value, Description and Cancel without leaving the dialog (control-openhands browser eval "document.activeElement.dataset.testid" after each browser press Tab). control-openhands browser press Escape and control-openhands browser mouse-click 30 500 leave it open (browser count 'testid=secret-request-modal' stays 1), and so does control-openhands browser reload, with the name still prefilled. Run control-openhands browser fill 'testid=secret-request-modal >> testid=value-input' qa-dummy-5190 and control-openhands browser click 'testid=secret-request-modal >> testid=submit-button': the dialog closes, control-openhands api GET /api/settings/secrets lists QA_REQ_SECRET, and after control-openhands conversation wait <req-id> --fresh --timeout 180 control-openhands conversation events <req-id> --kinds MessageEvent holds the user message [secret-request] {"status":"saved","name":"QA_REQ_SECRET"}, which the chat does not show (browser count 'text=[secret-request]' is 0). The running conversation now has the value: control-openhands conversation send <req-id> --prompt "Run exactly this command and reply with only its output: python3 -c \"import os; print(os.environ.get('QA_REQ_SECRET') == 'qa-dummy-5190')\"" --wait --timeout 240, then the last terminal ObservationEvent is True. Cancel: browser goto /, start a second conversation with the same prompt naming QA_REQ_CANCEL and reason QA cancel check., fill value-input with should-not-save and control-openhands browser click 'testid=secret-request-modal >> testid=cancel-button': the dialog closes, api GET /api/settings/secrets lists no QA_REQ_CANCEL, the agent receives [secret-request] {"status":"not_saved","name":"QA_REQ_CANCEL","guidance":...}, and a reload does not bring the dialog back. Already saved: a third conversation asking for QA_REQ_SECRET again shows no dialog (browser count 'testid=secret-request-modal' 0) and its events hold [secret-request] {"status":"saved","name":"QA_REQ_SECRET"}. Expected: at phone width the dialog fits the viewport (at most 90vw, 351 px at 390 px, insideViewport true) with the title, every field and both buttons visible. Known failure (reproduced 2026-10-14, #18432): at 390×844 browser bbox 'testid=secret-request-modal' is 520 px wide at x -65, insideViewport false, so the title, the field labels and Cancel are cut off on the left (and 65 px on the right); run the block below. Return with browser viewport desktop. QA_REQ_SECRET is deleted in the cleanup below.
sh known-bug F14.agent-request phone-width
control-openhands browser viewport desktop
control-openhands browser goto /
control-openhands conversation start --prompt "Call the request_secret tool with name QA_REQ_PHONE and reason 'QA phone check.' Do not run any other tools. After calling it, end your turn and wait." --wait --timeout 240
control-openhands browser wait 'testid=secret-request-modal'
control-openhands assert --field insideViewport --equals true -- browser bbox 'testid=secret-request-modal'
control-openhands browser viewport phone
control-openhands browser screenshot --feature F14.agent-request --name phone-width
control-openhands assert --field insideViewport --equals true --bug 'insideViewport eq false && box.width eq 520' -- browser bbox 'testid=secret-request-modal' # bug
control-openhands browser click 'testid=secret-request-modal >> role=button[name="Cancel"]'
control-openhands browser wait 'testid=secret-request-modal' --state detached
Escape cancels deleteF14.delete-escapeMapped behavior
Scenario F14--escape-cancels-delete · Permalink · Source
Given
Use F14’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/secrets.
- DoChoose “Secret row” / containing “QA_RENAMED_SECRET” / “Delete secret”.
- DoPress Escape.
- DoReload the page.
Expect
Escape closes the delete confirmation without deleting.
Exact CLI recipe & bug checks
Run control-openhands browser goto /settings/secrets, control-openhands browser click 'testid=secret-item >> has-text=QA_RENAMED_SECRET >> testid=delete-secret-button', control-openhands browser press Escape, then control-openhands browser count 'testid=confirmation-modal' (0) and browser count 'testid=secret-item >> has-text=QA_RENAMED_SECRET' (1). Clean up: delete QA_RENAMED_SECRET and then QA_REQ_SECRET (from F14.agent-request), each with delete-secret-button → testid=confirmation-modal >> testid=confirm-button, browser reload; api GET /api/settings/secrets lists only OPENHANDS_AUTOMATION_API_KEY.
Cipher mismatch refuses mutationF14.create · F14.edit · F14.deleteKnown failureKnown issue
Scenario F14--cipher-mismatch-refuses-mutation · Permalink · Source
Given
Use F14’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
- DoThis is an external-state fixture, not a credential test. Arrange two own dummy secrets and a dummy loopback LLM key; privately back up the run-owned
encryption-key,settings.jsonandsecrets.json. Replace only the own cipher file with a newly generated value (never display it), restart and doctor. After bootstrap, restore the old encrypted store bytes under the replacement cipher to isolate the UI write. Add a new dummy secret through the real Secrets form, and inspect only boolean preservation metadata / availability of the old dummy value privately. Independently restore the encrypted settings baseline and change Sound Notifications through Application → Save. Expected: reject writes when existing encrypted state cannot decrypt, preserving it. Known failure, reproduced 2026-10-12 (OpenHands/software-agent-sdk#5622): the secret create succeeds and rewrites an old entry while its dummy value is unavailable (getter 404, name still listed); two unrelated settings saves persist the old LLM key as null. Repeat with a fresh replacement cipher. Immediately restore the original cipher and both stores infinally, restart and doctor; original state must be readable again. This drives secret creation and settings Save, not every edit/delete permutation. Keep all cipher bytes, values and raw store snapshots private.
Expect
adding a secret persists it; it is listed after a reload.
editing the description with the value left blank keeps the stored value; Save stays disabled until something changes.
deleting asks for confirmation; Cancel keeps the row, Confirm removes it for good.
Known bug observations
Known failure, reproduced 2026-10-12 (OpenHands/software-agent-sdk#5622): the secret create succeeds and rewrites an old entry while its dummy value is unavailable (getter 404, name still listed); two unrelated settings saves persist the old LLM key as null. Repeat with a fresh replacement cipher. Immediately restore the original cipher and both stores in finally, restart and doctor; original state must be readable again. This drives secret creation and settings Save, not every edit/delete permutation. Keep all cipher bytes, values and raw store snapshots private.
Linked known issues
Known issue #17710: On the Cloud backend, deleting a secret reportedly adds a suffixed duplicate and leaves the original. Reproduction needs a disposable writable OpenHands Cloud account at the affected service; Local secret CRUD exercises a different transport. (F14.delete, F14.edit).
Exact CLI recipe & bug checks
This is an external-state fixture, not a credential test. Arrange two own dummy secrets and a dummy loopback LLM key; privately back up the run-owned encryption-key, settings.json and secrets.json. Replace only the own cipher file with a newly generated value (never display it), restart and doctor. After bootstrap, restore the old encrypted store bytes under the replacement cipher to isolate the UI write. Add a new dummy secret through the real Secrets form, and inspect only boolean preservation metadata / availability of the old dummy value privately. Independently restore the encrypted settings baseline and change Sound Notifications through Application → Save. Expected: reject writes when existing encrypted state cannot decrypt, preserving it. Known failure, reproduced 2026-10-12 (OpenHands/software-agent-sdk#5622): the secret create succeeds and rewrites an old entry while its dummy value is unavailable (getter 404, name still listed); two unrelated settings saves persist the old LLM key as null. Repeat with a fresh replacement cipher. Immediately restore the original cipher and both stores in finally, restart and doctor; original state must be readable again. This drives secret creation and settings Save, not every edit/delete permutation. Keep all cipher bytes, values and raw store snapshots private.
Family notes, prerequisites for known issues & limits Known issue
- Settings nav test ids embed the route, slashes included:
sidebar-settings-/settings/secrets. Quote the selector as written. - The value editor is a plain
textarea, not a password field: use dummy values only, and never ask the agent to print a real secret. - Edit forms intentionally show an empty value; that is not data loss.
- The invalid-name check is native browser validation. It shows a tooltip that screenshots do not capture, and it leaves any earlier
Secret already existsparagraph on screen. Assert withvalidationMessageand the API, not the paragraph. - The model is the weak link in the agent checks, not the product: asked to print a secret's length or last characters, deepseek-flash replies "I can't run that one" and runs nothing, and even for the equality check it may refuse to repeat
Truein its reply. Use the equality prompt and read the terminalObservationEvent;conversation eventstruncates message text to about 160 characters. - The conversation Overview has no Secrets entry point: its "..." menu (
conversation-overview-ellipsis) offers Workspace and Git sections only. - There is no empty state to reach safely:
secrets-emptyrenders only with zero secrets, which means deleting the launcher-seeded key (see below). - Secrets saved in Settings reach only conversations started after the save. Reuse an older conversation and the variable is missing. Only
request_secret(F14.agent-request) attaches a secret to a running conversation, and only on a local backend. request_secretis registered on every new OpenHands-agent conversation this frontend launches (not on ACP agents or older conversations) and appears in Show Agent Tools & Metadata (seeF07.agent-tools-modal). The agent learns the outcome from a hidden[secret-request] ...user message; read it withconversation events <id> --kinds MessageEvent, not from the chat.- At 390 px the name column truncates long names (
OPEN…); usebrowser texton the row rather than the screenshot to read a name. OPENHANDS_AUTOMATION_API_KEYis seeded by the launcher for automations; deleting it breaks F18/F19 runs in the same stack.- Known issue #17710: On the Cloud backend, deleting a secret reportedly adds a suffixed duplicate and leaves the original. Reproduction needs a disposable writable OpenHands Cloud account at the affected service; Local secret CRUD exercises a different transport. (
F14.delete,F14.edit).
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.