agentleFS
MicrosoftKnown publishermicrosoft/playwright/.claude/skills/playwright-release-notes/SKILL.md

playwright-release-notes

Skill99k starsChanged 2 days agoApache-2.0View on GitHub

Write the release notes for a Playwright release - the Node.js notes in docs/src/release-notes-js.md together with the Python, Java and .NET translations, and the GitHub markdown for each language's release. Use when asked to write, translate or publish release notes.

We split this skill into the rules it gives an agent

14 rules. About 0 are common, 2 are distinctive, and 12 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 12

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Every release has a ## Version 1.xx section in four files in docs/src/:

    line 10
  2. Very specific:

    Write the Node.js notes and the three translations in the same PR, so every language has its notes when it starts its release.

    line 19
  3. Very specific:

    Keep the structure: highlights with emoji headings, ### New APIs with #### groups, ### Breaking Changes ⚠️, ### Announcements and ### …

    line 36
  4. Distinctive:

    Remove what the language does not have:

    line 37
  5. Very specific:

    every API whose langs excludes the language (python, java, csharp).

    line 41
  6. Very specific:

    Use the language's API where it differs from Node.js:

    line 42
  7. Very specific:

    When a Node.js sample shows a library feature through playwright.config.ts, show the API call instead.

    line 46
  8. Very specific:

    Keep API links as docs link macros, and link the language's own option where it differs ( [option: Browser.newContext.recordVideoFps] ).

    line 47
  9. Distinctive:

    Do not add changes that only a language port made.

    line 49
  10. Very specific:

    Use the sync API: page.get_by_role("button").click().

    line 55
  11. Very specific:

    Use the alias-python names: route.continue_(), locator.or_(), page.expect_request().

    line 59
  12. Very specific:

    Leave out the ## Version 1.xx heading.

    line 104
  13. Very specific:

    Check that every link resolves.

    line 130
  14. Very specific:

    If the conversion shows a problem in the notes themselves, such as an API the language does not have or a sample in the wrong style, fix …

    line 156

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Release notes

In this skill, 1.xx is the release (for example 1.64).

Every release has a ## Version 1.xx section in four files in docs/src/:

LanguageNotesDocs base URLGitHub release in
Node.jsrelease-notes-js.mdhttps://playwright.dev/docs/microsoft/playwright
Pythonrelease-notes-python.mdhttps://playwright.dev/python/docs/microsoft/playwright-python
Javarelease-notes-java.mdhttps://playwright.dev/java/docs/microsoft/playwright-java
.NETrelease-notes-csharp.mdhttps://playwright.dev/dotnet/docs/microsoft/playwright-dotnet

Write the Node.js notes and the three translations in the same PR, so every language has its notes when it starts its release. The language repos then add only their own significant changes, and each one writes its GitHub release from its section (step 3).

1. Node.js notes

In docs/src/release-notes-js.md, add a ## Version 1.xx section above the previous version, and use previous versions as a guide:

  • Highlights come first, each with an emoji heading and a short sample. Ask teammates for help with them.
  • Then ### New APIs with #### groups, ### Breaking Changes ⚠️, ### Announcements and ### Browser Versions. Print the browser versions with node utils/print_versions.js.
  • Refer to APIs with docs link macros: [`method: Page.frameLocator`], [`property: Page.webmcp`], [`event: Page.dialogClosed`], [`option: Tracing.start.ariaSnapshots`], [Locator]. Each language's docs show them with that language's names.
  • Link other docs pages with relative paths: [test locks](./test-parallel.md#test-locks).

2. Python, Java and .NET translations

In each of release-notes-python.md, release-notes-java.md and release-notes-csharp.md, add a ## Version 1.xx section above the previous version. Translate it from the Node.js section. Compare the Version 1.63 sections of the files to see what past translations dropped and changed.

For every language:

  • Keep the structure: highlights with emoji headings, ### New APIs with #### groups, ### Breaking Changes ⚠️, ### Announcements and ### Browser Versions.
  • Remove what the language does not have:
    • the test runner: @playwright/test, test.*, config, fixtures, projects, reporters and npx playwright test options
    • UI mode, the HTML report, component testing and the VS Code extension
    • TypeScript-only features (generics, JSX, tsconfig) and devices descriptors
    • every API whose langs excludes the language (python, java, csharp). Check langs in docs/src/api/; options shared between methods are defined in docs/src/api/params.md.
  • Use the language's API where it differs from Node.js:
    • A language-specific option has its own langs. For example, recordVideoFps is langs: csharp, java, python, while Node.js has recordVideo.fps.
    • alias-<lang> renames a member, e.g. alias-java: isVisible for LocatorAssertions.toBeVisible.
    • The generated APIs in sibling checkouts confirm the names: ../playwright-python/playwright/sync_api/_generated.py, ../playwright-java/playwright/src/main/java/com/microsoft/playwright/ and ../playwright-dotnet/src/Playwright/API/Generated/.
  • When a Node.js sample shows a library feature through playwright.config.ts, show the API call instead. For example, the 1.64 video config became calls to Screencast.start and Screencast.showActions.
  • Keep API links as docs link macros, and link the language's own option where it differs ([`option: Browser.newContext.recordVideoFps`]). In plain text, use the language's names.
  • A relative link must point to a page that exists in the language: *-js.md pages are Node.js only. npm run doc reports broken links for each language.
  • Do not add changes that only a language port made. The language repo adds those to its notes.

Rewrite code samples in each language's style. The infra workflow checks the syntax of python, java and csharp snippets.

Python

  • Use the sync API: page.get_by_role("button").click(). Use snake_case names and Python values (True, False, None).
  • Options become keyword arguments: page.get_by_role("button", name="Save"). Objects and arrays become dicts and lists: size={"width": 1920, "height": 1080}.
  • Aria roles and other string values stay strings: "button", "ai".
  • Events: page.on("dialogclosed", handler). Assertions: expect(locator).to_have_text([...]). Print with print(...).
  • Use the alias-python names: route.continue_(), locator.or_(), page.expect_request().
  • Commands: write playwright install, not npx playwright install.

Java

Node.jsJava
await page.goto('...')page.navigate("...");: no await, double quotes, semicolons, typed locals (Locator dialog = ...)
page.getByRole('button', { name: 'Save' })page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Save"))
options object { path: 'video.webm', fps: 60 }options builder new Screencast.StartOptions().setPath(Paths.get("video.webm")).setFps(60)
object literal { name: 'session-id', value: '42', url }value class new Cookie("session-id", "42").setUrl(url)
['a', 'b'], { a: 2 }Arrays.asList("a", "b"), Map.of("a", 2); new String[] {"a", "b"} for assertion arguments
property page.webmcp, context.tracinggetter page.webmcp(), context.tracing()
event page.on('dialogclosed', handler)page.onDialogClosed(handler)
expect(locator).toHaveText(...)assertThat(locator).hasText(...). Likewise toBeX → isX, toHaveX → hasX, toContainX → containsX, toMatchX → matchesX
route.continue() and other members with alias-javathe alias, e.g. route.resume()
npx playwright install --no-removemvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --no-remove"
"array", undefined, 'ai' in prose"list", null, "ai"

.NET

Node.js.NET
await page.goto('...')await page.GotoAsync("...");: PascalCase members, Async suffix on async methods, var locals, double quotes, semicolons
page.getByRole('button', { name: 'Save' })page.GetByRole(AriaRole.Button, new() { Name = "Save" })
options object { path: 'video.webm', fps: 60 }options initializer new() { Path = "video.webm", Fps = 60 }
nested object size: { width: 1920, height: 1080 }Size = new() { Width = 1920, Height = 1080 }
object literal { name: 'session-id', value: '42', url }new Cookie { Name = "session-id", Value = "42", Url = url }
['a', 'b'], free-form object { a: 2 }new[] { "a", "b" }, anonymous object new { a = 2 }
string-literal union value 'ai', 'button'enum member AriaSnapshotMode.Ai, AriaRole.Button
property page.webmcp, context.tracingproperty page.Webmcp, context.Tracing
event page.on('dialogclosed', handler)page.DialogClosed += (_, dialog) => { ... };
expect(locator).toHaveText(...)await Expect(locator).ToHaveTextAsync(...);
console.log(x)Console.WriteLine(x);
members with alias-csharpthe alias, e.g. page.request → page.APIRequest
union-typed option, e.g. httpCredentials as a listone property per type, e.g. HttpCredentialsList
npx playwright install --no-removepwsh bin/Debug/netX/playwright.ps1 install --no-remove
option names in prose (fontSize), undefinedFontSize, null

Open one PR for all four files, titled docs: release notes for v1.xx. After it merges, cherry-pick it to release-1.xx with the playwright-cherry-pick skill.

3. GitHub release markdown

Each repo publishes the GitHub release for its language, with markdown converted from its ## Version 1.xx section on release-1.xx. Convert the notes yourself:

  • Leave out the ## Version 1.xx heading. Move every other heading up one level (### becomes ##, #### becomes ###).
  • Replace each link macro with a full link: the language's docs base URL from the table at the top, plus the path below. Use the language's name as the link text:

    MacroPath after the docs base URLNode.jsPythonJava.NET
    [Locator]api/class-locatorLocatorLocatorLocatorLocator
    [`method: Page.frameLocator`]api/class-page#page-frame-locatorpage.frameLocator()page.frame_locator()page.frameLocator()Page.FrameLocator()
    [`method: Page.ariaSnapshot`]api/class-page#page-aria-snapshotpage.ariaSnapshot()page.aria_snapshot()page.ariaSnapshot()Page.AriaSnapshotAsync()
    [`method: Locator.first`]api/class-locator#locator-firstlocator.first()locator.firstlocator.first()Locator.First
    [`property: Page.webmcp`]api/class-page#page-webmcppage.webmcppage.webmcppage.webmcp()Page.Webmcp
    [`event: BrowserContext.dialogClosed`]api/class-browsercontext#browser-context-event-dialog-closedbrowserContext.on('dialogclosed')browser_context.on("dialogclosed")browserContext.onDialogClosed()BrowserContext.DialogClosed
    [`method: LocatorAssertions.toBeVisible`]api/class-locatorassertions#locator-assertions-to-be-visibleexpect(locator).toBeVisible()expect(locator).to_be_visible()assertThat(locator).isVisible()Expect(Locator).ToBeVisibleAsync()
    [`option: Page.content.includeShadow`]api/class-page#page-content-option-include-shadow`includeShadow``include_shadow``includeShadow``IncludeShadow`
    [Playwright MCP](./getting-started-mcp.md)getting-started-mcpPlaywright MCPPlaywright MCPPlaywright MCPPlaywright MCP
  • An image ![alt](./images/foo.png) becomes ![alt](https://github.com/microsoft/playwright/blob/main/docs/src/images/foo.png?raw=true) in every language.

The page is class- and the class name in lower case. The anchor is the class and member names in kebab-case, so APIRequestContext.addCookies becomes api-request-context-add-cookies. Options add -option-<name>, and events add -event-<name>. Anchors use the names from docs/src/api/ even where a language renames the member, so Java's isVisible() links to #locator-assertions-to-be-visible.

The link text follows the language:

  • Node.js: the class in lower camel case (page, apiRequestContext, testConfig). Methods get (), properties none, events become on('<event in lower case>'), and assertions start with expect(locator)., expect(page). or expect(response)..
  • Python: the class and member in snake_case (browser_context, api_request_context). Methods get (). A member is a property, without (), if _generated.py declares it with @property. Events become on("<event in lower case>"), and assertions start with expect(locator)..
  • Java: the class in lower camel case and the alias-java member name. Methods and properties get (), events become on<Event>(), and assertions start with assertThat(locator)..
  • .NET: the class without the interface I (Page, APIRequestContext) and the member exactly as the generated I<Class>.cs declares it. Async methods take the Async suffix and (), sync methods get (), and properties and events get no parentheses. Assertions start with Expect(Locator)..

Check that every link resolves. playwright.dev already documents the release once the Node.js docs roll has landed. It serves minified HTML, so an anchor may appear without quotes (id=page-webmcp>):

grep -oE 'https://playwright\.dev/[^) ]+' <notes-file> | sort -u | while read -r url; do
  page=${url%%#*}
  html=$(curl -sfL "$page") || { echo "MISSING PAGE   $url"; continue; }
  if [[ "$url" == *"#"* ]]; then
    anchor=${url#*#}
    grep -qE "id=\"?${anchor}[\" >]" <<<"$html" || echo "MISSING ANCHOR $url"
  fi
done

Then scan for anything that wasn't converted, and for stray spaces inside link text ([Page. DialogClosed], [`HttpCredentialsList `]). The first command applies to every language; then run the one for the language. They should print nothing:

# every language
grep -nE '\[`(method|property|event|option|param): |\]\(\./|\[[A-Z][A-Za-z]*\]([^(]|$)|\[[A-Za-z_]+\. |\[`[^`]+ `\]' <notes-file>
# Python: camelCase names in link text
grep -nE '\[[a-z_]+\.[a-z_]*[A-Z]|\[`[a-z]+[A-Z]' <notes-file>
# Java: JS-style events, assertions and properties
grep -nE "\.on\('|\b(toBe|toHave|toContain|toMatch)[A-Z]|\bawait\b|\barray\b|\bundefined\b|\[[a-z][A-Za-z]*\.[a-z][A-Za-z]*\]\(" <notes-file>
# .NET: lower-case classes or members, JS-style events
grep -nE "\.on\('|\bundefined\b|\[[a-z][A-Za-z]*\.|\[[A-Z][A-Za-z]*\.[a-z]|\[Expect\([a-z]" <notes-file>

If the conversion shows a problem in the notes themselves, such as an API the language does not have or a sample in the wrong style, fix the notes too (step 2). Otherwise the problem stays on playwright.dev.

Download now (ZIP)

Trending

More talk lately.about the whole repository

Dec 2025: 3 mentionsJan 2026: 3 mentionsFeb 2026: 2 mentionsMar 2026: 2 mentionsApr 2026: 2 mentionsMay 2026: 1 mentionJun 2026: 0 mentionsJul 2026: 0 mentionsAug 2026: 1 mentionSep 2026: 3 mentionsOct 2026: 3 mentionsNov 2026: 0 mentions
Dec 2025Jun 2026Nov 2026
Mentions a month of the microsoft/playwright repository that our weekly crawl found. There is no adoption data for this file yet.

Who's talking about microsoft/playwright

The biggest 5 of 121 mentions linking to the repository that our crawl found. Each line is their own headline.

See all 121

Talked about on Bluesky, GitHub, Stack Overflow, Hacker News, the web and YouTube (121 times).

On Bluesky · 39

34 more on Bluesky

On GitHub · 31

26 more on GitHub

On Stack Overflow · 25

20 more on Stack Overflow

On the web · 9

4 more on the web

On YouTube · 8

3 more on YouTube

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.