change-keyword
Skill663 starsChanged 6 days agoApache-2.0View on GitHub
Add, change or remove a Browser library keyword across proto, Node and Python. Use when a task touches a keyword''s name, arguments, behaviour or docstring, or adds a new one.
In this repository7 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- ci-failure-triageSkill
- write-node-unit-testsSkill
- parse-rf-resultsSkill
- write-python-unit-testsSkill
- write-robot-testsSkill
The file
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 0 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 32
Every public keyword becomes an entry in each translation users maintain (rfbrowser translation), so removing or renaming one is a breaking …
- Very specific: line 41
Add or change the rpc in service Playwright and its messages under Request or Response.
- Very specific: line 45
Run inv node-build; it regenerates the Python and TypeScript stubs.
- Very specific: line 51
Write the implementation as a function in the feature module (getters.ts, interaction.ts, ...) with the signature (request, state: …
- Very specific: line 63
Put the method on the keyword class for its feature area in Browser/keywords/, decorated with @keyword(tags=(...)).
- Very specific: line 88
Check the result the way users read it: python -m robot.libdoc Browser show "<Keyword Name>" prints the signature and docstring, and inv …
- Very specific: line 107
Run this step without being asked, once step 6 is done.
- Very specific: line 124
Deprecate: Start the docstring with *DEPRECATED* and name the replacement, as Open Browser does in playwright_state.py.
- Very specific: line 133
Remove in the major release: Delete the keyword across all three layers and its acceptance tests, and say in the release notes which …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 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.
Files
Change a keyword
A keyword spans three layers: a Python method in Browser/keywords/, an rpc in
protobuf/playwright.proto, and a Node handler in node/playwright-wrapper/. Copy the example
that matches the keyword:
- Takes a selector, as most keywords do:
Get Text.Getters.get_text→rpc GetText→getText = this.wrapping(getters.getText)ingrpc-service.ts→getters.getText. - No selector:
Get Title.Getters.get_title→rpc GetTitle→getTitleingrpc-service.ts→getters.getTitle.
Steps
1. Is there a need for a keyword?
For a new keyword, name the need first. It is one of:
- Playwright functionality that can only be exposed to users as a keyword, or
- a user need that is generally useful, not one test's convenience.
Then look for a way that keeps the keyword count down: a new argument on an existing keyword, a
better assertion, or one higher-level keyword that combines several Playwright calls. State that
plugins, libraries built on Browser, or acceptance-test helpers need goes on an internal
Browser property, not a keyword (ADR 0009).
Every public keyword becomes an entry in each translation users maintain
(rfbrowser translation), so removing or renaming one is a breaking change for them too. Removal
and renaming follow their own path: see Removing or renaming a keyword.
Done when the need is stated in one sentence and the maintainer agrees with the shape: new keyword, new argument, or no keyword.
2. Proto
Add or change the rpc in service Playwright and its messages under Request or Response.
Reuse an existing message when one fits (Request.Empty, Response.String, Response.Json).
Arguments go in a typed Request message, not Request.Json, one rpc per Playwright call
(ADR 0013).
Run inv node-build; it regenerates the Python and TypeScript stubs.
Done when inv node-build succeeds.
3. Node
Write the implementation as a function in the feature module (getters.ts, interaction.ts,
...) with the signature (request, state: PlaywrightState) that returns a pb.Response_*.
Register it in grpc-service.ts as name = this.wrapping(module.name). wrapping resolves the
caller's state, logs the call, and turns errors into errorResponse. A selector keyword resolves
its element with findLocator(state, request.selector, request.strict, ...) from
playwright-invoke.ts, which handles frame piercing. Strict mode only applies because Python sends
strict in the request (step 4).
Done when inv node-build and inv lint-node pass.
4. Python
Put the method on the keyword class for its feature area in Browser/keywords/, decorated with
@keyword(tags=(...)); a new class must also be added to the libraries list in
Browser.__init__. Call Node with with self.playwright.grpc_channel() as stub:.
- Annotations stay narrow: an Enum, not
Enum | str(ADR 0006). - A selector keyword starts with
selector = self.presenter_mode(selector, self.strict_mode)and sendsstrict=self.strict_modein its request, the wayget_textdoes.presenter_modealso applies the selector prefix (Set Selector Prefix), so skipping it breaks more than presenter mode. - A getter asserts with
@with_assertion_pollingand theassertionenginehelpers (verify_assertionand friends), the wayget_titleandget_textdo. - A
timeout: timedelta | None = Noneargument goes to Node asself.get_timeout(timeout): milliseconds, falling back to the library timeout when the caller gave none. - Other settings come from
LibraryComponentproperties (self.strict_mode,self.timeout), never fromscope_stackdirectly (ADR 0009).
Done when inv lint-python passes.
5. Docstring
The docstring is the user documentation. It says what the keyword is for, what each argument
really does, and gives an example when usage is not obvious. When an argument's behaviour
changes, rewrite its row and check the example still holds. Code and tests stay free of
explanatory comments. inv node-build regenerates browser.pyi from the new signature.
Check the result the way users read it: python -m robot.libdoc Browser show "<Keyword Name>"
prints the signature and docstring, and inv docs renders the full page to docs/Browser.html
(gitignored) for checking links and formatting.
Done when every argument is described, the rendered page shows no broken links or formatting, and
utest/test_docs.py passes.
6. Tests
- Jest for Node logic worth testing in isolation (
node-unit-testskill). - pytest for Python logic that runs without a browser (
python-unit-testskill). - Acceptance tests for the keyword's behaviour against the Test App (
write-robot-testsskill). A new page or element for them goes innode/dynamic-test-app/.
Done when inv utest, inv utest-node and the affected inv atest --suite runs pass, and
inv lint is clean.
7. Review
Run this step without being asked, once step 6 is done. The review reads commits, so commit the
work on its branch first. Then dispatch a subagent to run the mattpocock-skills:code-review
skill, with the branch's merge-base with main as the fixed point.
The subagent sees only its prompt, so give it the spec: the issue, plus every decision the maintainer made that overrides or adds to it, such as a dropped argument.
Relay both axes to the maintainer, and treat each finding as theirs to accept or reject. Check a finding against the code before relaying it. Apply the accepted ones, then repeat step 6.
Done when the maintainer has ruled on every finding and step 6 passes with the accepted fixes in.
Removing or renaming a keyword
A keyword is never removed in the release that deprecates it. It is deprecated first, and removed
only in the next major release (Browser/version.py has the current version).
- Deprecate. Start the docstring with
*DEPRECATED*and name the replacement, asOpen Browserdoes inplaywright_state.py. Robot Framework then warns on every call. A renamed keyword keeps working under its old name until the removal. - Offer an automatic conversion when one is possible.
rfbrowser transformrewrites users' test data with a robocop formatter.Browser/robocop_transformer/network_idle.pyconvertsWait Until Network Is IdletoWait For Load State networkidleand is the example to copy. A new conversion needs the formatter, a flag ontransforminBrowser/entry/__main__.py, wiring inBrowser/entry/transform.py, and a test inatest/test/11_tidy_transformer/. Tell the maintainer when the change cannot be converted mechanically. - Remove in the major release. Delete the keyword across all three layers and its acceptance
tests, and say in the release notes which keyword or
rfbrowser transformflag replaces it.
Done when the keyword is deprecated with its replacement named, the maintainer has decided whether
rfbrowser transform gets a conversion, and the removal is planned for the next major release.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
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.

