wp-abilities-verify
wordpress/agent-skills
Verify WordPress plugin Abilities API registrations for correctness, permissions, and schema compliance.
What is wp-abilities-verify?
Validates WordPress plugin ability annotations against actual callback behavior, catching critical mismatches like readonly abilities that write to the database. Runs in static mode (source inspection only) or runtime mode (live environment execution) to verify permissions, schemas, audit documents, and idempotency claims.
- Enumerates registered abilities via static source inspection or runtime wp_get_abilities()
- Performs adversarial annotation correctness checks: detects readonly abilities that actually write, destructive claims that delete, and idempotent violations
- Validates permission callbacks against six standard shapes and confirms permission roundtrips against real users (runtime mode)
- Lints input schemas for required fields, descriptions, additionalProperties declarations, and static-constant defaults
- Validates audit documents produced by wp-abilities-audit against canonical schema
- Flags non-standard error codes and produces structured markdown reports with per-ability verdicts
How to install wp-abilities-verify
npx skills add https://github.com/wordpress/agent-skills --skill wp-abilities-verify- wp-project-triage must have been run on the plugin
- Plugin must have at least one wp_register_ability() call in source
- For runtime mode: a runnable environment (wp-env, Docker-based dev stack, or equivalent) and the plugin's AGENTS.md with env-up command
How to use wp-abilities-verify
- 1.Run the skill with the plugin checkout path and choose static or runtime mode
- 2.For runtime mode, provide the env-up command from the plugin's AGENTS.md (e.g., npm run wp-env start)
- 3.Optionally provide an audit document path to cross-validate against registered abilities
- 4.Specify the report output path (typically your vault)
- 5.Review the structured markdown report: check the top-line status (PASS/WARN/FAIL) and examine the annotation correctness table for any readonly-writes or other mismatches
- 6.For false positives, add // verify-ignore: <annotation> -- <reason> comments in the callback source and re-run
Use cases
- Pre-landing verification: validate ability annotations before a plugin PR merges to catch security mismatches
- Regression detection: health-check an already-shipped plugin to catch refactors that turned readonly abilities into writing ones
- Audit validation: confirm an audit document's accuracy and completeness before handing it to an implementer
- Permission gate review: verify permission callbacks match declared capabilities and work correctly with real user roles
- Idempotency verification: runtime mode executes twin invocations to detect unintended side effects on idempotent abilities
- WordPress plugin developers registering Abilities API endpoints
- Security reviewers validating plugin capability annotations before merge
- DevOps/QA engineers running health checks on shipped plugins
- Implementers validating audit documents before building agent integrations
wp-abilities-verify FAQ
Static mode inspects source code only—no environment needed—and catches obvious-shape violations like readonly abilities with database writes. Runtime mode requires a running environment and additionally executes each ability with curated inputs, confirms permission roundtrips against real users, and runs twin-invocation checks on idempotent abilities to catch bootstrap-order and side-effect issues.
It means the skill reads the callback body and checks whether what it actually does matches what the annotation claims. For example, a readonly: true ability that calls $wpdb->update() is a lie—agents plan actions based on annotations, so this mismatch is a security and UX disaster.
Yes. Add an inline // verify-ignore: <annotation> -- <reason> comment in the callback source code. Document why the suppression is legitimate, then re-run the verification.
The skill returns a clear 'no abilities registered' report, not an empty PASS. This prevents silent misses on plugins that should have abilities but don't.
For high-stakes plugins, yes. Static mode catches obvious violations, but runtime mode catches bootstrap-order, permission-roundtrip, and idempotency issues that static inspection cannot detect.
Full instructions (SKILL.md)
Source of truth, from wordpress/agent-skills.
name: wp-abilities-verify description: "Verify a WordPress plugin's Abilities API registrations: enumerate abilities, check that callback behavior matches each annotation's claim (the adversarial readonly-but-writes detection), validate permissions and schemas, and validate audit documents produced by wp-abilities-audit." compatibility: "Targets WordPress 7.0+ plugins (PHP 7.4.0+). Requires a runnable environment (wp-env, docker-based dev stack, or equivalent) for runtime mode; static mode runs entirely from the plugin checkout with no env. Filesystem-based agent with bash + node."
WP Abilities Verify
Verify a WordPress plugin's Abilities API registrations. The
centerpiece is the adversarial annotation correctness check: a
readonly: true ability that actually writes (via $wpdb->update,
update_option, a non-GET delegate, etc.) is a security and UX
disaster because agents plan actions on the basis of the annotations
they introspect. This skill catches those lies by reading the callback
body and comparing what it does against what the annotation claims.
The skill also validates audit docs produced by wp-abilities-audit,
checks permission gates and schema hygiene, and optionally executes
each ability against a live environment.
When to use
- After abilities have been registered in a plugin but before a PR lands.
- As a health-check on an already-shipped plugin (catch regressions where a refactor turned a readonly ability into a writing one).
- To validate an audit document before handing it to an implementer.
Two modes
- Static mode — runs from the plugin checkout. No env. Enumerates via source inspection, runs the adversarial correctness check, runs schema and permission lints, and validates audit docs.
- Runtime mode — requires a running env. Does everything static
does PLUS:
wp_get_abilities()for authoritative enumeration, executes each ability with curated inputs, confirms permission roundtrip against real users, and runs a twin-invocation heuristic onidempotent: trueabilities to flag candidates for review (return-value equality is a signal, not a verdict — core defines idempotent as "no additional effect on the environment").
Both modes produce the same structured report format.
A static-mode PASS means "no obvious-shape violations," not "verified
write-free." For high-stakes plugins, run runtime mode before landing
— it catches bootstrap-order, permission-roundtrip, and idempotency
issues that static can't. See references/annotation-correctness.md
for the static blind spots.
Inputs required
- Plugin checkout path — working tree to verify.
- Mode —
staticorruntime. Default to static if unspecified. - (Runtime only) Env-up command — read the plugin's
AGENTS.md. Common patterns:npm run wp-env start,npx wp-env start, or a composer-based bring-up. Plugin families with their own dev tooling will document their own command. Do NOT assumenpm run wp-envworks. - (Optional) Audit doc path — enables cross-checks between the audit and the registered abilities, and validates the audit itself.
- Report output path — explicit path, typically the user's vault.
Prerequisites
wp-project-triagehas been run on the plugin.- The plugin has at least one registered ability in source. Zero hits
on
wp_register_ability(→ return a clear "no abilities registered" report, not an empty PASS.
Procedure
1. (If audit provided) Validate the audit doc
Read references/audit-schema-validation.md. Validate the audit
against the canonical schema owned by wp-abilities-audit. Surface
missing required fields, multiple reference_ability: true, and
backing: null entries that aren't paired with a surfaced_gaps
entry. backing: null alone is WARN (intentional gap output), not
FAIL.
2. Enumerate abilities statically
Read references/static-enumeration.md. Find each
wp_register_ability( call, extract the name, the annotation block,
and the execute-callback location. Use a multi-line tool (rg --multiline --pcre2) — the canonical formatting splits the call
across lines. Record each ability's source-file + line + annotations +
callback byte range.
3. (Runtime only) Enumerate via REST + wp-cli
Read references/runtime-harness.md. Bring the env up using the
command from AGENTS.md, then enumerate via wp_get_abilities() over
wp-cli and cross-check against the static inventory. Source-only →
FAIL (registration not firing). Runtime-only → WARN (dynamic
registration path).
4. Annotation correctness (the adversarial core)
Read references/annotation-correctness.md. Read each callback body
and verify it matches the annotation claim:
readonly: true→ callback must not write to the database, the options table, post / user / term / comment data, the filesystem, cron, or via non-GET HTTP / REST delegates.destructive: false→ callback must not delete, refund, void, cancel, or trash.idempotent: true→ repeated calls with the same input have no additional effect on the environment (per theidempotentannotation's docblock inclass-wp-ability.php). Static catches counter writes and per-call cron schedules; runtime adds a twin-invocation heuristic for visible state changes.
The reference lists common write patterns as a starting set, not a checklist — plugin vocabularies vary, and the agent extends with verbs specific to the plugin under verification.
False positives get suppressed via an inline // verify-ignore: <annotation> -- <reason> comment.
5. Permission roundtrip
Read references/permission-roundtrip.md. Static: classify each
permission_callback against the six shapes (preferred Shape A
current_user_can(...); FAIL on Shape B-bad WP_REST_Request
patterns or Shape E literal true). Runtime: anon and subscriber
denied; admin allowed (unless deliberately public). When an audit was
provided, cross-check the registered cap against the audit's declared
gate.
6. Schema lints
Read references/schema-lints.md. Six small principles applied to
each ability's input_schema: object schemas declare
additionalProperties; required fields have descriptions; enums
non-empty; no $ref; defaults are statically constant (including
(object) array()); reference abilities have no required inputs.
Cross-reference ../wp-abilities-api/references/input-schema-gotchas.md
for the four runtime gotchas (defaults not injected on the
property-level path, pagination key drift, empty() on string IDs,
direct vs indirect invocation strictness).
7. Error-code vocabulary
Cross-reference ../wp-abilities-api/references/error-code-vocabulary.md.
Inspect each callback's WP_Error returns; non-vocabulary codes →
WARN.
Verification
The run produces a structured markdown report at the user-specified path:
---
Last updated: <YYYY-MM-DD HH:MM>
---
# <Plugin> Abilities Verification — <Static|Runtime> Mode
## Status: <PASS|WARN|FAIL>
## Audit doc validation (if provided)
## Static inventory
## Annotation correctness
| Ability | Claim | Result | Evidence |
|---|---|---|---|
## Permission gates
## Schema lints
## Error-code vocabulary
Every ability is OK, WARN, or FAIL. A single FAIL → top-line FAIL; WARNs without FAILs → WARN; otherwise PASS.
Failure modes / debugging
- Env not reachable (runtime) — env-up failed or Docker isn't
running. Re-run
wp-project-triage, then fix the env. Don't fall back silently to static without noting it in the report. - No abilities in source — return a clear "nothing to verify" report.
- Audit schema mismatch — point at
references/audit-schema-validation.md; don't auto-fix the audit. - False positive on readonly-writes — see the
// verify-ignoremechanism inreferences/annotation-correctness.md. Document why each suppression is legitimate. - Runtime enumeration smaller than static — registration hook isn't firing. Check init hook timing, activation state, autoloader order.
Escalation
- Recurring legitimate pattern that trips the adversarial check across
multiple plugins → propose adding it to the suppression guidance in
annotation-correctness.md. Don't broaden the candidate-pattern list speculatively. - Audit-schema validator rejects a legitimate audit → the canonical
schema in
../wp-abilities-audit/references/audit-schema.mdhas evolved. Updatereferences/audit-schema-validation.mdto match.
Out of scope
Token-budget measurement is a separate verification axis — an
annotation-clean, schema-clean, runtime-passing ability set can still
be unshippable if its tools/list form burns through an agent's
context budget. That axis is tracked separately. Do not aggregate
manual or external measurement into this skill's PASS / FAIL verdict.
Related skills
More from wordpress/agent-skills and the wider catalog.

wp-block-development
Develop WordPress Gutenberg blocks with block.json, registration, rendering, and deprecation workflows.

wp-block-themes
Develop WordPress block themes: theme.json, templates, patterns, and Site Editor debugging.

wp-interactivity-api
Build and debug WordPress Interactivity API features with data-wp-* directives, store management, and hydration.

wp-patterns
Create and manage WordPress block patterns for starter pages, templates, and layouts with design tokens and accessibility.

wp-performance
Diagnose and optimize WordPress performance using WP-CLI profiling, Query Monitor, and database analysis.

wp-phpstan
Configure and fix PHPStan static analysis in WordPress projects with proper typing and baseline management.