render-verify: look at what you rendered
Why this skill exists
A visual artifact can be technically valid and still tell the wrong story. A
chart with a collapsed axis, a merged color scale, or an empty data binding
renders cleanly. So does a report whose images 404, whose text is clipped, or
whose stylesheet never loaded. No validator catches any of it. validate_chart
proves a spec is well-formed, not that the picture is true. Only looking does.
This is the plugin's characteristic bug shape — see Known failure modes in the
repo docs. Every other silent failure here is a config path; this one is a
picture.
The rule: if you rendered it, opened it, or edited it, look at it before you
say it is done.
Scope. The method below — open, read the console first, walk a catalog, check
the claim — is general. It applies to charts, generated HTML reports, SVG
figures, dashboards, diagrams, and printable output. Charts are the
deepest-worked case because this plugin produces them, and their catalog is the
longest; a shorter general catalog follows it.
When to invoke
Mandatory:
- After any post-Flint Vega-Lite edit. The
flint-chart skill forbids
sending an edited spec back to render_chart, so the MCP server's own
validation no longer protects you. You are flying without instruments.
- Before committing generated HTML, SVG, or PNG. Inline specs fail silently.
- When the artifact is layered, faceted, multi-series, or multi-figure. Most
failures below come from layer, scale, or layout interaction.
Recommended:
- After the first render of anything that will be shown to someone other than
the person who asked for it.
- Whenever you changed the data binding or the page structure, not just styling.
Skip:
- Single-layer chart, small embedded data, spec unchanged since a render you
already looked at.
- The user is iterating rapidly on color or title only.
The failure catalog — charts
These render without error. Check each one explicitly — the list is the point of
the skill, not the tooling.
| Failure |
What you see |
Usual cause |
| Empty binding |
Axes, gridlines, legend — and no marks |
Data ref resolved to nothing. A chart with no data still looks like a chart. Rule out a render race first — see capability 5 in Step 1 |
| Collapsed scale |
Everything squashed into a fraction of the plot area |
One layer forced zero: true (or a quantitative axis) into a shared scale |
| Merged color scale |
A mark is the wrong color for its meaning |
Two layers' color scales resolved together. Fix with independent scale resolution, not by recoloring |
| Undefined category |
A blank, null, or undefined row/tick on a categorical axis |
Mis-encoded layer contributing to a shared categorical domain |
| Duplicate marks |
Rows repeated, bars double-height |
Missing dedup upstream — a data problem wearing a chart costume |
| Embedded totals |
One bar dwarfs the rest; parts look flat |
An aggregate level (all, Total) charted alongside its own parts |
| Double-scaled units |
Percentages at 0–10000, or everything at 0.0x |
A 0–100 rate tagged as Percentage and scaled again |
| Overplotting |
A solid blob instead of a distribution |
Too many marks, no opacity/jitter/binning |
| Right on sample, wrong on real |
Looks perfect, means nothing |
Verified against test rows, never against the actual dataset |
The failure catalog — any rendered artifact
For generated HTML, SVG, dashboards, diagrams, and printable output. These also
render without error, and a screenshot alone can look plausible.
| Failure |
What you see |
Usual cause |
| Missing resource |
A broken-image icon, a blank figure slot, an unstyled block |
A 404 on an image, stylesheet, font, or script. The console names it — this is why Step 2 reads errors first |
| Unstyled content |
Raw serif text, no layout, everything left-aligned |
The stylesheet never loaded, or loaded after the capture |
| Clipped or overflowing text |
Sentences cut mid-word, labels truncated, text escaping its container |
Fixed heights, overflow: hidden, or a font substitution that changed metrics |
| Font substitution |
Right words, wrong typeface; spacing subtly off |
A web font failed to load and a fallback took over. Silent by design |
| Layout collapse |
Columns stacked, panels overlapping, huge whitespace |
The captured viewport hit a responsive breakpoint you did not intend |
| Below-the-fold content never checked |
Everything visible looks fine |
Only the viewport was captured. Scroll or capture full-page |
| Stale render |
Your change is not there |
Viewing a cached copy, an old build output, or a different file than you edited |
| Placeholder survived |
Literal TODO, Lorem ipsum, {{value}}, undefined, NaN |
A template slot never filled. Search the rendered text, not just the source |
Step 1 — pick a verification capability
This skill names the capability, not a product. Work down this ladder and
stop at the first rung that works. Do not install a second MCP server for a
job the host already does.
- The host's own browser capability — always try this first. If your tool
inventory contains anything that opens a page and returns a screenshot or a
page snapshot to you, use it. In VS Code Copilot these are the built-in
browser tools; they open
file:// with no flags, no browser download, and no
configuration, and they were verified against this plugin's own demo. This
rung costs nothing and has no security trade-off.
- The optional
playwright MCP server — fallback. Use when rung 1 is
absent, or when rung 1 lacks console-error access and the defect you are
chasing needs a cause rather than a symptom. On a terminal-only agent such
as GitHub Copilot CLI there is no rung 1 at all — it has no browser, so
this rung is the primary path, not the fallback. See Playwright MCP setup
below. It carries real costs: a browser must already be installed, file://
needs --allow-unrestricted-file-access, and it writes artifacts into the
working directory.
- The human. Ask the user to open the artifact and describe what they see,
or give them a specific checklist item to confirm. This is a legitimate
outcome, not a failure — but it must be stated.
Never silently skip verification. If you reached rung 3, or if you have
partial capability (see below), say so plainly in your report. An unverified
chart described as verified is worse than an unverified chart.
Which capabilities you actually need
"Can open HTML" is not one capability — it is five, and hosts differ in which
they provide. Establish what you have before interpreting what you see.
| # |
Capability |
Needed for |
If missing |
| 1 |
Open a local file:// |
Reaching the artifact at all |
Fall back to a render_chart PNG/SVG, or rung 3 |
| 2 |
Agent-readable output (screenshot or accessibility snapshot returned to you) |
Steps 3–4 |
You are on rung 3 — the human is verifying, not you |
| 3 |
Console-error access |
Step 2 — finding the cause |
You can still see symptoms; say that causes were not checked |
| 4 |
Element-scoped or scrolled capture |
Multi-figure artifacts |
Verify one figure per page-load, or accept reduced confidence and say so |
| 5 |
Wait-for / re-capture after render |
Anything JS-rendered (Vega-Lite, ECharts) |
See the false-positive warning below |
[!WARNING]
Capability 5 can manufacture a defect that isn't there. Vega-Lite and
ECharts draw after page load. A screenshot taken too early shows an empty
container — which is visually identical to the empty binding row in the
failure catalog. Before diagnosing "empty binding", re-capture at least once
and confirm the emptiness is stable. Diagnosing a race as a data bug sends the
fix upstream into a spec that was never wrong.
Probe by doing, not by asking: attempt the action against the real artifact
and observe the result. Tool names vary between hosts; outcomes do not.
Step 2 — open it and read the errors first
- Open the artifact. For local files use the canonical absolute
file:///… form.
- Read the console errors before looking at the picture. This is the check
that finds the cause rather than the symptom — a silently-failing inline
Vega-Lite spec throws to the console while still rendering a plausible-looking
page. With the Playwright server this is
browser_console_messages at level
error.
- Then screenshot it.
Zero console errors plus a wrong-looking artifact means a spec, data, or layout
problem. Console errors plus a right-looking artifact means you are probably
looking at a stale render.
Step 3 — check the picture against the catalogs
Walk the chart table if it is a chart, and the general table for anything that
is rendered as a page. Then, for multi-figure artifacts:
- Scroll each figure into view and capture it separately. A single full-page
screenshot visually hides defects in unfocused figures.
- Check the axes have real domains — not
[0, 0], not a collapsed range,
no undefined ticks.
- Count the marks against what the data should produce.
- Search the rendered text for placeholders —
TODO, undefined, NaN,
{{, Lorem. Search what rendered, not the source that produced it.
Step 4 — check the claim, not just the render
Every artifact worth verifying exists to carry a claim. For charts that is the
Big Idea from the chart-big-idea skill; for a report or diagram it is whatever
the surrounding prose asserts. A correct render of a wrong claim is still a
defect.
- Verify prose claims arithmetically against the plotted or tabulated values.
If the caption says "less than a fifth of the noise", compute it.
Order-of-magnitude overstatements in captions survive every automated check
there is.
- Re-read the claim and ask whether the picture shows it. If the claim is
about a gap and the eye goes to a trend, the chart type is wrong — go back to
flint-chart §0.2, do not patch the styling.
Step 5 — report honestly
State which capability you used, that you looked, and what you checked. If you
could not verify, say that instead. Never describe an unopened render as
verified.
Playwright MCP setup
Fallback only — rung 2 of Step 1. Try the host's own browser capability
first; if it can open the artifact and return a screenshot to you, you do not
need this server. Measured against @playwright/mcp@0.0.78:
{
"servers": {
"playwright": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@playwright/mcp@0.0.78",
"--headless",
"--isolated",
"--browser",
"msedge",
"--allow-unrestricted-file-access"
]
}
}
}
Merge this additively into the existing server map — overwriting the file
destroys the user's other servers, including flint. Same per-host path table
as the flint-chart skill (.vscode/mcp.json for VS Code, .mcp.json for
Claude Code, .cursor/mcp.json for Cursor, ~/.copilot/mcp-config.json with
key mcpServers for Copilot CLI).
Why each flag
| Flag |
Why |
--headless |
No visible window; this is a verification pass, not a demo |
--isolated |
No persistent browser profile — keeps the user's real session out of it |
--browser msedge |
There is no bundled browser — Playwright drives an installed one by channel. Edge ships with Windows, which is where most heirs are; the upstream default (chrome) is frequently absent there. Override with chrome, firefox, or webkit where Edge is not installed — typically Linux |
--allow-unrestricted-file-access |
Required for file://. Without it navigation is blocked outright. See the security note below |
Security note — read before enabling the file-access flag
--allow-unrestricted-file-access lets the browser read any file the user can
read. That is acceptable for verifying local artifacts you just produced. It is
not acceptable in combination with browsing untrusted web pages: a malicious
page can attempt to drive the agent into reading local files and sending them
out. Keep this server for local verification. If you need general web browsing,
use a separate configuration without the flag.
Do not enable browser_run_code_unsafe workflows for verification. Screenshot
and console access are sufficient; arbitrary code execution is not needed to
look at a chart.
Housekeeping
The server writes artifacts (accessibility snapshots, screenshots) into the
working directory. Add .playwright-mcp/ to .gitignore or they land in
commits.
Do not pass a bare filename to browser_take_screenshot. A bare name like
shot.png is written to the working-directory root, which is outside the
ignored folder and shows up as an untracked file in the user's repo. Either omit
filename entirely — the server then writes into .playwright-mcp/ — or give a
path inside that folder. Verified 2026-07-25: a bare filename leaked into
git status while the snapshot beside it did not.
Troubleshooting
| Symptom |
Cause |
Fix |
Access to "file:" protocol is blocked |
Flag missing — the default blocks file:// navigation entirely |
Add --allow-unrestricted-file-access |
Browser distribution '<channel>' is not found |
No bundled browser — the selected channel is not installed on this machine |
Switch --browser to a channel that is present (msedge / chrome / firefox / webkit), or run npx playwright install <channel> |
Server reports a version like 1.62.0-alpha-… |
That is the underlying Playwright library version, not the @playwright/mcp package version |
Do not pin against what the handshake reports |
| Tools never appear at all |
Config in the wrong path or under the wrong top-level key |
Same trap as flint — see the per-host table in the flint-chart skill |
Untracked .playwright-mcp/ in git status |
Working-directory artifacts |
Gitignore it |
Anti-patterns
- Declaring an artifact done because the tool returned success. The tool
reporting OK means bytes were written, not that the picture is true.
- Trusting a batch edit's summary line. When a multi-edit call reports
"1 succeeded, 1 failed", verify which one landed by inspecting the file
before re-rendering. The visible change is often not the one that succeeded.
- One full-page screenshot for a multi-figure report. Defects hide in the
figures you did not focus.
- Verifying against sample data only. The failure mode this skill exists for
appears when real data meets the spec.
- Installing the Playwright server on a host that already has a browser
capability. Redundant dependency, extra config surface, no gain. Rung 1
before rung 2, always.
- Diagnosing an empty chart before re-capturing. JS-rendered charts draw
after load; one early screenshot is not evidence of an empty binding.
- Screenshotting without reading the console. The console usually names the
cause — a 404'd image, a failed font, a thrown spec error — while the picture
only shows the symptom.
- Fixing a data or chart-type problem with a style tweak. Recoloring a mark
that is wrong because two scales merged hides the bug instead of fixing it.
Would Revise If
Revise this skill by 2026-10-25 (90 days) or sooner if:
- The host's built-in browser tools gain or lose console-error access.
browser_console_messages is currently the main capability that justifies the
optional Playwright server at all.
- A host appears whose canvas renders HTML for the user but returns nothing
to the agent. Capability 2 in Step 1 assumes "renders" and "agent can read
it back" usually travel together. A surface that splits them would make rung 3
the common case rather than the exception, and Step 5's honesty requirement
the most load-bearing part of this skill.
@playwright/mcp changes its file:// default. The security note and the
flag table both assume navigation is blocked unless the flag is set.
@playwright/mcp ships a bundled browser by default. The troubleshooting
row about installed-Chrome-by-channel would then be wrong.
- A failure mode recurs that is not in either catalog above. The tables are
the load-bearing content; extend them rather than adding tooling.
- The general catalog stays unused across several sessions. That would mean
this skill is really chart-only in practice and the broader name overpromises —
either narrow the name back or delete the general table.
- Verification is consistently skipped by users, indicating the step is too
heavy and should collapse into the
flint-chart render step instead of
standing as its own skill.
1---2name: render-verify3description: Verify a rendered visual artifact actually says what it was supposed to say — open it, read its console errors, walk a failure catalog, and check it against the claim it was meant to carry. Works on charts, generated HTML reports, SVG, dashboards, diagrams, and any other output meant to be looked at. Use after render_chart / create_chart_view, after editing a post-Flint Vega-Lite spec, and before committing any generated HTML/SVG/PNG. Satisfied by the host's built-in browser tools or by the optional playwright MCP server.4---5
6# render-verify: look at what you rendered
7
8## Why this skill exists
9
10A visual artifact can be **technically valid and still tell the wrong story**. A
11chart with a collapsed axis, a merged color scale, or an empty data binding
12renders cleanly. So does a report whose images 404, whose text is clipped, or
13whose stylesheet never loaded. No validator catches any of it. `validate_chart`
14proves a spec is well-formed, not that the picture is true. Only looking does.
15
16This is the plugin's characteristic bug shape — see _Known failure modes_ in the
17repo docs. Every other silent failure here is a config path; this one is a
18picture.
19
20**The rule:** if you rendered it, opened it, or edited it, look at it before you
21say it is done.
22
23**Scope.** The method below — open, read the console first, walk a catalog, check
24the claim — is general. It applies to charts, generated HTML reports, SVG
25figures, dashboards, diagrams, and printable output. Charts are the
26deepest-worked case because this plugin produces them, and their catalog is the
27longest; a shorter general catalog follows it.
28
29## When to invoke
30
31**Mandatory:**
32
33- After **any post-Flint Vega-Lite edit.** The `flint-chart` skill forbids
34 sending an edited spec back to `render_chart`, so the MCP server's own
35 validation no longer protects you. You are flying without instruments.
36- Before **committing generated HTML, SVG, or PNG.** Inline specs fail silently.
37- When the artifact is **layered, faceted, multi-series, or multi-figure.** Most
38 failures below come from layer, scale, or layout interaction.
39
40**Recommended:**
41
42- After the first render of anything that will be shown to someone other than
43 the person who asked for it.
44- Whenever you changed the data binding or the page structure, not just styling.
45
46**Skip:**
47
48- Single-layer chart, small embedded data, spec unchanged since a render you
49 already looked at.
50- The user is iterating rapidly on color or title only.
51
52## The failure catalog — charts
53
54These render without error. Check each one explicitly — the list is the point of
55the skill, not the tooling.
56
57| Failure | What you see | Usual cause |
58| ---------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
59| **Empty binding** | Axes, gridlines, legend — and no marks | Data ref resolved to nothing. A chart with no data still looks like a chart. **Rule out a render race first** — see capability 5 in Step 1 |
60| **Collapsed scale** | Everything squashed into a fraction of the plot area | One layer forced `zero: true` (or a quantitative axis) into a shared scale |
61| **Merged color scale** | A mark is the wrong color for its meaning | Two layers' color scales resolved together. Fix with independent scale resolution, not by recoloring |
62| **Undefined category** | A blank, `null`, or `undefined` row/tick on a categorical axis | Mis-encoded layer contributing to a shared categorical domain |
63| **Duplicate marks** | Rows repeated, bars double-height | Missing dedup upstream — a data problem wearing a chart costume |
64| **Embedded totals** | One bar dwarfs the rest; parts look flat | An aggregate level (`all`, `Total`) charted alongside its own parts |
65| **Double-scaled units** | Percentages at 0–10000, or everything at 0.0x | A 0–100 rate tagged as `Percentage` and scaled again |
66| **Overplotting** | A solid blob instead of a distribution | Too many marks, no opacity/jitter/binning |
67| **Right on sample, wrong on real** | Looks perfect, means nothing | Verified against test rows, never against the actual dataset |
68
69## The failure catalog — any rendered artifact
70
71For generated HTML, SVG, dashboards, diagrams, and printable output. These also
72render without error, and a screenshot alone can look plausible.
73
74| Failure | What you see | Usual cause |
75| ---------------------------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
76| **Missing resource** | A broken-image icon, a blank figure slot, an unstyled block | A 404 on an image, stylesheet, font, or script. **The console names it** — this is why Step 2 reads errors first |
77| **Unstyled content** | Raw serif text, no layout, everything left-aligned | The stylesheet never loaded, or loaded after the capture |
78| **Clipped or overflowing text** | Sentences cut mid-word, labels truncated, text escaping its container | Fixed heights, `overflow: hidden`, or a font substitution that changed metrics |
79| **Font substitution** | Right words, wrong typeface; spacing subtly off | A web font failed to load and a fallback took over. Silent by design |
80| **Layout collapse** | Columns stacked, panels overlapping, huge whitespace | The captured viewport hit a responsive breakpoint you did not intend |
81| **Below-the-fold content never checked** | Everything visible looks fine | Only the viewport was captured. Scroll or capture full-page |
82| **Stale render** | Your change is not there | Viewing a cached copy, an old build output, or a different file than you edited |
83| **Placeholder survived** | Literal `TODO`, `Lorem ipsum`, `{{value}}`, `undefined`, `NaN` | A template slot never filled. Search the rendered text, not just the source |
84
85## Step 1 — pick a verification capability
86
87This skill names the **capability**, not a product. Work down this ladder and
88stop at the first rung that works. **Do not install a second MCP server for a
89job the host already does.**
90
911. **The host's own browser capability — always try this first.** If your tool
92 inventory contains anything that opens a page and returns a screenshot or a
93 page snapshot _to you_, use it. In VS Code Copilot these are the built-in
94 browser tools; they open `file://` with no flags, no browser download, and no
95 configuration, and they were verified against this plugin's own demo. This
96 rung costs nothing and has no security trade-off.
972. **The optional `playwright` MCP server — fallback.** Use when rung 1 is
98 absent, or when rung 1 lacks console-error access and the defect you are
99 chasing needs a cause rather than a symptom. **On a terminal-only agent such
100 as GitHub Copilot CLI there is no rung 1 at all** — it has no browser, so
101 this rung is the primary path, not the fallback. See _Playwright MCP setup_
102 below. It carries real costs: a browser must already be installed, `file://`
103 needs `--allow-unrestricted-file-access`, and it writes artifacts into the
104 working directory.
1053. **The human.** Ask the user to open the artifact and describe what they see,
106 or give them a specific checklist item to confirm. This is a legitimate
107 outcome, not a failure — but it must be _stated_.
108
109**Never silently skip verification.** If you reached rung 3, or if you have
110partial capability (see below), say so plainly in your report. An unverified
111chart described as verified is worse than an unverified chart.
112
113### Which capabilities you actually need
114
115"Can open HTML" is not one capability — it is five, and hosts differ in which
116they provide. Establish what you have _before_ interpreting what you see.
117
118| # | Capability | Needed for | If missing |
119| --- | ---------------------------------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------ |
120| 1 | **Open a local `file://`** | Reaching the artifact at all | Fall back to a `render_chart` PNG/SVG, or rung 3 |
121| 2 | **Agent-readable output** (screenshot or accessibility snapshot returned _to you_) | Steps 3–4 | You are on rung 3 — the human is verifying, not you |
122| 3 | **Console-error access** | Step 2 — finding the _cause_ | You can still see symptoms; say that causes were not checked |
123| 4 | **Element-scoped or scrolled capture** | Multi-figure artifacts | Verify one figure per page-load, or accept reduced confidence and say so |
124| 5 | **Wait-for / re-capture after render** | Anything JS-rendered (Vega-Lite, ECharts) | **See the false-positive warning below** |
125
126> [!WARNING]
127> **Capability 5 can manufacture a defect that isn't there.** Vega-Lite and
128> ECharts draw _after_ page load. A screenshot taken too early shows an empty
129> container — which is visually identical to the **empty binding** row in the
130> failure catalog. Before diagnosing "empty binding", re-capture at least once
131> and confirm the emptiness is stable. Diagnosing a race as a data bug sends the
132> fix upstream into a spec that was never wrong.
133
134Probe by **doing, not by asking**: attempt the action against the real artifact
135and observe the result. Tool names vary between hosts; outcomes do not.
136
137## Step 2 — open it and read the errors first
138
1391. **Open the artifact.** For local files use the canonical absolute
140 `file:///…` form.
1412. **Read the console errors before looking at the picture.** This is the check
142 that finds the cause rather than the symptom — a silently-failing inline
143 Vega-Lite spec throws to the console while still rendering a plausible-looking
144 page. With the Playwright server this is `browser_console_messages` at level
145 `error`.
1463. **Then screenshot it.**
147
148Zero console errors plus a wrong-looking artifact means a spec, data, or layout
149problem. Console errors plus a right-looking artifact means you are probably
150looking at a stale render.
151
152## Step 3 — check the picture against the catalogs
153
154Walk the chart table if it is a chart, and the general table for anything that
155is rendered as a page. Then, for multi-figure artifacts:
156
157- **Scroll each figure into view and capture it separately.** A single full-page
158 screenshot visually hides defects in unfocused figures.
159- **Check the axes have real domains** — not `[0, 0]`, not a collapsed range,
160 no `undefined` ticks.
161- **Count the marks** against what the data should produce.
162- **Search the rendered text for placeholders** — `TODO`, `undefined`, `NaN`,
163 `{{`, `Lorem`. Search what rendered, not the source that produced it.
164
165## Step 4 — check the claim, not just the render
166
167Every artifact worth verifying exists to carry a claim. For charts that is the
168Big Idea from the `chart-big-idea` skill; for a report or diagram it is whatever
169the surrounding prose asserts. **A correct render of a wrong claim is still a
170defect.**
171
172- **Verify prose claims arithmetically against the plotted or tabulated values.**
173 If the caption says "less than a fifth of the noise", compute it.
174 Order-of-magnitude overstatements in captions survive every automated check
175 there is.
176- **Re-read the claim and ask whether the picture shows it.** If the claim is
177 about a gap and the eye goes to a trend, the chart type is wrong — go back to
178 `flint-chart` §0.2, do not patch the styling.
179
180## Step 5 — report honestly
181
182State which capability you used, that you looked, and what you checked. If you
183could not verify, say that instead. Never describe an unopened render as
184verified.
185
186## Playwright MCP setup
187
188**Fallback only — rung 2 of Step 1.** Try the host's own browser capability
189first; if it can open the artifact and return a screenshot to you, you do not
190need this server. Measured against `@playwright/mcp@0.0.78`:
191
192```json
193{
194 "servers": {
195 "playwright": {
196 "type": "stdio",
197 "command": "npx",
198 "args": [
199 "-y",
200 "@playwright/mcp@0.0.78",
201 "--headless",
202 "--isolated",
203 "--browser",
204 "msedge",
205 "--allow-unrestricted-file-access"
206 ]
207 }
208 }
209}
210```
211
212Merge this **additively** into the existing server map — overwriting the file
213destroys the user's other servers, including `flint`. Same per-host path table
214as the `flint-chart` skill (`.vscode/mcp.json` for VS Code, `.mcp.json` for
215Claude Code, `.cursor/mcp.json` for Cursor, `~/.copilot/mcp-config.json` with
216key `mcpServers` for Copilot CLI).
217
218### Why each flag
219
220| Flag | Why |
221| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
222| `--headless` | No visible window; this is a verification pass, not a demo |
223| `--isolated` | No persistent browser profile — keeps the user's real session out of it |
224| `--browser msedge` | **There is no bundled browser** — Playwright drives an _installed_ one by channel. Edge ships with Windows, which is where most heirs are; the upstream default (`chrome`) is frequently absent there. Override with `chrome`, `firefox`, or `webkit` where Edge is not installed — typically Linux |
225| `--allow-unrestricted-file-access` | **Required for `file://`.** Without it navigation is blocked outright. See the security note below |
226
227### Security note — read before enabling the file-access flag
228
229`--allow-unrestricted-file-access` lets the browser read any file the user can
230read. That is acceptable for verifying local artifacts you just produced. It is
231**not** acceptable in combination with browsing untrusted web pages: a malicious
232page can attempt to drive the agent into reading local files and sending them
233out. Keep this server for local verification. If you need general web browsing,
234use a separate configuration without the flag.
235
236Do not enable `browser_run_code_unsafe` workflows for verification. Screenshot
237and console access are sufficient; arbitrary code execution is not needed to
238look at a chart.
239
240### Housekeeping
241
242The server writes artifacts (accessibility snapshots, screenshots) into the
243working directory. **Add `.playwright-mcp/` to `.gitignore`** or they land in
244commits.
245
246**Do not pass a bare `filename` to `browser_take_screenshot`.** A bare name like
247`shot.png` is written to the _working-directory root_, which is outside the
248ignored folder and shows up as an untracked file in the user's repo. Either omit
249`filename` entirely — the server then writes into `.playwright-mcp/` — or give a
250path inside that folder. Verified 2026-07-25: a bare filename leaked into
251`git status` while the snapshot beside it did not.
252
253## Troubleshooting
254
255| Symptom | Cause | Fix |
256| ----------------------------------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
257| `Access to "file:" protocol is blocked` | Flag missing — the default blocks `file://` navigation entirely | Add `--allow-unrestricted-file-access` |
258| `Browser distribution '<channel>' is not found` | No bundled browser — the selected channel is not installed on this machine | Switch `--browser` to a channel that is present (`msedge` / `chrome` / `firefox` / `webkit`), or run `npx playwright install <channel>` |
259| Server reports a version like `1.62.0-alpha-…` | That is the underlying **Playwright library** version, not the `@playwright/mcp` package version | Do not pin against what the handshake reports |
260| Tools never appear at all | Config in the wrong path or under the wrong top-level key | Same trap as `flint` — see the per-host table in the `flint-chart` skill |
261| Untracked `.playwright-mcp/` in `git status` | Working-directory artifacts | Gitignore it |
262
263## Anti-patterns
264
265- **Declaring an artifact done because the tool returned success.** The tool
266 reporting OK means bytes were written, not that the picture is true.
267- **Trusting a batch edit's summary line.** When a multi-edit call reports
268 "1 succeeded, 1 failed", verify _which_ one landed by inspecting the file
269 before re-rendering. The visible change is often not the one that succeeded.
270- **One full-page screenshot for a multi-figure report.** Defects hide in the
271 figures you did not focus.
272- **Verifying against sample data only.** The failure mode this skill exists for
273 appears when real data meets the spec.
274- **Installing the Playwright server on a host that already has a browser
275 capability.** Redundant dependency, extra config surface, no gain. Rung 1
276 before rung 2, always.
277- **Diagnosing an empty chart before re-capturing.** JS-rendered charts draw
278 after load; one early screenshot is not evidence of an empty binding.
279- **Screenshotting without reading the console.** The console usually names the
280 cause — a 404'd image, a failed font, a thrown spec error — while the picture
281 only shows the symptom.
282- **Fixing a data or chart-type problem with a style tweak.** Recoloring a mark
283 that is wrong because two scales merged hides the bug instead of fixing it.
284
285## Would Revise If
286
287Revise this skill by 2026-10-25 (90 days) or sooner if:
288
289- **The host's built-in browser tools gain or lose console-error access.**
290 `browser_console_messages` is currently the main capability that justifies the
291 optional Playwright server at all.
292- **A host appears whose canvas renders HTML for the _user_ but returns nothing
293 to the agent.** Capability 2 in Step 1 assumes "renders" and "agent can read
294 it back" usually travel together. A surface that splits them would make rung 3
295 the common case rather than the exception, and Step 5's honesty requirement
296 the most load-bearing part of this skill.
297- **`@playwright/mcp` changes its `file://` default.** The security note and the
298 flag table both assume navigation is blocked unless the flag is set.
299- **`@playwright/mcp` ships a bundled browser by default.** The troubleshooting
300 row about installed-Chrome-by-channel would then be wrong.
301- **A failure mode recurs that is not in either catalog above.** The tables are
302 the load-bearing content; extend them rather than adding tooling.
303- **The general catalog stays unused across several sessions.** That would mean
304 this skill is really chart-only in practice and the broader name overpromises —
305 either narrow the name back or delete the general table.
306- **Verification is consistently skipped by users**, indicating the step is too
307 heavy and should collapse into the `flint-chart` render step instead of
308 standing as its own skill.