docs · concepts
Skills & SKILL.md
A skill is one task on one site, written down precisely enough that any agent, with any browser, can replay it: the exact selectors and — whenever possible — the direct in-page request.
Anatomy of a SKILL.md
A skill is a single SKILL.md file: YAML frontmatter for machines, a browser-agnostic recipe for the agent. The catalog id is the URL path ({domain}/{task}, e.g. linkedin.com/search-people); the frontmatter name is the kebab-case task name the agent registers natively.
--- name: search-people description: Search people on LinkedIn, one or many queries with auto-pagination. site: linkedin.com needs: [navigate, evaluate] side_effect: read auth: session --- ## Preconditions A logged-in linkedin.com session in the browser profile. ## Execute 1. navigate to https://www.linkedin.com/feed/ (same-origin) 2. evaluate the Extractor with params { query, limit } ## Extractor In-page async function: an authenticated fetch against the site's own search API, parse, return the JSON below. ## Success assertion returns.people is a non-empty array with name + profile url.
Frontmatter fields
| Field | Example | Meaning |
|---|---|---|
name | search-people | Kebab-case, native-valid skill name — it must register cleanly into the agent’s own skill framework |
description | — | One paragraph: what it does and when to use it |
site | linkedin.com | The domain the skill operates on |
needs | [navigate, evaluate] | Browser capabilities required to run it (see below) |
side_effect | read | Safety level: read, write or irreversible |
auth | session | Whether a logged-in session is required |
Generic skills: one skill, a whole class of tasks
A generic skill is parameterized: it takes inputs and handles an entire class of requests on a site, instead of hard-coding a single case. search-people searches for any query and page count; get-profile fetches any slug. The same SKILL.md serves every call — you pass the params, the recipe stays put.
| Kind | Example | Covers |
|---|---|---|
| generic | linkedin.com/search-people | Any { query, limit } — one skill for every search |
| fixed-case | instacart.com/search-limon | One frozen input (always searches “limon”) — no params |
Prefer generic whenever the task has natural inputs: lift the varying values into params (declared in the description and read by the Extractor) and keep the steps fixed. A fixed-case skill is the shortcut — worth writing only when the input never changes, or as a first draft you later generalize.
Capabilities: skills never name a tool
A skill writes its steps in generic capability verbs — it never says “call browser_navigate”. Your agent maps each verb to whatever browser it actually has:
| Capability | What it must do | Playwright MCP | claude-in-chrome |
|---|---|---|---|
navigate(url) | Open a URL, establishing the session | browser_navigate | navigate |
evaluate(fn) | Run JavaScript inside the page and read the result | browser_evaluate | javascript_tool |
snapshot() | Read the rendered page structure | browser_snapshot | read_page |
click(ref) | Click an element | browser_click | computer |
type(ref, text) | Type into a field | browser_type | form_input |
network() | Read the page’s network requests | browser_network_requests | read_network_requests |
Check needs up front: if your browser can’t provide a capability, switch to one that can. Skills ship CSS selectors, never ephemeral refs or screen coordinates — you resolve them at runtime.
How a skill executes
The browser holds the session — cookies never leave it. The extractor runs inside the page, so authentication rides on the session that is already there.
Prefer doing DOM actions inside evaluate (document.querySelector(sel).click(), scrollIntoView()) — it behaves the same across every browser and beats native click/type for reliability.
Robust vs fragile skills
Declared needs | Shape | Stability |
|---|---|---|
[navigate, evaluate] | One in-page fetch + parse against the site’s own API | robust |
includes click / type / snapshot | UI-driven: depends on the rendered page and its markup | more fragile |
Side-effect levels
| Level | Meaning | Examples |
|---|---|---|
| read | Only reads data — safe to run and retry freely | search people, fetch a profile, list issues |
| write | Changes state somewhere, usually undoable | add to cart, save a draft |
| irreversible | Publishes or sends for real — confirm before running | send a DM, post a comment, submit a connection request |
Auth: auth: session
Skills that need a logged-in session declare it and list it under Preconditions. The rules are simple:
- Site already logged in, in the browser profile you drive → just run the skill.
- Not logged in →
navigateto the site, let the user log in manually, then retry. The session persists in the profile. - Session expires mid-run → re-prompt the user to log in and retry. Never re-learn the skill and never automate the login.