Agent Skillsaduermael/herm › webbrowser

webbrowser

GitHub

用于网页搜索、浏览、交互、截图及用户交接。优先于HTTP处理需JS或登录态的场景。默认后台运行,仅在用户要求或需人工验证时显示。广泛研究委托子代理,小任务直接操作。

app/apple/herm/Skills/webbrowser/SKILL.md aduermael/herm

触发场景

需要进行网页搜索或浏览 需要与网站进行表单交互或登录 需要截取网页屏幕快照 需要用户手动完成认证或支付

安装

npx skills add aduermael/herm --skill webbrowser -g -y
更多选项

非标准路径

npx skills add https://github.com/aduermael/herm/tree/main/app/apple/herm/Skills/webbrowser -g -y

不安装直接使用

npx skills use aduermael/herm@webbrowser

指定 Agent (Claude Code)

npx skills add aduermael/herm --skill webbrowser -a claude-code -g -y

安装 repo 全部 skill

npx skills add aduermael/herm --all -g -y

预览 repo 内 skill

npx skills add aduermael/herm --list

SKILL.md

Frontmatter
{
    "name": "webbrowser",
    "metadata": {
        "short-description": "Native WebKit browsing and authenticated website interaction through CPSL primitives."
    },
    "description": "Use CPSL's native webbrowser module for web search, browsing, authenticated website interaction, forms, file uploads and downloads, screenshots, and user handoff."
}

Webbrowser

Use this skill when a task needs web search, page browsing, browser interaction, screenshots, or a handoff where the user needs to see or operate the browser.

Prefer webbrowser over raw HTTP when the page needs JavaScript, logged-in state, form interaction, or visual inspection.

A missing dedicated integration for a service is not a reason to stop when its website can perform the requested action. Browser sessions use persistent WebKit state and may already be signed in. When the user explicitly asks for a specific action, use the normal website flow on their behalf before reporting that it cannot be completed.

Availability

help() is the authoritative module list. When it lists webbrowser, use the global directly; do not call require or search the filesystem for browser code. If help() does not list webbrowser even though this skill is present, the host did not register the browser bridge. Report that runtime mismatch after one check instead of trying alternate imports.

Background By Default

  • Use the browser in the background by default. Do not call webbrowser.show() just because you opened, searched, clicked, typed, or inspected a page.
  • Call webbrowser.show(browser) only when the user explicitly asks to see the browser, or when the task truly requires user handoff for authentication, consent, CAPTCHA, payment, permission prompts, or subjective visual confirmation.
  • If a page can be inspected with webbrowser.page(), webbrowser.eval(), or webbrowser.screenshot() without interrupting the user, keep the browser hidden.

Sub-Agent First For Research

  • For broad web research, multi-page comparison, repeated search result triage, or anything likely to produce a lot of page text, delegate the browsing task to an agent sub-agent in explore mode.
  • Delegate broad research once. Give the helper a concrete output shape and ask it to return the best verified findings it has before its final turn; do not redo the same research in the main agent unless the helper reports a specific missing fact.
  • Keep the main conversation context focused on the user's request, the sub-agent task, and the concise result. Do not stream raw search result pages, long page dumps, or every visited URL into the main context unless the user asks for that detail.
  • Use the main agent directly only for small, targeted browsing where one or two page inspections are enough.

Webbrowser vs HTTP

  • Use webbrowser for search engines, normal websites, documentation sites, pages that need JavaScript, pages that may use cookies/login state, forms, visual inspection, screenshots, and user handoff.
  • Use http for direct API calls, JSON endpoints, known static files, webhooks, or machine-readable resources where browser rendering and cookies are unnecessary.
  • Do not use http as a replacement for browsing a site. If the user asks to search, browse, inspect, click, log in, or verify what a page shows, use webbrowser.
  • Do not use webbrowser for simple API retrieval when http can fetch the exact machine-readable endpoint more directly.

Defaults

  • webbrowser.create() and webbrowser.open() use lean resource mode by default in CPSL.
  • Lean mode avoids heavy resources such as images, media, and fonts for faster agent browsing.
  • Herm browser sessions default to a desktop-sized viewport, currently 1200px wide by default. Do not resize a browser to phone dimensions unless the user explicitly needs mobile rendering.
  • Use {resource_mode="full"} when visual resources are needed immediately.
  • Use full mode from the first navigation for heavy JavaScript apps, login flows, social sites, and any account action involving a private message, form, or file transfer. Do not switch modes by reloading after preparing a draft.
  • webbrowser.show(browser) is only for explicit user handoff. The native host should show the browser UI and promote lean pages to full mode before displaying them.
  • webbrowser.type() uses {backend="auto"} by default. Background pages remain attached to an offscreen native host. macOS uses AppKit key events. iOS uses a scene-associated window that cannot become key, temporarily sets inputmode="none", and attempts WebKit's UIKeyInput responder without activating the software keyboard. If WebKit cannot expose that responder before committing text, it falls back once to a whole-string DOM edit. Read result.typing.backendUsed, nativeAttempted, committedCharacterCount, fallbackReason, interruptionReason, and host diagnostics instead of assuming which path ran. Use {speed=4.0} if you need to be explicit.

Search And Browse

Reuse one browser for a research pass. Navigate that browser to each query or result instead of creating a browser per query; create another only when two independent login states or simultaneous pages are genuinely required. For a normal comparison, gather enough evidence in at most three sandbox invocations, then synthesize. More browsing is appropriate only when a named fact is still missing or sources conflict.

local opened = webbrowser.open("https://www.google.com/search?q=site%3Aexample.com+query")
local browser = opened.browser

local page = webbrowser.page(browser, {
  fields = {"title", "url", "text", "actions"},
})
print(page.page and page.page.text or page.text or "")

Do not add wait_resources to initial navigation as a precaution. Use webbrowser.wait_resources(browser, {resource_timeout=3}) or webbrowser.page(browser, {wait_resources=true, resource_timeout=3}) after opening when scripts, styles, images, or fetches matter.

If the response is short but references a saved JSON file, read the file from /tmp with fs.read().

Interaction

local result = webbrowser.page(browser)
local page = result.page
webbrowser.click(browser, "a1")
webbrowser.type(browser, "a2", "search terms", {speed = 4.0})
webbrowser.key_press(browser, "a2", "Enter")

Browser calls return a result wrapper. Read page state from result.page (result.page.url, result.page.actions, result.page.dialogs), not from the top-level result.

webbrowser.fill() replaces existing text. webbrowser.type() focuses and appends naturally paced text; it does not clear first. Use webbrowser.key_press(browser, action, "Enter") for Enter—never webbrowser.type(..., "\n").

key_press() accepts one exact control-key name such as Enter, Escape, Tab, Backspace, or an arrow key. Do not invent strings such as Control+Enter. On iOS the result includes result.keyPress.pageConsumed, which says whether a page handler prevented the dispatched key; verify the actual postcondition because event delivery alone does not prove submission.

For text entry, use one current textbox action and one type() or fill() call. Verify result.typing.target or result.target before an irreversible submission. Do not stack retries through custom JavaScript beforeinput, paste, execCommand, or synthetic keyboard events; reactive editors may process more than one path even when an immediate DOM check looks empty. If entry does not verify, refresh the page actions and make at most one clean retry with the current textbox handle.

For submission, inspect the returned page and draft once. If the intended state change did not occur, refresh the actions and make at most one clean retry. Do not probe modifier combinations, repeatedly submit the same form, or reload a prepared draft while searching for another submission mechanism.

Once a submission is confirmed, do not send a corrective follow-up unless the user explicitly asks. Report the actual result, including every side effect.

File Uploads

Use webbrowser.upload() when one visible action directly opens a file chooser. Pass that action and one CPSL path or an array of CPSL paths. The host arms a one-shot native file-picker handler, clicks the action, and gives WebKit the resolved on-device file URLs when the page opens its chooser.

webbrowser.upload(browser, "a4", {
  "/attachments/conversation-id/photo.jpg",
  "/home/herm/report.pdf",
})

When uploading requires multiple normal interactions—for example, opening an attachment menu and then choosing "Upload a File"—open and inspect the menu first, then call upload() on the current final menu item. This keeps chooser arming and the final click atomic, and only succeeds after WebKit asks the host for files.

local opened = webbrowser.click(browser, "a4") -- opens the site's attachment menu
local page = opened.page -- find the current Upload action here
local result = webbrowser.upload(browser, "a9", {
  "/attachments/conversation-id/photo.jpg",
})
assert(result.upload.state == "selected")

After upload.state == "selected", keep that page and draft intact until it is submitted or deliberately cancelled. Do not navigate, reload, replace the browser, or re-upload the same file while troubleshooting a later step.

Use arm_upload() only when the final chooser-opening interaction cannot be expressed as one current action. It is single-use and expires after 60 seconds. The following click() result includes result.upload.state: selected means the native chooser consumed the paths; armed means no chooser opened yet.

Typing and key results include browserHost, typing, and keyPress diagnostics. Interaction diagnostics include the non-key host and main-window identities, keyboard notification frames, and privacy-safe focus/input event metadata (event type and text lengths, never the typed text). Upload results include the chooser mode, action, timestamps, host-at-arm state, selection count, and failure state. Preserve these fields when reporting an unexpected interaction so the session trace remains useful.

Use the website's existing controls. Never unhide, relabel, restyle, or inject file inputs or proxy buttons. Do not invent host paths or use JavaScript to read local files. If normal site interaction cannot open the chooser, report the limitation instead of modifying the page to manufacture an upload target.

Call webbrowser.page() after the upload if the site needs time to render a preview, then submit or send the form normally.

If webbrowser.upload() is unavailable despite being documented, stop and report that the browser runtime is out of sync. Do not work around it by reading a binary file into JavaScript, extracting browser credentials, or calling a site's private API.

Never extract, print, copy, or reuse authentication tokens, cookies, or other session secrets from browser storage or page JavaScript. Keep authenticated actions inside the normal browser flow; use webbrowser.show() for user handoff when that flow cannot be completed safely.

Downloads

Downloads triggered by browser links and buttons are saved under /tmp/downloads. A completed download may be returned as result.download by webbrowser.click(), and webbrowser.page() includes recent paths in page.downloads. If the site prepares a download asynchronously, inspect the page again before assuming it failed.

Use http instead when the task starts from an exact static-file URL and does not need browser cookies, JavaScript, or a button click.

For coordinate-only controls:

webbrowser.click(browser, 320, 480)
webbrowser.scroll(browser, 500, 700, 0, 600)

webbrowser.eval() returns a table. Read the JavaScript result from .value:

local title = webbrowser.eval(browser, "return document.title", {function_body=true}).value

Objects and arrays in .value are JSON strings. Decode them before reading fields:

local result = webbrowser.eval(browser, "return {x: 10, y: 20}", {function_body=true})
local point = json.decode(result.value)

Return strings, numbers, booleans, or JSON-serializable values from eval. For DOM nodes or framework objects, extract the fields you need and return a plain table/object or JSON.stringify(...).

Screenshots

Write screenshots under /tmp unless the user asks for a persistent output path. Screenshots are currently saved artifacts, not visual input to the agent. Use result.page.dialogs, page text, and page actions to inspect browser state; do not claim to have visually analyzed a saved screenshot.

webbrowser.screenshot(browser, "/tmp/page.png", {
  resource_timeout = 5,
  capture_delay = 0.3,
})

User Handoff

Do not show the browser during ordinary browsing. Show it only when the user asked to see it or when authentication, consent, CAPTCHA, payment, permission prompts, or subjective visual confirmation is required.

webbrowser.show(browser)

After the user acts, call webbrowser.page(browser) again to inspect the new page state.

After every unexpected interaction result, inspect the returned page before continuing. Treat entries in result.page.dialogs as blocking UI that must be handled or reported. Action IDs identify a specific element; if one becomes stale, get the latest page instead of guessing or substituting another control.

版本历史

  • f2da284 当前 2026-07-19 13:56

同 Skill 集合

app/apple/herm/Skills/apple-context/SKILL.md
app/apple/herm/Skills/beautiful-pdfs/SKILL.md
app/apple/herm/Skills/image-vision/SKILL.md
skills/c-bounds-safety/SKILL.md
skills/device-interaction/SKILL.md
skills/modernize-tests/SKILL.md
skills/uikit-app-modernization/SKILL.md
skills/audit-xcode-security-settings/SKILL.md
skills/swiftui-specialist/SKILL.md
skills/swiftui-whats-new-27/SKILL.md

元信息

文件数
0
版本
f2da284
Hash
a3c6ab01
收录时间
2026-07-19 13:56

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-21 14:01
浙ICP备14020137号-1 $访客地图$