## Commit Convention
Semantic commit messages: `label(scope): description`
Labels: `fix`, `feat`, `chore`, `docs`, `test`, `devops`
```bash
git checkout -b fix-39562
# ... make changes ...
git add <changed-files>
git commit -m "$(cat <<'EOF'
fix(proxy): handle SOCKS proxy authentication
Fixes: https://github.com/microsoft/playwright/issues/39562
EOF
)"
git push origin fix-39562
gh pr create --repo microsoft/playwright --head username:fix-39562 \
--title "fix(proxy): handle SOCKS proxy authentication" \
--body "$(cat <<'EOF'
## Summary
- <describe the change very! briefly>
Fixes https://github.com/microsoft/playwright/issues/39562
EOF
)"
```
Never add Co-Authored-By agents in commit message.
Branch naming for issue fixes: `fix-<issue-number>`
## Rolling Playwright
1. Run `node roll.js` (or `npm run roll`) to bump `playwright`, `playwright-core`, and `@playwright/test`, refresh `config.d.ts`, and regenerate the README. The script prints the resolved version — use its suffix for the branch name.
2. Create a branch: `git checkout -b roll-pw-<version-suffix>`.
3. Run `npm test`. Only proceed if all tests pass.
4. Commit with `chore: roll Playwright to <version>`, push, and open a PR against `microsoft/playwright-mcp` with the same title.
## Preparing a Release
See [.claude/skills/release.md](.claude/skills/release.md).
---
name: release
description: Prepare a playwright-mcp release — roll Playwright, bump the version, and open a `chore: mark v0.0.<next>` PR whose body IS the release notes (changes from this repo and upstream microsoft/playwright since the last release).
---
# Preparing a Release
A release is a `chore: mark v0.0.<next>` commit whose **PR body is the release notes**. There is a single PR — the version bump and the notes ship together. Most MCP source lives upstream at `~/playwright/packages/playwright-core/src/tools/` (and `tests/mcp/`), so the notes draw from both this repo and upstream.
## 1. Roll Playwright
Follow the "Rolling Playwright" steps in `CLAUDE.md`: run `node roll.js`, branch as `roll-pw-<version-suffix>`, run `npm test`, and open a `chore: roll Playwright to <version>` PR. **Wait for it to merge into `main`** before proceeding.
## 2. Bump the version
```bash
git checkout main && git pull
git checkout -b mark-v0.0.<next>
# Bump "version" in package.json, package-lock.json (both occurrences), and server.json (both occurrences)
```
Do NOT open the PR yet — its body must be the release notes, so write those first (steps 3–5).
## 3. Find the exact commit window
The reliable boundary is the **`gitHead` of each published alpha build**, not a fuzzy date window (date windows double-count commits that land on the boundary day — e.g. a commit written on the previous release's build date but not actually in that build).
```bash
# Playwright version pinned by the previous release (last "mark v" commit) and by this release
git log --oneline | grep "mark v" | head -1
git show <prev-release-sha>:package.json | grep '"playwright":' # baseline alpha
grep '"playwright":' package.json # new alpha (already rolled)
# Resolve each alpha to the exact upstream commit it was built from
npm view playwright-core@<baseline-alpha> gitHead # e.g. -> 287ad476...
npm view playwright-core@<new-alpha> gitHead # e.g. -> a061d963...
```
The window is `<baseline-gitHead>..<new-gitHead>`.
## 4. Collect changes
```bash
# Upstream playwright — MCP code path widened to catch tools/extension/dashboard too
cd ~/playwright
git log <baseline-gitHead>..<new-gitHead> --reverse --pretty='%h %s' -- \
packages/playwright-core/src/tools/ packages/playwright-core/src/extension/ tests/mcp/
# This repo
cd -
git log <prev-release-sha>..HEAD --oneline
```
Filter for `feat(mcp)`, `fix(mcp)`, `feat(extension)`, `fix(extension)`, `feat(aria)` snapshot changes, and dashboard changes. Many extension PRs land in *both* repos because the extension source lives upstream now — prefer the `microsoft/playwright` PR link. Use `git show <sha> --stat` to disambiguate ambiguous subjects.
**Drop:** test-only changes, docs, `chore(deps)`, CLI-daemon internals with no MCP-facing effect, reverted commits, and anything not user-visible. **Verify membership** of boundary commits with `git merge-base --is-ancestor <sha> <gitHead>` — a commit can be listed in the previous release's notes yet not actually be in that build; if it was already announced, do not repeat it.
## 5. Write `release-notes.md`
Follow the format from the prior release (`gh pr view <prev-PR> --repo microsoft/playwright-mcp --json body -q .body`). **No top-level `#` header** — the PR title is the heading. Sections: `## What's New` (with `### New Tools`, `### Tool Improvements`, optional `### Browser Extension`, `### Dashboard`, `### Other Changes`) then `## Bug Fixes`. Link each entry to its PR (`[#NNNNN](https://github.com/microsoft/playwright/pull/NNNNN)` or the playwright-mcp equivalent). Fold follow-up PRs into the feature they extend (e.g. a `browser_find` enhancement joins the `browser_find` bullet).
Wording rules:
- Only list things that change user-visible behavior.
- **Do not mention features that are not enabled by default** — confirm with the user before listing experimental flags.
## 6. Commit, push, open the PR with the notes as its body
```bash
git commit -am "chore: mark v0.0.<next>"
git push -u origin mark-v0.0.<next>
gh pr create --repo microsoft/playwright-mcp --head <user>:mark-v0.0.<next> \
--base main \
--title "chore: mark v0.0.<next>" \
--body-file release-notes.md
```
The PR body is the release notes verbatim — no `#` header, no filename, nothing else.
## Pitfalls
- **Don't open the version-bump PR with a placeholder body** and backfill later — write the notes first so the PR is created with them.
- **Don't use a date window** for the upstream diff — use the `gitHead` range. Dates double-count boundary-day commits.
- **Don't re-announce** a commit that already appeared in the previous release's notes; check ancestry with `git merge-base --is-ancestor`.
- **Don't include a `#` header** in the PR body — GitHub renders the PR title already.