browser

GitHub

通过 agent-browser CLI 驱动真实浏览器,执行页面导航、截图、表单填写、登录流程、数据抓取及控制台/网络调试。结合 lemma-app-qa 进行系统化的应用测试、缺陷取证和发布评估,支持本地或部署的应用交互。

lemma-skills/browser/SKILL.md lemma-work/lemma-platform

Trigger Scenarios

需要操作网页或本地应用的界面交互 执行自动化 UI 测试或回归验证 进行前端页面的截图或元素抓取 处理复杂的登录流程和动态渲染页面

Install

npx skills add lemma-work/lemma-platform --skill browser -g -y
More Options

Non-standard path

npx skills add https://github.com/lemma-work/lemma-platform/tree/main/lemma-skills/browser -g -y

Use without installing

npx skills use lemma-work/lemma-platform@browser

指定 Agent (Claude Code)

npx skills add lemma-work/lemma-platform --skill browser -a claude-code -g -y

安装 repo 全部 skill

npx skills add lemma-work/lemma-platform --all -g -y

预览 repo 内 skill

npx skills add lemma-work/lemma-platform --list

SKILL.md

Frontmatter
{
    "name": "browser",
    "description": "Operate a real browser in a Lemma workspace for web pages or local\/deployed apps: navigation, screenshots, login flows, forms, scraping, console\/network inspection, and saved pages through Agent Browser. Use lemma-app-qa alongside it for systematic app journeys, defect evidence, or release judgment."
}

Browser

Drive a real, full desktop Chrome with the agent-browser CLI. Use it for anything a page renders: local dev apps, JS-heavy sites, logins, scraping, screenshots, console/network debugging.

The CLI is the whole surface. There is one browser tool, browser_sign_in, and it exists because a login is the one thing the command line must not do (below). Everything else is agent-browser through exec_command, and view_image to look at what it captures.

The Core Loop (this is law)

agent-browser open <url>         # the browser starts itself on first use
agent-browser snapshot -i        # interactive elements with @eN refs
agent-browser click @e3          # act via refs
agent-browser wait --url "**/dashboard"   # semantic wait, never bare sleeps
agent-browser snapshot -i        # ALWAYS re-snapshot after the page changes

Refs go stale the moment the page changes (navigation, submit, dialog, re-render). Acting on a stale ref is the #1 failure — re-snapshot first. Always use -i (interactive-only) to keep output small; add -u to include link URLs.

Chain with && and end on a snapshot. Each exec_command is a round trip, and the steps between two snapshots are usually not decisions — you already know you will click, wait and re-read. One command is one round trip:

agent-browser click @e3 && agent-browser wait --url "**/dashboard" && agent-browser snapshot -i

Split them only where you genuinely need to see the output before choosing the next step. && also stops at the first failure, so a click that missed does not go on to report a snapshot of the page it failed to leave.

What is different about this browser:

  • It is the person's, and there is one of it. Its session and profile are set for you: do not pass --session or --profile unless you genuinely need a second browser at the same time (see Parallel isolated sessions). Naming one by hand opens a different, empty Chrome — not the one that is signed in, and not the one the person is watching.

  • Sites stay signed in, across your run and across conversations, the way they do in the browser on their desk. If one is not, browser_sign_in asks them; you never type a password. Never save session state to a file (agent-browser state save) — it writes cookies in plaintext that outlive your run, and the browser already remembers.

  • Somebody may be watching, and may take over. If a step lands somewhere you did not expect — a page you did not navigate to, a field already filled — assume they did it, re-snapshot, and carry on from what is on screen. You do not need to wait for them.

  • The window size can change under you, because it follows whoever is watching. If the size matters for a screenshot or a recording, set it first: set-display-size <width> <height>.

  • Use $PWD whenever agent-browser writes a file. It resolves a relative path inside the browser daemon, whose working directory is whichever conversation happened to start the browser -- not yours. So screenshot ./shot.png can land in somebody else's directory, and screenshot with no path goes somewhere you will not find it.

    agent-browser screenshot "$PWD/shot.jpeg"     # lands where you are
    agent-browser pdf "$PWD/page.pdf"
    agent-browser record start "$PWD/run.webm"
    agent-browser screenshot ./shot.jpeg          # DON'T — resolved elsewhere
    

    save-webpage --out already does this for you, and a shell redirect (agent-browser get html html > page.html) is written by the shell, so it lands where you are as normal.

  • A file the page downloads goes to ~/Downloads, not your working directory -- that is Chrome's, and one browser serves every conversation. Move it if you want it beside your other output.

  • One browser serves every conversation, and it has one active tab. agent-browser tab new binds the session to the tab it opens, and every command after it acts on that binding -- so a run in another conversation that opens a tab takes the binding from you, and your next get html or screenshot is of their page. Nothing fails; you just save the wrong page. save-webpage takes a lock and is safe. Driving the CLI directly over several steps is not, so keep such a sequence short, and re-check get url before you trust what you are reading.

  • Local apps: browse http://127.0.0.1:<port>, never the public preview URL.

  • Everything is preinstalled. Never install Playwright or a browser.

Acting On Pages

agent-browser fill @e3 "user@example.com"     # clear + type
agent-browser type @e4 "extra text"           # type without clearing
agent-browser press Enter
agent-browser select @e5 "Option A"
agent-browser check @e6 / uncheck @e6
agent-browser upload @e7 ./file.pdf
agent-browser scroll down 500 ; agent-browser scrollintoview @e9
agent-browser click @e8 --new-tab

No snapshot handy? Semantic locators work without one:

agent-browser find text "Sign In" click
agent-browser find role button click --name "Submit"
agent-browser find label "Email" fill "user@test.com"

Raw CSS selectors (agent-browser click "#submit") are the last resort.

Waiting (pick the right one)

After Wait
Click that navigates wait --url "**/new-page"
Form submit wait --text "Success" or wait --url
SPA update, no URL change wait --load networkidle
Element appears dynamically wait @e3 or wait --text "..."
Custom readiness wait --fn "window.app.ready === true"
Nothing else fits wait 2000 (last resort — slow and flaky)

Reading And Extracting

agent-browser get text @e5 ; agent-browser get attr @e10 href
agent-browser get url ; agent-browser get title
agent-browser --max-output 500000 get html html > page.html   # big output needs --max-output
agent-browser screenshot "$PWD/shot.jpeg"        # viewport — what you usually want
agent-browser screenshot --full "$PWD/full.jpeg" # whole scroll: slow, and megabytes
agent-browser screenshot --annotate "$PWD/map.png"            # numbered labels keyed to @eN refs

# Arbitrary JS — heredoc avoids quote-escaping hell
cat <<'EOF' | agent-browser eval --stdin
Array.from(document.querySelectorAll("table tbody tr")).map(r => ({
  name: r.cells[0].innerText, price: r.cells[1].innerText,
}))
EOF

Open, then read. Never read <url> in one shot. Passing a URL to read does not wait for the page to render, and it fails silently — measured in this sandbox:

page read <url> open <url> then read
a React app 1 byte 1 964
an ad-funded news page 0 bytes 8 522
a static docs page 4 161 5 355

Exit code zero every time, so nothing tells you the page was empty. The core reference shipped with the CLI recommends the one-shot form; it is wrong for anything that renders client-side, which is most of what needs a browser at all. web_fetch uses the two-step form and checks the result has text in it.

A screenshot is a file until you look at it. screenshot writes to the sandbox and tells you nothing about what it captured; view_image with workspace_file_path is what puts the picture in front of you. If this agent's model cannot see images, view_image asks one that can and hands you back the description — so set instructions to the question you actually have ("is the chart's y-axis labelled?"), not "describe this".

Use it for what a snapshot cannot describe: layout, charts, broken styles, error overlays. Everything textual is cheaper through snapshot and get text. --annotate writes numbered labels keyed to the @eN refs, which is how you tell two identical-looking buttons apart. Default to .jpeg, and to the viewport. A full-page .png is several times the bytes for a photograph of a web page, and a full-page capture of a long article measured 12.4s and 7.0 MB against 2.5s and 76 KB for the viewport. Ask for --full only when the part you need is below the fold.

Save pages for later reading/citation (markdown via Readability+Turndown; pdf/jpeg/png direct):

save-webpage https://example.com/article --formats markdown,pdf --out research
save-webpage https://example.com/article --formats jpeg --full-page   # whole scroll, when you need it

Recipes

Login walls. You do not sign in. Call browser_sign_in(origin, reason) and stop there.

It opens the site and looks. If the browser is already signed in — which it often is, because the profile is durable and somebody may have signed in weeks ago in another conversation — it returns immediately and you carry on. Otherwise it puts the site in front of the person and pauses your run until they answer, however long that takes.

# Never do any of these:
#   ask the person for their password, in the conversation or on a page
#   type a password you were given, or one you found in a file or an env var
#   agent-browser auth save ... --password-stdin
#   agent-browser state save ./auth.json     # plaintext cookies on the durable disk

A password is never yours to hold. browser_sign_in is the only sanctioned path, and what it produces is the person's own browser session, held by their browser — visible to them on the connectors page, where signing out really signs the browser out.

Tabs. agent-browser tab (list), tab new <url>, tab 2, tab close 2. Refs are per-page — re-snapshot after switching.

Parallel isolated sessions. agent-browser --session user-a --profile /tmp/lemma-browser/profile-user-a open ... gives a separate browser with its own cookies, tabs and refs. Use it only when you genuinely need two at once — comparing two signed-in users, say.

Pass --profile with --session, always. A session is a whole separate Chrome and needs a profile directory of its own; Chrome locks the one it opens. --session on its own therefore exits immediately with nothing but Chrome exited early. A named session's profile is also scratch — under /tmp, gone with the sandbox — so anything you sign in to there is lost. That is deliberate: the durable profile is the default one, and a second browser is for comparing two accounts, not for keeping one.

Dialogs and iframes. agent-browser dialog accept|dismiss; iframes are auto-inlined in snapshots (refs work through them), or agent-browser frame @e3 / frame main to switch context explicitly.

Local app debugging. curl -fsS http://127.0.0.1:<port> first → agent-browser open http://127.0.0.1:<port> → reproduce → screenshot + console/network logs — don't stop at the visual failure.

Test a pod app (authenticated)

To exercise a Lemma app in the agent browser as the current agent/user, let the CLI open it authenticated instead of wiring tokens by hand:

lemma apps open support-app                          # a DEPLOYED app, by slug — resolves its served URL + injects the bearer
lemma apps open --url http://localhost:5173 --no-auth # a `npm run dev` app — it already self-authenticates via the dev token

lemma apps open <slug> seeds the current access token into the app's localStorage (the browser SDK's injectedToken mode — the only signal its auth check honours) and registers it as an Authorization: Bearer header scoped to the API origin, so cross-origin API calls authenticate too. Then it opens the app — no login UI. A local dev server (npm run dev) seeds the token itself, so pass --url <dev-url> --no-auth. From there it's the normal core loop: snapshot -i → click/fill → re-snapshot, plus screenshot to capture the rendered UI.

Then screenshot + view_image as above, to see the rendered app rather than infer it. view_image reads from either store — pass exactly one of workspace_file_path (the sandbox) or pod_file_path (the datastore); it never guesses from the path shape, and giving both or neither is an error. So an uploaded image or a rendered page from a pod document (lemma files child …/pages/page_0001.jpg) works too, and you can confirm a chart or document looks right without a browser at all. It handles images only: a PDF comes back with a pointer to pod_view_document_pages, which renders that document's pages for you and is the shorter route anyway. (App design, deploy, and test details: lemma-builder/references/apps.md.)

Troubleshooting

  • Element missing from snapshot → scroll it into view, wait for it, or dismiss the overlay covering it; then re-snapshot.
  • Click does nothing → a modal/banner is intercepting; find and dismiss it.
  • Fill ignored by custom inputs → agent-browser keyboard inserttext "text" bypasses key events.
  • "Failed to install browser network controls" / "Session with given id not found" → the daemon's CDP session is stale. agent-browser close --all, then open again; one restart is the whole fix. Do not keep re-opening, and do not reach for doctor --fix. This one matters more than it reads: installing the network controls is also what answers a proxy's auth challenge, so where a proxy is configured every request comes back 407 and no page loads — a healthy proxy looks like a dead internet.
  • CDP/connection errors or weird state → agent-browser doctor to diagnose. Do not run doctor --fix: its repairs are destructive — it purges browser state, which throws away a login browser_sign_in just restored, and reinstalls Chrome, which replaces the browser this image pins.
  • More guides ship with the CLI: agent-browser skills list, agent-browser skills get <name>; references/agent-browser-core.md has the full core reference.

See also

  • Full core reference (snapshot/ref model, every command) → references/agent-browser-core.md
  • Build and deploy a pod app → lemma-builder/references/apps.md
  • Design its product experience → the lemma-app-design skill
  • Test it systematically and judge a release → the lemma-app-qa skill
  • Operate the pod (open apps, mint file URLs) → the lemma-user skill
  • Inline live views over pod data → the lemma-widget skill

Version History

  • 4e1f360 Current 2026-09-22 02:35

    修复浏览器视图源允许列表逻辑,现基于cors_origins配置;优化代理认证处理及错误日志诊断能力。

  • 8999990 2026-09-08 20:51
  • 8b52627 2026-08-12 11:07

    重构沙箱配置,统一使用 WORKSPACE_* 环境变量替代 AGENTBOX_*,并增强沙箱镜像复用时的图像一致性校验以防止静默失败。

  • e2e8815 2026-08-02 23:38
  • 0b61713 2026-07-19 09:57

Same Skill Collection

lemma-backend/lemma-connectors/skills/integration-creator/SKILL.md
lemma-skills/lemma-artifact-author/SKILL.md
lemma-skills/lemma-builder/SKILL.md
lemma-skills/lemma-research/SKILL.md
lemma-skills/lemma-skill-creator/SKILL.md
lemma-skills/lemma-user/SKILL.md
lemma-skills/lemma-widget/SKILL.md
lemma-skills/liteparse-documents/SKILL.md
lemma-skills/lemma-app-design/SKILL.md
lemma-skills/lemma-app-qa/SKILL.md
lemma-skills/lemma-data-analysis/SKILL.md
lemma-skills/lemma-evals/SKILL.md

Metadata

Files
0
Version
731e17f
Hash
56930dc7
Indexed
2026-07-19 09:57

ホーム - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-28 07:59
浙ICP备14020137号-1