Platform
Verification
Verification turns an agent's test claims into evidence a reviewer or auditor can trust: tests tied to each acceptance criterion, CI results checked against the agent's, and invariants that every later change must keep.
The agent does the testing, and Planwright decides what counts. Reports are matched to the agent's commit, missing or removed tests are flagged, and every override a human makes is written to the audit chain.
What verification is
ConceptAn agent saying "tests pass" is a claim. Verification turns it into evidence: checked-in tests tied to each criterion, raw reports matched to the commit, and your CI as a second opinion.
Every finished objective should leave behind tests that keep guarding it after it ships. Planwright asks agents to write those tests, tags each one with the criterion or invariant it guards, and checks what the agent reports against what your CI reports for the same commit. When the evidence is missing, contradictory or shrinking, acceptance waits for a human, and the human's decision goes on the audit chain.
Planwright never runs your code. Agents run tests on their own machines under a set protocol, and your CI provides the independent result.
A test for every acceptance criterion
EvidenceEach criterion gets a stable id, and the test that proves it carries a marker naming the objective and that id.
When an agent first claims an objective, each acceptance criterion gets an id (ac_1, ac_2, …) that never changes, and a marker that adds the objective's id prefix. The agent writes a checked-in test whose title includes the marker, for example "refuses a blank note [AC:3f2a91c0:ac_3]", and submits the raw Playwright JSON or JUnit XML report. Every objective has an ac_1, so a result counts only toward the objective its marker names, even when one report holds the whole suite. Criteria are tagged as a behavior (what the change does) or an error case (what it must do when something goes wrong, like an expired token or bad input), so failure paths get tests too. A criterion the agent can't test is listed as such and left for the reviewer to check by hand.
Older tests tagged with a bare marker like [AC:ac_3] count only for the objective that first reported them. Tests for objectives that shipped before markers existed can be linked later: an agent adds the qualified marker, and the link waits for approval on the Verification page. An objective's own tests need no approval: once the objective is accepted, the tests its run reported are linked automatically, and the audit log records which run reported each one.
Agent results and CI results
EvidenceTwo sources, kept apart, so a reviewer can see when they disagree.
Agent-executed
What the agent reports through planwright_submit_test_run. The raw reports must come from the agent's own commit, and they're checked against the tests the run was asked to run.
CI-verified
Check runs and workflow runs from your GitHub CI on the agent's commit, or on a later commit pushed on top of it. Test reports in workflow artifacts (JUnit XML or Playwright JSON) give per-test results. This needs the GitHub App's Actions: read permission; without it, CI evidence is only an overall pass or fail.
If the two disagree, acceptance is blocked at Enforce. A reviewer who has looked at both can accept anyway with a reason, which is audited. A CI re-run that agrees with the agent clears the block without an override.
Invariants
ConceptStatements every change must keep true, each guarded by tests and scoped to the code it covers.
An invariant is one line, such as "Audit records are never updated or deleted", with a permanent key like audit-append-only. Tests whose titles carry [INV:audit-append-only] guard it, once a human approves the link. Its scope is a set of path globs. When a run's diff touches a file in scope, the invariant's guarding tests must have passed in that run. An invariant with no scope is never checked against diffs. Agents propose new invariants, drawn from your context files or from the criteria of finished objectives: the agent that built an objective judges each of its criteria when it hands the work off, and criteria worded like rules come back in later sessions too. A human approves every proposal before it applies.
A failing invariant can't be overridden at acceptance. The only way past it is an exemption that waives that invariant for the objective.
Verification levels
SettingOne level per project decides whether verification work happens and whether it blocks acceptance.
Off
Agents write tests at their discretion and report their own results. Nothing is checked: no invariant checks, CI comparison or verification tools.
Observe
Agents do the full verification work, and results show on the Verification page and in review. Anything that would block at Enforce appears as a warning instead.
Enforce
Failing invariants, agent/CI disagreements and removed tests block acceptance until a human resolves them. The default for new workspaces.
Strict
Meant to add tests written, shown failing and locked before any code. Those checks haven't shipped yet, so Strict currently behaves like Enforce.
The workspace sets the default and a project can override it. Projects created before levels existed start at Off and get a one-time prompt to turn verification on. Any member except a viewer can change a level, and every change is audited.
Turning verification on
SettingSwitching a project from Off to Observe starts a one-time backlog for your agents, then changes how each new objective is verified. The Levels & exemptions tab shows how big that backlog is for your project.
The backlog
Testable criteria of accepted objectives with no linked test (your agent looks for existing tests that prove them and adds a marker), criteria worded like rules (never, always, must not) and context files to read for invariants, and a .planwright/verify.yml if the project has none.
Who does it
Your own coding agent. Planwright hands it a batch when a session starts and tells it to do the work after whatever you asked for, or sooner if you ask. Nothing runs on Planwright or in your CI, and agents never run your full suite. Working through it costs agent time and tokens in those sessions, so a large backlog takes several sessions.
What you review
Proposed invariants and every link the agent makes between an existing test and a criterion or invariant, each with its reasoning. Nothing counts as evidence until a person approves it, so the backlog also adds to your review queue.
What changes after
Agents tag the tests they write with each criterion's marker, run them with the commands in verify.yml, and keep the project's invariants in mind. Your CI's results are compared with the agent's. At Observe all of this shows as warnings in review and never blocks acceptance.
Turning it off
Set the level back to Off on the same tab. Agents stop getting the backlog and the verification tools, and nothing already recorded is deleted.
There's no time estimate for finishing the backlog: it depends on how often your agents run and how quickly your team reviews. Start at Observe to see what verification finds before moving to Enforce, where it blocks acceptance.
Exemptions
SettingLower the level for one objective, or waive specific invariants, with a reason.
Some objectives can't meet the project's level, like a spike or a change to code with no test harness yet. A member can set an exemption on the objective directly, and it applies at once. An agent can request one, but the stricter level stays in force until a human approves the request. An exemption only ever lowers the level or waives invariants, never raises them, and every request and decision is audited with who made it.
.planwright/verify.yml
ProtocolThe test commands agents are handed, checked into your repo and approved by a human.
verify.yml tells Planwright how to run a given set of tests and where the reports land. At claim, Planwright fills in the markers the run needs, the objective's criteria plus any invariants it touches, and hands the agent the exact commands. The agent runs them on a clean checkout of its commit and submits the raw reports. Selected tests missing from the reports need the reviewer's approval note.
version: 1
setup: pnpm install --frozen-lockfile
run: pnpm vitest run -t "{grep}" --reporter=junit --outputFile=reports/junit.xml
reports:
- path: reports/junit.xml
format: junit- setup
- Optional. Runs once before the tests.
- run
- Required. Must contain {grep} (a regex of the markers) or {markers} (a space-separated list).
- files
- Optional. Runs whole test files: must contain {files}, where Planwright puts the test files the test-impact index selected. Write its report to its own path under reports.
- reports
- Required. Paths and formats: junit, playwright, lcov, cobertura or jacoco. At least one must be junit or playwright.
- coverage
- Optional. Measures one test file for the test-impact index: must contain {file}, and writes a report listed under reports as lcov, cobertura or jacoco.
- coverage_noise
- Optional, default 0.5. A source file covered by more than this share of the measured test files (a db client, config, a logger) is left out of every mapping. Applies once five test files are measured.
- full
- Optional. The whole suite, used only to generate a CI workflow. Never handed to an agent.
Planwright only uses the latest approved version. An agent can draft or change the file as part of an objective, and accepting that objective approves it. A human's commit is approved when it lands on the default branch. Changing an approved file needs an approval note at acceptance. If a report from the commands finds no tests, or a command fails to start, agents are told the commands may be out of date and to fix them.
Starter kits for JS/TS, Python and Go →Test-impact index
SelectionWhich source files each test file covers, so a change runs every test that can catch a break in it, tagged or not.
With a coverage command in verify.yml, agents measure test files one at a time and Planwright stores the source files each one covered, with the commit it was measured on and the run that measured it. A run measures only the test files its change adds or modifies, the files holding its selected tests that haven't been measured yet, and mappings its diff makes due: the test file changed, or the diff touches a file the mapping covers or one in the same directory. Never the whole suite. At record_diff, every test file whose mapping covers a changed file joins the run's selection and runs through the files command. The review drawer lists each added test file with where its coverage came from, this run or an earlier one, and the changed files no recorded coverage includes, without asking anyone to run the full suite for them. Each invariant also gets a derived scope, the coverage of its [INV:] test files, and diffs are matched against it as well as its hand-written globs.
The coverage that narrows a selection is measured by agents, so the reviewer always sees whether this same run measured it, an earlier run did, or it came from a seed. In an existing repo the index starts empty and fills in as agents work. To fill it on day one, Suite health offers a seed script built from verify.yml and your known test files: you run it with your Planwright token, it measures every test file once and uploads each report, and a test file whose coverage command fails is reported and skipped. It's effectively a full-suite run, so it's yours to run; agents are never asked to.
No silent test removal
GuardAn agent can pass a suite by trimming it. Planwright catches existing tests that were deleted, skipped or renamed.
Planwright reads the run's whole diff from GitHub rather than trusting the agent's own account of it, and flags existing tests the run removed or skipped. Moving a test to another file isn't a removal. A rename blocks only when the old title guarded a criterion or an invariant, since the link goes with it. At Enforce, flagged tests block acceptance until the reviewer approves them with a note, so the suite only shrinks on purpose.
The Verification page
PlacementOne page per project for what the tests prove and the invariants every change must keep.
Suite health
A calendar of the last 26 weeks of test reports, one square per day: blue when they passed, red when any failed, solid when the full suite ran and light when only an agent's selected tests did. It shows when the full suite last ran, so how often your CI runs it is visible rather than silent, and lists every known test by file, with filters for failing, flaky, quarantined, unlinked and long-unrun ones. A project with no CI configuration says it has no independent test run and offers a GitHub Actions workflow, generated from verify.yml, for you to commit. The page opens here, since every other tab's evidence is only as fresh as the runs behind it.
Acceptance criteria
Every criterion of a Done or Released objective and the test that last verified it: guarded, failing, stale (no result in 30 days), unguarded or non-testable. Each objective is one row with a status bar and its problem counts; open it to see its criteria, problems first. Objectives that need you come first (a failing criterion, one gone stale in the last 14 days, or an unguarded one accepted in the last 30), then the rest worst first, 25 at a time. Fully guarded objectives fold into one line. Click a status, pick an initiative, or search to narrow the list. The Evidence filter keeps criteria whose latest test result came from your CI, or only from an agent's own report. Group by switches the rows between objectives, guarding test files (what each test protects, flagging one test guarding three or more criteria) and initiatives.
Invariants
Each invariant with its scope, approved guarding tests and latest results. Below that: proposals waiting for review, pending test links, and tests whose markers name no invariant.
Test markers
Which tests count as evidence, through the [AC:] and [INV:] markers in their titles. Three sections: invariants and completed objectives' criteria that no approved marked test proves yet, with a prompt that has an agent mark the tests you already have; markers agents added to existing tests, each with the agent's reason, waiting for you to approve or reject; and the tests with no marker at all, which still run but don't count as evidence.
Levels & exemptions
The project's level and whether it inherits the workspace default, plus every exemption requested or set on its objectives, with pending requests to decide. While verification is off, the page opens here and shows what turning it on would hand your agents.
The review drawer shows the same evidence per objective. It shows test evidence only when something needs attention, alongside Code Signals.
Continue reading
verify.yml Starter Kits →
Working test commands, marker conventions and a CI workflow for JS/TS, Python and Go.
Review Agent Output →
How to weigh test evidence and Code Signals when deciding accept or reject.
GitHub Integration →
The GitHub App that delivers your CI results to Planwright.
Audit Chain Health →
Where level changes, exemptions and overrides are recorded, and how to check the chain.