agentleFS
jjanczurjjanczur/tyran/skills/browser-check/SKILL.md

browser-check

Skill81 starsChanged 4 months agoApache-2.0View on GitHub

Drive a real browser and come back with a MEASUREMENT rather than an impression - console errors and >=400 responses as counts, computed styles as JSON when appearance is disputed. Use when work touches UI, when a review must verify one, or when fidelity-gate asks for its measurement.

1 other project uses a version of this.

Adopted by

Most recently taken up by

  • Other versions1 project uses a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 1

    1. antsteyer/claude-skills★ 0same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository15 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

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

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

    Wait for a *condition*: a response, a selector, a network-idle state, a font ready promise.

    line 33
  2. Distinctive:

    every in-page link, resolved once and cached by URL

    line 54

≈ “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.

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

Browser check — proving a UI works, in numbers

Three places in this plugin order a browser pass — the conductor's quality gates, the reviewer, the implementer — and fidelity-gate asks for computed styles on top. None of them said how. This is the how, and it exists so that "I checked it in the browser" stops being a sentence and starts being a counter someone else can re-run.

A browser pass is a measurement. It returns numbers: pages visited, links resolved, console errors, failed responses. Looks fine, renders correctly and no obvious issues are REJECTED by the evidence contract exactly like a test report with no output, and for the same reason — nothing in them can be wrong.

Before you promise a run

  1. The browser exists. npx playwright --version, and install only chromium (npx playwright install chromium) — a full browser install is several GB for two extra engines nobody asked for.
  2. The server is up and SERVING WHAT YOU THINK. Fetch one known URL and check the status before automating anything. A dev server that is still compiling, or is serving a stale build on a port you forgot to kill, produces a page of failures that have nothing to do with your change.
  3. Build first when the target is a static site. Testing the dev server and shipping the build tests two different programs.

Waits are deterministic — never a sleep

Wait for a condition: a response, a selector, a network-idle state, a font ready promise. waitForTimeout is a guess that is simultaneously too long on your machine and too short in CI, and the failures it produces are indistinguishable from real ones. The only defensible fixed wait is settling an animation you cannot observe, and it says so in a comment.

Warm the routes before a batch run. The first request to a route compiles it; a cold compile times out and reads as a defect in the page. Hitting every route once before measuring costs one pass and removes a whole class of false finding.

What you collect, and what you return

Subscribe before you navigate — listeners attached after the first goto miss everything that page already did:

  • console events of type error
  • pageerror — uncaught exceptions, which are NOT console errors and are routinely missed by checking only the first
  • response with status >= 400, including the ones fired by the page's own fetches, which no amount of clicking will reveal
  • every in-page link, resolved once and cached by URL

Return them as counts plus the first few offenders, then a single verdict line. A pass with 0 console errors is a fact; "the console was clean" is a recollection.

When the UI claims to change something the SERVER acts on — a mapping, a setting, a value the next request depends on — a clean console and a 2xx are not proof it arrived. The evidence has to follow the value to what got STORED, not stop at what got RENDERED: capture the request body you actually sent, or read the value back with a second request or a reload, and assert on THAT. This is not hypothetical. A column-mapping override shipped with a perfect browser pass — 15/15 columns visible, 0 console errors, the mapping visibly changed by hand — while the server re-derived the source type from the uploaded bytes and discarded the mapping, answering 201 either way. Only a reviewer reading the server route caught it; nothing in the browser measurement could have, because it never inspected what the server persisted.

Selectors that do not go blind

Anchor on what the user sees — a role, a label, the text — not on a container class or an nth-child. This is not a style preference. A selector scoped to the markup it was written against keeps passing while silently checking LESS of the page as the page grows, and it reports the narrowed number as success. That has already happened in this repo: a link check named two regions of one framework's chrome, and went from checking every link to checking half of them on the day a page was added outside that chrome — with no failure anywhere.

So: assert the COUNT you expected as well as the condition. 24 links checked, 0 broken catches the regression that 0 broken cannot.

When the disagreement is about appearance

Settle it with getComputedStyle, dumped to JSON, compared against the inventory. Never by looking, and never by asking a model to look:

await page.$$eval(SELECTORS, (els) => els.map((el) => {
  const s = getComputedStyle(el);
  return { text: el.textContent.trim(), fontSize: s.fontSize, fontWeight: s.fontWeight, color: s.color };
}));

Two rules that keep this a measurement:

  • Assert the element's text alongside its geometry. A structural selector with no text assertion measures the wrong element when the markup is renumbered, and reports a confident wrong number instead of a loud miss.
  • A zero-size box is a failure, not a pass. An element that renders with no width, or a glyph that inherits fill: none, is present in the DOM and invisible on the screen. Check the bounding box whenever you check anything visual, or the check passes on a page nobody can read.

For a frozen reference, this step belongs to fidelity-gate, which owns the inventory, the relics list and the verdict format. Do not invent a second one.

Artefacts and cleanup

Screenshots, JSON dumps and logs go under .tyran/, never /tmp — they are evidence for a report, and evidence a colleague cannot open is not evidence. Name them for the run, not screenshot.png.

End the way you started: close the browser, and stop the server you started with SIGTERM so it can release its port. kill -9 leaves the port held and the next run fails for a reason that has nothing to do with the code.

The report

PAGES 13 · LINKS 24/24 · CONSOLE ERRORS 0 · PAGE ERRORS 0 · HTTP>=400 0
BROWSER PASS: OK

Then the failures, if any, with the URL that produced each. State plainly what you did NOT drive — the viewport you skipped, the flow behind a login, the browser you do not have. An unchecked area named in the report is a decision for the conductor; an unchecked area left out of it is a claim.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.