Operate Lexmount remote browser sessions through the browser-cli command line tool. Use when Codex or another agent needs to create, list, inspect, keep alive, or close Lexmount browser sessions; manage persistent browser contexts, pick reusable contexts, or detect locked contexts; guide authentication with auth status/export-env/login; verify installation, environment, and API connectivity with doctor; open pages, wait for selectors, URLs, load state, network idle, text, or form values, click, click indexed selector matches, type, focus, blur, clear, inspect form fields, inspect element state and geometry, set form values, check or uncheck labeled controls, dispatch common DOM events, submit forms, navigate history, read or mutate localStorage/sessionStorage and document.cookie-visible cookies, screenshot, evaluate JavaScript, inspect interactive elements, or snapshot page title, URL, HTML, and body text through the CLI; or verify Lexmount browser credentials without writing custom Playwright code.
Resources
8Install
npx skillscat add lexmount/browser-cli Install via the SkillsCat registry.
browser-cli
Use browser-cli as the primary interface for Lexmount browser automation.
Prefer CLI commands and JSON output over importing Python internals or writing
ad hoc Playwright scripts.
Setup
Check that the CLI is available:
browser-cli --helpIf it is not installed, install it with:
uv tool install git+https://github.com/lexmount/browser-cli.gitRequire credentials in the local shell:
export LEXMOUNT_API_KEY="<api-key>"
export LEXMOUNT_PROJECT_ID="<project-id>"Do not ask the user to paste secrets into chat. Direct the user tohttps://browser.lexmount.cn for China region credentials. The China region
defaults to https://api.lexmount.cn; set LEXMOUNT_BASE_URL only when a
non-default API endpoint is needed.
Use local auth helpers instead of handling secrets in chat:
browser-cli auth status
browser-cli auth login
browser-cli auth export-envauth export-env prints placeholders by default. With --from-current, it
still masks LEXMOUNT_API_KEY unless --reveal-secrets is explicitly used in
a trusted local terminal.
After credentials are configured, run:
browser-cli doctor --jsonRun browser-cli doctor --json before the first browser action in a thread,
after credential changes, or when a session/context/action command fails for an
unclear reason. Parse the JSON before deciding what to do:
status: "pass": continue with browser work.status: "warn": continue only when all failed checks haveseverity: "warning"and the warning does not block the requested task.status: "fail"orok: false: stop before creating sessions and follownext_steps.
Use browser-cli doctor --skip-api only for offline setup checks or when the
user explicitly asks to avoid a live API call. Do not treat a skipped API check
as proof that browser sessions will work.
Workflow
If setup is uncertain, run browser-cli auth status, then browser-cli doctor --json
before creating a session. If credentials are missing, runbrowser-cli auth login and guide the user to set local environment variables.
For a one-off task:
browser-cli session create
browser-cli action open-url --session-id <session_id> --url <url>
browser-cli action snapshot --session-id <session_id>
browser-cli action wait-selector --session-id <session_id> --selector <selector>
browser-cli session close --session-id <session_id>Use persistent contexts only when cookies, login state, or storage should
survive across sessions:
browser-cli context create
browser-cli session create --context-id <context_id> --context-mode read_write
browser-cli session create --context-metadata-json '{"purpose":"codex-login"}' --create-context-if-missing --context-mode read_writeUse read_write for login/setup work that should update cookies or storage. Useread_only when inspecting an existing logged-in state. Before deleting a context,
confirm that the task no longer needs its login state.
Parse context_reuse from the session result. Reuse only whencontext_reuse.selected is true; if candidates include locked: true, report
that a busy context was skipped. Use context status --context-id <context_id>
before reuse when the context id came from older notes.
If a command fails, parse the JSON error first. For configuration or credential
errors, stop browser work and guide the user to configure local environment
variables. For missing selectors, take a fresh snapshot or screenshot before
choosing another selector.
Write custom Playwright only when the CLI cannot express the task and explain
why the CLI was insufficient.
Always close sessions created for temporary automation unless the user asks to
keep them open. Always close temporary sessions.
Commands
Authentication:
browser-cli auth status
browser-cli auth login
browser-cli auth export-env
browser-cli auth export-env --from-current --include-base-urlDiagnostics:
browser-cli doctor
browser-cli doctor --json
browser-cli doctor --skip-apiSession lifecycle:
browser-cli session create
browser-cli session create --context-metadata-json '{"purpose":"codex-login"}' --create-context-if-missing
browser-cli session list
browser-cli session get --session-id <session_id>
browser-cli session close --session-id <session_id>
browser-cli session keepalive --session-id <session_id>Context lifecycle:
browser-cli context create
browser-cli context list
browser-cli context get --context-id <context_id>
browser-cli context status --context-id <context_id>
browser-cli context pick --metadata-json '{"purpose":"codex-login"}'
browser-cli context pick --metadata-json '{"purpose":"codex-login"}' --create-if-missing
browser-cli context delete --context-id <context_id>Browser actions:
browser-cli action open-url --session-id <session_id> --url https://example.com
browser-cli action wait-selector --session-id <session_id> --selector "main"
browser-cli action click --session-id <session_id> --selector "button"
browser-cli action type --session-id <session_id> --selector "input[name=q]" --text "query"
browser-cli action screenshot --session-id <session_id> --output /tmp/page.png
browser-cli action eval --session-id <session_id> --script "() => document.title"
browser-cli action snapshot --session-id <session_id> --max-chars 8000
browser-cli action reload --session-id <session_id>
browser-cli action go-back --session-id <session_id>
browser-cli action go-forward --session-id <session_id>
browser-cli action wait-url --session-id <session_id> --url /dashboard
browser-cli action wait-load-state --session-id <session_id> --state complete
browser-cli action wait-network-idle --session-id <session_id> --idle-ms 500
browser-cli action get-text --session-id <session_id> --selector "main"
browser-cli action exists --session-id <session_id> --selector "button"
browser-cli action count --session-id <session_id> --selector ".item"
browser-cli action wait-count --session-id <session_id> --selector ".item" --count 3 --comparison gte
browser-cli action query --session-id <session_id> --selector ".item" --max-nodes 20
browser-cli action get-attribute --session-id <session_id> --selector "a" --name href
browser-cli action wait-attribute --session-id <session_id> --selector "button" --name aria-busy --state absent
browser-cli action wait-text --session-id <session_id> --text "Ready" --selector "main"
browser-cli action focus --session-id <session_id> --selector "input[name=q]"
browser-cli action get-value --session-id <session_id> --selector "input[name=q]"
browser-cli action wait-value --session-id <session_id> --selector "input[name=q]" --value "query"
browser-cli action blur --session-id <session_id> --selector "input[name=q]"
browser-cli action storage-get --session-id <session_id> --area local --key featureFlag
browser-cli action storage-set --session-id <session_id> --area local --key seenIntro --value true
browser-cli action storage-remove --session-id <session_id> --area session --key draft
browser-cli action storage-clear --session-id <session_id> --area session --prefix temp:
browser-cli action wait-storage --session-id <session_id> --area local --key authToken
browser-cli action cookie-get --session-id <session_id> --name consent
browser-cli action cookie-set --session-id <session_id> --name consent --value yes --path /
browser-cli action cookie-delete --session-id <session_id> --name consent --path /
browser-cli action cookie-clear --session-id <session_id> --prefix tmp: --path /
browser-cli action wait-cookie --session-id <session_id> --name consent --value yes
browser-cli action clear --session-id <session_id> --selector "input[name=q]"
browser-cli action set-value --session-id <session_id> --selector "input[name=q]" --value "query"
browser-cli action dispatch-event --session-id <session_id> --selector "input[name=q]" --event input --event change
browser-cli action submit --session-id <session_id> --selector "form"
browser-cli action scroll --session-id <session_id> --y 600
browser-cli action scroll-into-view --session-id <session_id> --selector "button"
browser-cli action bounding-box --session-id <session_id> --selector "button"
browser-cli action inspect --session-id <session_id> --selector "button"
browser-cli action select-option --session-id <session_id> --selector "select" --value pro
browser-cli action select-label --session-id <session_id> --label "Plan" --option-label "Pro"
browser-cli action check --session-id <session_id> --selector "input[type=checkbox]"
browser-cli action uncheck --session-id <session_id> --selector "input[type=checkbox]"
browser-cli action check-label --session-id <session_id> --label "Remember me"
browser-cli action uncheck-label --session-id <session_id> --label "Remember me"
browser-cli action hover --session-id <session_id> --selector ".menu"
browser-cli action press --session-id <session_id> --selector "input[name=q]" --key Enter
browser-cli action click-text --session-id <session_id> --text "Submit"
browser-cli action click-role --session-id <session_id> --role button --name "Submit"
browser-cli action click-index --session-id <session_id> --selector ".item button" --index 2
browser-cli action fill-label --session-id <session_id> --label "Email" --text "me@example.com"
browser-cli action form-snapshot --session-id <session_id> --selector "form" --max-nodes 50
browser-cli action accessibility-snapshot --session-id <session_id> --max-nodes 100
browser-cli action interactive-snapshot --session-id <session_id>Prefer these built-in actions over writing custom JavaScript. reload,go-back, go-forward, wait-url, wait-load-state, wait-network-idle,get-text, exists, count, query, get-attribute, wait-count,wait-attribute, wait-text, focus, get-value, wait-value, blur,storage-get, storage-set, storage-remove, storage-clear,wait-storage, cookie-get, cookie-set, cookie-delete, cookie-clear,wait-cookie, clear, set-value, dispatch-event, submit, scroll,scroll-into-view, bounding-box, inspect, select-option, select-label,check, uncheck, check-label, uncheck-label, hover, and press plusclick-text, click-role, click-index, fill-label, form-snapshot,accessibility-snapshot, and interactive-snapshot are DOM/eval backed, so always parse their structuredresult fields such as found, exists, count, checked, selected,clicked, filled, focused, value, readable, blurred, set,removed, deleted, cleared, items, cleared_count, requested_count,state, attribute_found, requested_value, network_idle, quiet_ms,submitted, hovered, pressed, dispatched, dispatched_events, fields,value_masked, bounding_box, in_viewport, index,attributes, html_truncated, requested_option_label, option_found,option_label, requested_checked, previous_checked, changed, andnavigation_requested before assuming the page changed.
For page work, choose actions in this order:
- Inspect with
snapshot, theninteractive-snapshotwhen selectors or roles
are unclear; useform-snapshotbefore filling complex forms. - Prefer semantic actions:
click-rolefor known roles/names,click-textfor
visible text,click-indexfor a chosen repeated selector match,fill-labelfor labeled text fields,select-labelfor labeled native
selects, andcheck-labelfor labeled checkbox or switch controls. - Use selector actions when a stable selector is known:
exists,count,wait-count,query,inspect,get-attribute,wait-attribute,wait-text,get-text,wait-selector,click,type,focus,get-value,wait-value,blur,clear,set-value,dispatch-event,submit,select-option,check, anduncheck. - Use
reload,go-back,go-forward,wait-url,wait-load-state, andwait-network-idlefor navigation and async refresh flows. - Use
storage-get,storage-set,storage-remove, andstorage-clearfor
localStorage/sessionStorage state instead of writing storage JavaScript. Usewait-storageafter actions expected to create, update, or remove keys. - Use
cookie-get,cookie-set,cookie-delete, andcookie-clearfor
document.cookie-visible cookies. Usewait-cookieafter consent/login flows;
do not expect HttpOnly cookies here. - Use
scroll,scroll-into-view,bounding-box,inspect,hover,press, ordispatch-eventfor viewport, menu, keyboard, geometry, and event-triggered
UI flows. - Use
evalonly for page-local work not covered by a first-class action, and
keep the expression small. - If
result.found,result.exists,result.clicked, orresult.filledis
false, inspect again before trying a different action. For form state, parseresult.valueandresult.readablebefore deciding whether to type again.
Common task recipes:
- Fill and submit a form: run
form-snapshotorinteractive-snapshot, usefill-labelfor labeled fields andset-valuefor stable selectors,clearbefore replacement text when needed, useget-valueorwait-value
to confirm form state, useblurfor focus-driven validation, useselect-labelfor labeled selects,select-optionorcheckfor stable
selector controls, prefercheck-labelfor labeled controls, usedispatch-event --event input --event changewhen the app needs explicit
events, then usesubmit,click-role --role button --name <text>orclick-text. - Click a visible control: prefer
click-role, thenclick-text, thenscroll-into-viewand selectorclickafterexists,inspect, orbounding-box
confirms a stable selector. For repeated matches, runqueryand thenclick-index --index <n>. - Navigate page history or async refresh: use
reload,go-back, orgo-forward, then confirm withwait-url,wait-load-state,wait-network-idle,wait-text, orsnapshot. - Open menus or keyboard flows: use
focus,hoverfor menus,pressfor
shortcuts or Enter/Escape,dispatch-eventfor explicit DOM events, andblurfor focus-driven validation, then inspect again withinteractive-snapshot. - Read page results: use
wait-countfor dynamic lists,wait-attributefor
DOM state changes,get-textfor a known selector; usesnapshotwhen the
page structure or selector is unknown; usewait-textbefore reading
dynamic results. - Adjust browser state: use
storage-getfor local/session storage,storage-setfor feature flags or onboarding state, andstorage-removeorstorage-clear --prefix <prefix>for targeted cleanup; usewait-storage
when the page updates keys asynchronously. Usecookie-get,cookie-set,cookie-delete, orcookie-clearfor document.cookie-visible cookies such
as consent or non-HttpOnly flags, andwait-cookiewhen cookie changes are
async. - Debug selectors: use
count,query,inspect, andget-attributebeforeeval; useinspectforstate.disabled,state.readonly, maskedvalue,attributes, andin_viewport; usewait-countorwait-attributefor async DOM changes. - Capture final evidence: use
screenshotafter the action sequence and close
the session unless the user asks to keep it open.
Each action must use exactly one target:
--session-id <session_id>
--connect-url <cdp_websocket_url>
--direct-urlPrefer --session-id. Use --direct-url only when the user explicitly wants
the shared direct websocket path.
Output
Parse command output as JSON. Check ok first, then inspect command,error, message, and command-specific fields. Do not log revealed API keys.
Do not paste API keys, Project IDs, or full direct connect URLs into chat, docs,
commits, screenshots, or test fixtures. By default, browser direct URLs are
masked. Use reveal flags only for local debugging in a trusted shell.
Failure messages and payloads mask api_key, token-like query parameters, and
the current LEXMOUNT_API_KEY value.
If error is argument_error, read the JSON usage field and rerun a
corrected command; do not parse stderr.
For auth, report credential presence, missing variables, and next steps; do
not report API key values. For auth export-env, use placeholders or masked
commands unless the user explicitly asked to reveal secrets locally.
For doctor, inspect checks and report failed check names without revealing
API keys. When a check includes fix, use its commands, env, andguidance fields as the repair workflow.