openonion/connectonion/connectonion/useful_skills/browser-workflow-skill-builder/SKILL.md
browser-workflow-skill-builder
Create robust browser automation skills for sites like LinkedIn, X/Twitter, YouTube, Stripe, or other logged-in web apps by saving page context, analyzing HTML/CSS, writing skill-local JS extract/verify scripts, and using CSS selector actions with screenshot verification.
- Source repository stars
- 1,480
- Declared platforms
- 0
- Static risk flags
- 2
- Last source update
- 2026-08-28
- Source checked
- 2026-08-28
Decision brief
What it does: where it fits
Create or improve browser automation skills for logged-in web apps. Use this when building skills that read a page, choose the correct item, generate or prepare content, click/type/upload, or submit/post/publish.
Not for
- Tasks that require unconfirmed production actions or broad system permissions.
- Environments where the pinned source and install steps cannot be inspected.
Compatibility matrix
Platform support, with evidence labels
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
Inspect first. Install second.
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/openonion/connectonion --skill "connectonion/useful_skills/browser-workflow-skill-builder"Inspect the Agent Skill "browser-workflow-skill-builder" from https://github.com/openonion/connectonion/blob/d517030cc13881ee6968b2416d3e68556a4afc69/connectonion/useful_skills/browser-workflow-skill-builder/SKILL.md at commit d517030cc13881ee6968b2416d3e68556a4afc69. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
What the source asks the agent to do
- 01
Build Workflow
1. Create or update .co/skills//SKILL.md. 2. Start with safe read-only browser analysis: - navigate to the target page - take a screenshot - run co browser savepagecontext before - inspect saved page.html, styles.css, and elements.json 3. Identify stable selectors: - Prefer sema…
Create or update .co/skills//SKILL.md.Start with safe read-only browser analysis:navigate to the target page - 02
Architecture Rule
Do not add site-specific Python to the core browser tool.
Do not add site-specific Python to the core browser tool.Use generic browser primitives — run each as co browser , positional args in order, options as --flag=value:Put site-specific selectors and DOM logic in the target skill: - 03
Discovery Protocol
Before writing automation, gather evidence from the real page:
Open the target page in the browser workflow.Take a normal viewport screenshot, not only a full-page screenshot.Save context: - 04
Selector Heuristics
Prefer selectors in this order:
aria-label with a meaningful stable phrase.role plus text or nested semantic structure.contenteditable, placeholder, name, type, data-testid. - 05
extract JS returns actionindex among all visible matching action buttons
co browser clickelementbyselector button --index= --text='' bash co browser clickelementnearselector '' button \ --targettext='' \ --containerselector='' js (args) = { const maxItems = args.maxItems || 3; // scan visible containers return { ok: true, items: [ { itemindex: 0, aut…
gototakescreenshotsavepagecontext
Permission review
Static risk signals and limitations
Runs scripts
The documentation asks the agent to run terminal commands or scripts.
For frame-aware workflows, run the same script with:Runs scripts
The documentation asks the agent to run terminal commands or scripts.
node --check .co/skills/<target-skill>/scripts/extract-items.jsWrites files
The documentation asks the agent to create, modify, or delete local files.
Good: create a real skill-local file under `.co/skills/<skill>/scripts/*.js` and call it with `script_path`.Evidence record
Why each signal appears
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 94/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 1,480 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Provenance and original SKILL.md
- Repository
- openonion/connectonion
- Skill path
- connectonion/useful_skills/browser-workflow-skill-builder/SKILL.md
- Commit
- d517030cc13881ee6968b2416d3e68556a4afc69
- License
- Apache-2.0
- Collected
- 2026-08-28
- Default branch
- main
View the original SKILL.md
Browser Workflow Skill Builder
Create or improve browser automation skills for logged-in web apps. Use this when building skills that read a page, choose the correct item, generate or prepare content, click/type/upload, or submit/post/publish.
The core pattern is: save context -> analyze DOM/CSS -> write skill-local JS extraction -> verify same item by hash -> click/type with generic browser tools -> screenshot/context verify.
Designing the command surface of a co <thing> CLI and its SKILL.md, rather than a browser workflow on top of one? That is the sibling skill cli-skill-design.
Architecture Rule
Do not add site-specific Python to the core browser tool.
Use generic browser primitives — run each as co browser <function>, positional args in order, options as --flag=value:
co browser save_page_context <name>
co browser take_screenshot
co browser run_page_script <script_path> '<args_json>'
co browser run_frame_script <script_path> '<args_json>' --frame_url_contains=<substring> --frame_name=<name>
co browser click_element_by_selector <selector> --index=<n> --text='<visible text>'
co browser type_text_by_selector <selector> '<text>' --index=<n>
co browser click_element_near_selector <anchor_selector> <target_selector> --target_text='<text>' --container_selector=<selector>
co browser upload_file_by_selector <selector> <file_path> --frame_name=<name>
co browser upload_file_after_click_by_selector <click_selector> <file_path> --text='<button text>' --frame_name=<name>
Put site-specific selectors and DOM logic in the target skill:
.co/skills/<target-skill>/
SKILL.md
scripts/
extract-<items>.js
verify-<item>.js
run_page_script(...) runs JS in the main document of the current browser page, so it shares the same browser context, login cookies, current tab, and DOM state.
run_frame_script(...) runs the same page-function script across matching frames and returns per-frame results. Use it when elements.json shows the target element has a non-main frame, when the UI is rendered through iframe/frame-like surfaces, or when main-document selectors cannot see a visible modal/composer.
Build Workflow
- Create or update
.co/skills/<target-skill>/SKILL.md. - Start with safe read-only browser analysis:
- navigate to the target page
- take a screenshot
- run
co browser save_page_context <target>_before - inspect saved
page.html,styles.css, andelements.json
- Identify stable selectors:
- Prefer semantic selectors:
aria-label,role,contenteditable,placeholder,data-testid, stable text. - Avoid generated class names unless there is no alternative.
- For repeated items, identify the container selector, body/text selector, author/title selector, and primary action selector.
- Prefer semantic selectors:
- Write
scripts/extract-<items>.js.- It must return structured JSON, not prose.
- Include normalized text, a deterministic
text_hash, action indexes, and visible bounds. - Filter ads/promoted/sidebar items in JS when possible.
- Write
scripts/verify-<item>.js.- It must accept expected author/title/text/hash from
args. - It must rescan the current DOM and return
ok: trueonly when the same item is still visible and actionable.
- It must accept expected author/title/text/hash from
- Update
SKILL.mdto make the scripts mandatory gates before clicks/submits. The targetSKILL.mdmust also include a trust-the-scripts rule: during a live run, do not read,ls, orglobthe skill's own script files, and do not runnode --checkor local tests. Live testing on 2026-06-12 showed an agent spending its first ~10 iterations reading every script before acting. Scripts are trusted by path; if one fails twice, save context and stop — fix it outside the live run. - Run a safe extraction test first: no click, no type, no submit.
- Run a full workflow only after extraction and verification are proven.
If browser setup itself fails with profile locks, closed browser context, or Playwright sync/async errors, stop and report the browser failure. Do not write fallback browser runners, do not switch to ad hoc Python/Node Playwright scripts, and do not inspect browser tool source during a target skill run.
Discovery Protocol
Before writing automation, gather evidence from the real page:
-
Open the target page in the browser workflow.
-
Take a normal viewport screenshot, not only a full-page screenshot.
-
Save context:
co browser save_page_context <site>_<workflow>_before -
Inspect
elements.jsonfirst for clickable actions, aria labels, positions, text, button order, and theframefield. -
If the target has a non-main
frameor appears in a shadow/interop surface, plan to userun_frame_script(...)and shadow-aware JS traversal. Do not assumedocument.querySelectorAll(...)from the main page can see it. -
Inspect
page.htmlfor stable DOM relationships around the target item and action button.- For frame/shadow UIs,
page.htmlmay not include the interactive internals. Treatelements.jsonplus screenshots as stronger evidence.
- For frame/shadow UIs,
-
Inspect
styles.cssonly when visibility, sticky layout, or hidden duplicate elements make DOM matching ambiguous. -
Write down the exact selector set in the target skill:
- item container selector
- item text selector
- author/title/channel selector
- action selector and action text
- editor/input selector
- submit selector and submit text
- frame name/url filter if
run_frame_script(...)is required - whether scripts must traverse open shadow roots
- upload trigger selector and file input selector if local file upload is part of the workflow
- whether the editor is plain text or a rich text editor that preserves HTML
For feeds, modals, infinite scroll, and dashboards, the same visible label often appears many times. Treat button indexes as valid only when they come from the same extraction/verification script that selected the item.
Selector Heuristics
Prefer selectors in this order:
aria-labelwith a meaningful stable phrase.roleplus text or nested semantic structure.contenteditable,placeholder,name,type,data-testid.- Stable link URL patterns or form attributes.
- Text filter passed separately:
co browser click_element_by_selector <selector> --text='...'. - Generated classes only as a last resort and only after screenshot/context evidence shows no semantic alternative.
Do not use CSS classes that look generated as the primary selector for social feeds. They usually change between sessions.
Do not assume a visible control is a <button>. Social apps often use div[role="button"] or frame-provided controls for labels such as Start a post. Match by semantic role and visible text before falling back to tag selectors.
Do not hardcode temporary context locators such as [data-browser-agent-id="318"] into a target skill. They are useful evidence for one saved context, not stable selectors.
When there are many matching buttons, prefer one of these patterns:
# extract JS returns action_index among all visible matching action buttons
co browser click_element_by_selector button --index=<action_index> --text='<Action>'
or:
co browser click_element_near_selector '<editor/input selector>' button \
--target_text='<Submit/Post/Comment>' \
--container_selector='<item/form container selector>'
The first pattern is for opening the item editor/action. The second pattern is for final submit near an already active editor.
Extraction Script Contract
The extraction script should look like:
(args) => {
const maxItems = args.maxItems || 3;
// scan visible containers
return {
ok: true,
items: [
{
item_index: 0,
author: "Name or channel",
text: "Exact visible content used for generation",
text_hash: "stable hash of normalized text",
action_index: 0,
has_action: true,
visible_bounds: { x: 0, y: 0, width: 0, height: 0 }
}
],
selected_item: null
};
}
Rules:
- Normalize whitespace before hashing.
- Hash the exact text sent to the content-generation skill.
- Return the action index among the same selector/text set that
click_element_by_selector(...)will use. - Include enough identity to disambiguate repeated items: author/title/channel, timestamp if stable, URL/id if available, visible bounds.
- Return
ok: falsewith a reason when no safe item is found. - Do not click from JS.
- Filter things that should never be acted on: ads, promoted/sponsored items, sidebars, notifications, navigation, suggested people, unrelated cards.
The extractor should be conservative. It is better to return ok: false than to act on the wrong item.
Verify Script Contract
The verify script should look like:
(args) => {
const expectedHash = args.expected_text_hash;
const expectedText = args.expected_text;
const expectedAuthor = args.expected_author;
// rescan visible DOM
return {
ok: true,
matched_item: {
item_index: 0,
author: expectedAuthor,
text: expectedText,
text_hash: expectedHash,
action_index: 0,
has_action: true
}
};
}
Rules:
ok: trueonly when author/title and text/hash match.- Include the current action index from the current DOM.
- If the feed moved, the modal changed, or the item is gone, return
ok: false. - The browser workflow must stop on
ok: false. - Return
scanned[]on failure so the next debugging pass can see what the script did find. - Do not accept fuzzy matches for final submit. Fuzzy matching is allowed only during discovery, not during action.
Match Contract
For any workflow where content is generated for a page item, keep this state:
verified_item_author_or_title
verified_item_text
verified_item_text_hash
generated_content
Required gates:
- Extract JS returns the item text/hash.
- Content generation receives exactly
verified_item_text. - Verify JS confirms the same item before opening the editor/form/action.
- Verify JS confirms the same item again before final submit/post/upload.
If any gate fails, stop before click/type/submit.
For generated replies/comments, the prompt to the writer skill must receive exactly verified_item_text, not a paraphrase, screenshot summary, or page-wide text. This prevents "good comment, wrong item" failures.
Browser Action Pattern
After JS verification, use generic browser tools:
co browser click_element_by_selector button --index=<matched_item.action_index> --text=Comment
co browser type_text_by_selector '<editor selector>' '<generated_content>'
co browser click_element_near_selector '<editor selector>' button \
--target_text='<submit text>' --anchor_index=-1 \
--container_selector='<item container selector>' \
--require_anchor_text=true --wait_ms=2500 --verify_anchor_text_cleared=true
For uploads, use the equivalent stable input/button selectors and keep the same extraction/verification gates around the item or form being acted on.
Local file uploads cannot be completed by browser JavaScript alone. Browser-side JS cannot set a real local path on <input type="file">. Use generic browser upload primitives:
co browser upload_file_after_click_by_selector '<upload button selector>' '<absolute local file path>' \
--text='<Upload/Add file/Upload from computer>' --frame_name='<optional frame name>'
or, when a file input is directly available:
co browser upload_file_by_selector 'input[type="file"]' '<absolute local file path>' \
--frame_name='<optional frame name>'
Wrap uploads with skill-local JS scanners such as verify-upload-controls.js and verify-upload-complete.js that report visible upload triggers, input[type=file] metadata, media previews, and upload completion state. Save screenshot/context immediately after upload. If upload verification fails, stop before submit/publish.
For final side-effect actions in frame/shadow UIs, prefer a skill-local JS click script over generic CSS clicking:
co browser run_frame_script .co/skills/<target-skill>/scripts/click-<action>.js \
'{"expected_text":"...","expected_text_hash":"..."}' --frame_name='<optional frame name>'
The click script must verify the exact editor/composer content or item identity, find the enabled visible submit button near that verified context, click exactly once, and return ok: true only when it actually clicked. The workflow must require both matched_frame.result.ok === true and matched_frame.result.clicked === true before reporting success.
For multi-step publish flows, model every side-effect button as a separate one-shot gate. Example: article editor Next is not the same action as final Publish. Use click-next.js after exact editor verification, save the share/publish surface context, then use a separate click-final-publish.js that verifies the expected title/content is visible in that final surface before clicking Publish.
For testing multi-step publish flows without publishing, add an explicit debug flag such as debug_next: true: it may click the non-final Next, save context/screenshot of the final publish surface, report visible buttons, and stop before final Publish.
For reactions/likes, treat the reaction as the same pattern with no generated content:
extract reaction targets -> verify same target by author/text/hash -> click verified reaction index -> verify the unreacted selector disappeared for that target
Example target skill:
.co/skills/linkedin-thumbup/
SKILL.md
scripts/
extract-like-targets.js
verify-like-target.js
The reaction script is just another action variant. Do not add like_linkedin_post() to the browser core.
Skill-Local JS Pattern
Each target skill should include scripts next to SKILL.md:
.co/skills/<target-skill>/scripts/extract-items.js
.co/skills/<target-skill>/scripts/verify-item.js
Use the templates from this skill when starting:
.co/skills/browser-workflow-skill-builder/scripts/extract-items-template.js
.co/skills/browser-workflow-skill-builder/scripts/verify-item-template.js
The scripts must be page functions:
(args) => {
return { ok: true };
}
They are run with:
co browser run_page_script .co/skills/<target-skill>/scripts/extract-items.js '{"maxItems":3}'
For frame-aware workflows, run the same script with:
co browser run_frame_script .co/skills/<target-skill>/scripts/verify-item.js \
'{"expected_text_hash":"..."}' --frame_url_contains='' --frame_name=''
Extraction and verification scripts should be deterministic and small. Avoid network requests, timers, mutation, clicks, typing, or localStorage writes. They should read DOM only and return JSON.
Final click-<action>.js scripts are the exception: they may click only after exact verification passes. They must never perform broad searches such as "first Post button" without checking the matching editor/item context.
If modals, editors, or submit buttons may live inside open shadow roots, include a small deep traversal helper in the script:
const queryAllDeep = (root, selector) => {
const out = [...root.querySelectorAll(selector)];
for (const el of root.querySelectorAll('*')) {
if (el.shadowRoot) out.push(...queryAllDeep(el.shadowRoot, selector));
}
return out;
};
Browser-side scripts run in the page, not Node. Do not use require, fs, process, or other Node APIs inside .co/skills/<target-skill>/scripts/*.js.
Rich Text Editors
Do not assume a rich text editor renders Markdown when raw Markdown is typed or inserted. Live LinkedIn article testing showed raw Markdown stayed literal (##, **bold**, bullets, and Markdown links were displayed as text). For rich editors:
- Parse source content outside the browser when needed.
- Produce both rendered HTML and expected visible text.
- Insert HTML through a paste-like path,
document.execCommand('insertHTML', ...), or directinnerHTMLonly inside a guarded fill script. - Verify against expected visible text, not the original Markdown syntax.
- Return formatting evidence from verification: heading count, bold/italic count, link count, unordered/ordered list count, list item count, and code/pre count.
Example script contract:
parse-markdown.js -> { title, raw_body, body_html, body_text, body_hash }
fill-editor.js(args: title, body_html, body_text) -> { ok, fill_method, formatting }
verify-editor.js(args: title, body_text) -> { ok, text_hash, formatting }
If formatting matters, the workflow must report formatting counts and use a screenshot to confirm rendered appearance. If visible text matches but formatting counts are zero for a Markdown-rich source, treat it as a draft-quality failure and stop before publishing.
When a screenshot, script result, or human report shows a Markdown render problem, always run co browser save_page_context <workflow>_markdown_render_problem while the bad rendering is still visible, then co browser take_screenshot <workflow>_markdown_render_problem.png. Do not rely on screenshots alone. The saved context provides page.html, styles.css, and elements.json for frame/shadow/selector analysis before changing fill or verification logic.
Run Efficiency
Agent runs have an iteration budget, and every tool call in its own turn costs a full LLM round trip. Live data from 2026-06-12: a sequential engagement run spent 20 of 100 iterations on bare wait() turns and hit the cap mid-run with no final report; after the rules below, the same workflow finished 4 items in 66 iterations with a clean report.
Write these rules into every sequential/multi-item target skill:
- Never spend a turn on a bare
wait(). If the UI needs a settle pause, callwaitand the next script in the same turn — multiple tool calls per turn are supported. - While scanning for the next item, batch
scroll+ extract in one turn. Do not take unnamed screenshots during scanning; they feed images into model context and bloat it. The extract JSON is the source of truth while scanning. - Screenshot only at evidence gates (before-submit, completed), with the item hash in the filename.
- Set an explicit per-run item budget (for example: stop after 4 successfully processed items unless the user asks for more). Repeat runs scroll past their own history, so an unbounded loop exhausts the budget hunting and loses the final report.
- End every run with a final report listing, per item: identity, hash, content, status, and the exact screenshot and saved-context paths.
For nested content-generation sub-calls (co ai "/writer-skill ..." from Bash):
- Pin the model explicitly with
-m <model>. Nested calls use the CLI default model, not the parent run's model, and content quality tracks model quality. - Sub-calls can stall; if one times out once, retry exactly once with an explicit timeout, then skip the item.
- Do not trust a sub-agent's own "complete" status for side-effect steps. Weak models quit multi-gate workflows after generating content and their self-evaluation still reports success; require the side-effect script's
ok/clickedJSON and hash-named evidence instead.
Testing Sequence
Use this order for every new browser workflow skill:
-
Script syntax:
node --check .co/skills/<target-skill>/scripts/extract-items.js node --check .co/skills/<target-skill>/scripts/verify-item.js node --check .co/skills/<target-skill>/scripts/click-<action>.js -
Local JS regression tests for non-trivial scripts:
- Use
jsdomor a simple DOM harness for hash matching, visibility guards, disabled button guards, and open shadow-root traversal. - Test that the final click script refuses wrong text/hash and clicks only the matching enabled button.
- For rich text editors, test raw Markdown to HTML/text conversion, HTML fill behavior, visible-text verification, and formatting counts.
- For uploads, test upload-control scanners and upload-complete verifiers with file input/media preview fixtures.
- Use
-
Safe browser extraction test:
Open <site>. Do not click, type, upload, post, submit, or publish anything. Take a screenshot, run extract-items.js, then run verify-item.js for selected_item. Report selected author/title, text_hash, action_index, and verify ok. -
Editor-only test when safe:
- Open the editor/input.
- Type a harmless draft only if the user asked for it.
- Screenshot and stop before submit.
- For rich text editors, test with headings, bold, italic, links, unordered lists, ordered lists, and code. Verify whether raw typing stays literal or HTML insertion preserves formatting.
-
Full live workflow:
- Only after extraction and verification both pass.
- The final action must be one-shot.
- Stop after screenshot/context, even if status is ambiguous.
Never skip the safe extraction test. It catches almost all wrong-container and wrong-button bugs before a live action happens.
Page Context Analysis
Always save context during skill creation or debugging:
co browser save_page_context <site>_<workflow>_before
Use saved files this way:
page.html: find semantic DOM structure and nearby stable attributes.styles.css: inspect visibility/layout clues only when DOM is ambiguous.elements.json: find clickable elements, text, aria labels, positions, frame names, and candidate selectors.- screenshots: verify that extracted text matches the actual visible center workflow.
Do not rely only on screenshot OCR or raw page-wide get_text for fragile workflows.
Know where artifacts land so the final report can cite real paths: take_screenshot(...) writes under the working directory's .tmp/, and save_page_context(...) writes a timestamped folder under ~/.co/browser_context/<timestamp>_<name>/ containing page.html, styles.css, and elements.json. For sequential multi-item workflows, stamp the item's text_hash into evidence names (<workflow>_before_submit_<hash>, <workflow>_completed_<hash>) — hash-distinct evidence pairs are also how to prove the run processed different items rather than looping on one.
The skill scripts only resolve as .co/skills/<skill>/scripts/... when the working directory has a .co/skills symlink (or the skill is installed globally and run from a project with that layout). Verify the path resolves before a live run; a missing symlink makes the agent burn iterations rediscovering script paths with ls.
When a visible element exists in elements.json but cannot be found from run_page_script(...), suspect a frame or shadow-root boundary before changing selectors.
For upload workflows, elements.json may show only the visible upload button while the actual input[type=file] is hidden. Use both saved context and a skill-local scanner to discover hidden file inputs, but use browser upload primitives for the actual local file selection.
Debugging Wrong Matches
If the agent comments/posts/uploads to the wrong item, fix in this order:
- Save context after the bad match.
- Compare screenshot,
elements.json, and extractor output. - Check whether the action index was computed among the same selector/text set used for clicking.
- Check whether verification ran after any scroll, modal open, expansion, or content generation.
- Check whether the target element lives in a non-main frame or open shadow root.
- Add a stronger identity field to extraction: author/title, URL, timestamp, visible bounds, stable DOM id.
- Add an exclusion rule for ads/sidebar/navigation if those appeared in
scanned[].
Do not solve wrong matches by telling the agent to "be careful". Make the script return better structured evidence.
For fragile submit failures, create a separate debug-capture skill that never publishes. It should open the relevant modal/editor, insert only harmless test content if needed, save context, take a screenshot, and run an analyzer script that reports button metadata, frames, visibility, disabled state, and nearby editor text.
For multi-step final actions, capture the intermediate surface before adding final submit. Example: after a verified Next click, save <workflow>_share_before_publish and report visible final buttons. Only add final publish after that surface has been captured and the final button can be verified semantically.
Safety Rules
- Dry-run first: extraction + verification only, no click/type/submit.
- For social media or publishing actions, final submit is a one-shot action.
- After final submit click, never retry by clicking the same submit/post button again in the same run.
- Always take a pre-submit screenshot and post-submit screenshot.
- Save page context before submit and after submit when the skill needs debugging evidence. For new or fragile skills, make this mandatory.
- If a final JS click script fails or returns ambiguous evidence, immediately save context named
<workflow>_submit_js_failed, take a screenshot, report the failure evidence, and stop. Do not try a different selector in the same live run. - If the editor still shows the content after submit, report uncertain state instead of clicking again.
- For social, email, payment, upload, or publishing workflows, assume actions are externally visible and irreversible unless proven otherwise.
- If the user's request is only to test extraction or draft, do not click submit/post/upload even if the skill knows how.
- Do not navigate away from an already-open editor/composer that contains the intended content. Verify the existing composer first; navigation may discard the draft or open a different surface.
- If
open_browser, navigation to the target editor, or browser context access fails, stop and report that setup failure. Do not write fallback Playwright runners or switch automation stacks inside the target skill. - Do not create helper scripts during a live browser run. Add or edit skill-local scripts outside the live run, then run tests before the next live attempt.
- For uploads, verify the local file exists before opening the browser. If the upload fails or the uploaded media cannot be verified, stop before submit/publish.
Skill Output Checklist
When creating the new target skill, make sure SKILL.md includes:
- exact page URL or navigation target
- required tools list
- script paths
- extraction JSON shape
- verification JSON shape
- stable selectors
- upload trigger/file input selectors if files are involved
- frame/shadow-DOM strategy
- rich-text strategy: raw text vs HTML insertion, expected visible text, and formatting evidence
- multi-step publish strategy: intermediate
Next/preview/share gates and final submit gate - match contract
- dry-run test command
- full-run test command
- one-shot submit rule
- screenshot/context save points with item hash in evidence names
- trust-the-scripts rule: no reading/
ls/globof skill scripts during live runs - wait/batching rules: no bare
wait()turns, scroll+extract batched while scanning - per-run item budget for sequential workflows
- final report shape listing per-item evidence paths (
.tmp/screenshots,~/.co/browser_context/contexts) - pinned model (
-m) for any nested content-generation sub-call - exact stop conditions
- expected dry-run evidence
- expected full-run evidence
Example Target Skill Skeleton
---
name: <site-action>
description: <what this browser skill does and when to use it>
tools:
- go_to
- take_screenshot
- save_page_context
- run_page_script
- run_frame_script
- click_element_by_selector
- type_text_by_selector
- click_element_near_selector
- upload_file_by_selector
- upload_file_after_click_by_selector
---
# <Site Action>
Use scripts:
- `.co/skills/<site-action>/scripts/extract-items.js`
- `.co/skills/<site-action>/scripts/verify-item.js`
- `.co/skills/<site-action>/scripts/click-submit.js` when final submit lives in a frame/shadow UI or generic selectors are ambiguous
- `.co/skills/<site-action>/scripts/verify-upload.js` when local files are involved
- `.co/skills/<site-action>/scripts/fill-editor.js` when rich text or HTML insertion is involved
Workflow:
1. Navigate.
2. Screenshot and save context.
3. Run extract script.
4. Select item and set `verified_item_text_hash`.
5. Generate or prepare content from exactly `verified_item_text`.
6. Run verify script before click.
7. Click action by verified index.
8. Type/upload.
9. Screenshot and save context before submit.
10. Run verify script again.
11. Submit once.
12. Screenshot and save context after submit.
13. Report item identity, hash, content, and final status.
Bad Patterns
Bad: adding linkedin_extract_posts() or twitter_post_reply() directly to core browser.py.
Good: generic run_page_script(...) in browser core, with .co/skills/<skill>/scripts/*.js holding site-specific DOM logic.
Bad: generate a comment from one post, then click the first visible Comment button.
Good: hash the exact extracted post text, verify the same hash before clicking, and use the current verified action index.
Bad: if submit is ambiguous, click again.
Good: screenshot/context, report uncertain state, and stop.
Bad: pass inline JavaScript as script_text or put JS source in the script_path argument.
Good: create a real skill-local file under .co/skills/<skill>/scripts/*.js and call it with script_path.
Bad: use Node APIs such as require('fs') inside browser-executed scripts.
Good: write browser page functions that use DOM APIs and return structured JSON.
Bad: keep retrying alternate submit selectors after a live final click fails.
Good: save <workflow>_submit_js_failed context plus screenshot, then analyze elements.json and the frame/shadow boundary before another live attempt.
Bad: type raw Markdown into a rich text editor and assume it renders.
Good: convert Markdown to HTML plus expected visible text, insert HTML through a guarded fill script, then verify visible text and formatting counts.
Bad: set a local file path from browser JS or write site-specific upload Python.
Good: use generic upload_file_after_click_by_selector(...) or upload_file_by_selector(...), with skill-local JS only for discovering upload controls and verifying uploaded media.
Bad: after Next opens a publish/share dialog, immediately click the first visible Publish.
Good: treat Next and final Publish as separate one-shot gates; save the intermediate context and verify the final surface before the final click.
Bad: when open_browser or navigation fails, write fallback Playwright scripts inside the live skill run.
Good: stop, report the browser/profile failure, and fix the skill or browser tool outside the live run.
Bad: spend a whole turn on wait(seconds=2), then another on extract, then another on an unnamed screenshot.
Good: batch the settle wait, the scroll, and the extract into one turn; screenshot only at hash-named evidence gates.
Bad: read every script in scripts/ with read_file before acting, "to understand the workflow".
Good: trust the script paths listed in SKILL.md and run them; read scripts only outside live runs.
Bad: loop a sequential workflow until the iteration cap kills it mid-hunt with no final report.
Good: stop after the per-run item budget, then spend the remaining budget on the evidence-path report.
Bad: call a nested writer skill without -m and accept whatever the default model returns.
Good: pin a strong model, gate the returned content against concrete rejection rules, retry once with the rejection reason, and skip the item if it still fails.
Frequently asked questions
What to verify before installation and use
What does the browser-workflow-skill-builder source document cover?
Create or improve browser automation skills for logged-in web apps. Use this when building skills that read a page, choose the correct item, generate or prepare content, click/type/upload, or submit/post/publish.
How do I install browser-workflow-skill-builder?
The source record exposes this install command: npx skills add https://github.com/openonion/connectonion --skill "connectonion/useful_skills/browser-workflow-skill-builder". Inspect the command and pinned source before running it.
Which permission-related actions were detected?
Static rules flagged exec-script, write-files in the source; the page lists the matching lines and excerpts.
Alternatives
Compare before choosing
alirezarezvani/claude-skills
app-store-optimization
App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist
prowler-cloud/prowler
postgresql-indexing
PostgreSQL indexing best practices for Prowler: index design, partial indexes, partitioned table indexing, EXPLAIN ANALYZE validation, concurrent operations, monitoring, and maintenance. Trigger: When creating or modifying PostgreSQL indexes, analyzing query performance with EXPLAIN, debugging slow queries, reviewing index usage statistics, reindexing, dropping indexes, or working with partitioned table indexes. Also trigger when discussing index strategies, partial indexes, or index maintenance
trailofbits/skills
constant-time-testing
Measures timing side channels in cryptographic implementations by running them, using dudect for statistical analysis and Timecop over Valgrind for dynamic tracing. Covers the formal, symbolic, dynamic, and statistical tool categories and how to read a result. Use when testing whether a running implementation is constant-time, measuring timing variance on a compiled binary, or investigating a suspected timing attack. Not for statically inspecting compiler output — the constant-time-analysis plug
dotnet/skills
migrate-static-to-wrapper
Migrate C# static calls to a wrapper or built-in abstraction the user already named, within named files/projects, including affected fake-based test updates. USE FOR explicit DateTime.UtcNow/Now to TimeProvider, File.* to IFileSystem, existing IEnvironmentReader/ITextFileStore, scoped migrations, constructor injection, or a static API seam that keeps callers compiling and DateTimeKind unchanged. DO NOT USE when the user asks for behavior tests but leaves seam selection open (testability-obstacle