Generated banner for Wp Abilities Verify
Generated logo for Wp Abilities Verify

Wp Abilities Verify

WordPressOfficialPublished by WordPress

  • Skill
  • Review and audit
  • Software development
  • GPL-2.0-or-later
  • No issues found

From the author

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.
— the description by WordPress

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

wp-abilities-verify is a tool for auditing WordPress plugin Abilities API registrations. It performs static analysis and optional runtime verification to ensure that the code's behavior matches its declared annotations. The skill identifies discrepancies where a readonly-annotated ability performs write operations, validates input schemas, checks permission gates, and verifies audit documentation produced by related tools.

What it does

  • Performs adversarial annotation correctness checks to detect hidden write operations in readonly abilities.
  • Validates plugin audit documents against canonical schemas.
  • Enforces schema hygiene and permission gate consistency for registered abilities.
  • Executes abilities in a runtime environment to confirm permission roundtrips and idempotency.
  • Generates a structured markdown report detailing status, inventory, and identified issues.
  • Supports suppression of false positives via inline code comments.

When to use it

  • Before merging pull requests for plugins using the Abilities API.
  • To perform health checks on existing plugins to catch regressions.
  • To validate audit documentation before sharing it with developers.
  • When you need to confirm that ability annotations accurately reflect the underlying code behavior.

Advantages

  • Prevents security and UX issues caused by misleading ability annotations.
  • Provides both static and runtime verification modes for flexible analysis.
  • Ensures consistency between plugin source code and audit documentation.
  • Automates the detection of common write patterns that violate readonly claims.

Usage examples

“Verify the abilities in the plugin located at /var/www/html/wp-content/plugins/my-plugin using static mode.”
The agent inspects the plugin source code, checks annotation correctness, validates schemas, and outputs a markdown report to the specified path.
“Run a runtime verification for the plugin in /app/plugins/example-plugin using the environment command npm run wp-env start.”
The agent brings up the environment, performs runtime enumeration, executes abilities to check permission roundtrips, and generates a comprehensive verification report.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/wordpress/wp-abilities-verify/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip wp-abilities-verify.zip -d .agents/skills

Documentation by WordPress

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 on idempotent: true abilities 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

  1. Plugin checkout path — working tree to verify.

  2. Mode — static or runtime. Default to static if unspecified.

  3. (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 assume npm run wp-env works.

  4. (Optional) Audit doc path — enables cross-checks between the audit and the registered abilities, and validates the audit itself.

  5. Report output path — explicit path, typically the user's vault.

Prerequisites

  • wp-project-triage has 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 the idempotent annotation's docblock in class-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-ignore mechanism in references/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.md has evolved. Update references/audit-schema-validation.md to 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.

Files

references/runtime-harness.md

Runtime Harness

The runtime-mode procedure. Everything static-mode does, plus six canonical checks that need a live wp_get_abilities() call.

Static mode catches structural problems (annotation lies, schema lint failures, audit mismatches). Runtime mode catches the class of bug that only surfaces against a booted WordPress: missing constructor arguments, bootstrap-ordering issues, schema-validator paths, capability-roundtrip failures, and idempotency violations at the response-byte level.

Harness rule: stop on first fatal

If any step below produces a PHP fatal, STOP. Later steps won't produce meaningful output. Capture the failure, escalate to the plugin's implementer to fix, then re-run from step 1.

A WP_Error return is acceptable — any <plugin>_* or upstream-prefixed error means the execute callback handled the error path gracefully. Only PHP fatals block.

Step 0 — identify the env-up command

Read the plugin's AGENTS.md for the canonical env bring-up command. Do NOT assume npm run wp-env start works for every plugin. Common patterns seen in real plugin trees:

  • npm run wp-env start — projects using @wordpress/env with a checked-in .wp-env.json.

  • npx wp-env start — projects using @wordpress/env without a custom npm script wrapper.

  • composer install && composer test-php --setup-only — package-local test bootstraps that don't run a full WordPress install.

  • docker-compose up -d — plugin-specific dev Docker stacks.

Plugin families with their own dev tooling will have their own bring-up command in AGENTS.md; follow it as documented.

If AGENTS.md doesn't document it, ask the user rather than guessing. Record the env-up command + the corresponding wp-cli invocation (e.g. npx wp-env run cli wp) and use them uniformly for the rest of the harness.

In this file, <env-cli> is shorthand for whatever wp-cli invocation the plugin uses.

Step 1 — bring up the env and sanity-check

<env-up-command>
<env-cli> wp core version
<env-cli> wp plugin list --status=active
<env-cli> wp eval 'var_export( function_exists( "wp_get_abilities" ) );'

Confirm:

  • WordPress version >= 6.9 (Abilities API available in core).

  • The plugin being verified is active.

  • wp_get_abilities exists (true if WP >= 6.9, else the Abilities API feature plugin/package must be active).

Any "no" answer halts the harness.

Check 1 — ability names match source-expected list

Enumerate runtime abilities and diff against the static inventory from static-enumeration.md:

<env-cli> wp --user=admin eval '
$names = array_filter(
    array_keys( (array) wp_get_abilities() ),
    function ( $n ) {
        return strpos( $n, "<plugin-slug>/" ) === 0;
    }
);
sort( $names );
echo "count=" . count( $names ) . PHP_EOL;
echo implode( PHP_EOL, $names ) . PHP_EOL;
'

Compare against the static inventory:

  • Source contains ability, runtime missing → FAIL. Registration hook isn't firing; check init hook timing and plugin activation.

  • Runtime contains ability, source missing → WARN. Dynamic registration path the enumerator couldn't follow. Document but don't block.

  • Counts match → OK.

Check 2 — annotations read back as declared

<env-cli> wp --user=admin eval '
$names = array_filter(
    array_keys( (array) wp_get_abilities() ),
    function ( $n ) {
        return strpos( $n, "<plugin-slug>/" ) === 0;
    }
);
sort( $names );
foreach ( $names as $name ) {
    $a = wp_get_ability( $name );
    $m = $a->get_meta();
    printf(
        "%s | readonly=%s | destructive=%s | idempotent=%s | category=%s" . PHP_EOL,
        $name,
        var_export( $m["annotations"]["readonly"], true ),
        var_export( $m["annotations"]["destructive"], true ),
        var_export( $m["annotations"]["idempotent"], true ),
        $a->get_category()
    );
}
'

Cross-reference each annotation against the audit's declared value (if an audit was provided) AND against the static inventory's declared value. Mismatch on either axis → FAIL.

This check complements the static adversarial check from annotation-correctness.md: static checks the callback's actual behavior; runtime checks what the registration hook resolved to at boot time. Both must agree for the annotations to be trustworthy.

Check 3 — each read ability's execute() behaves as the contract claims

Two verification levels. The smoke level catches bootstrap and gross-error regressions; the high-confidence level is the one that actually exercises the ability against the data shape it will see in production. Run both when the audit doc provides seed_data_needs; run the smoke level alone when it doesn't.

Level 1 — smoke execution (synthetic inputs)

Confirm each read returns OK or a vocabulary WP_Error. Catches PHP fatals, un-bootstrapped services, registration failures.

<env-cli> wp --user=admin eval '
$reads = array(
    "<plugin-slug>/<read-ability-1>",
    "<plugin-slug>/<read-ability-2>",
    // ...
);
foreach ( $reads as $name ) {
    $r = wp_get_ability( $name )->execute();
    echo $name . ": " . ( is_wp_error( $r ) ? "WP_Error(" . $r->get_error_code() . ")" : "OK" ) . PHP_EOL;
}
'

Acceptable outcomes:

  • OK — the ability returned without error.

  • WP_Error(<plugin>_not_initialized) — bootstrap guard fired (e.g. un-bootstrapped service). Happy error path.

  • WP_Error(<plugin>_<resource>_data_unavailable) — transient backend error. Acceptable.

  • WP_Error(<upstream_code>) — upstream third-party error bubbled through. Document, don't block.

Unacceptable:

  • PHP fatal → stop the harness.

  • WP_Error with a non-vocabulary code → WARN. Cross-reference ../../wp-abilities-api/references/error-code-vocabulary.md.

Abilities with required input get invoked separately with a synthetic-but-plausible value:

<env-cli> wp --user=admin eval '
$r = wp_get_ability( "<plugin>/<ability-with-required-input>" )
    ->execute( array( "<field>" => "<synthetic-id>" ) );
echo "<ability>: " . ( is_wp_error( $r ) ? "WP_Error(" . $r->get_error_code() . ")" : "OK" ) . PHP_EOL;
'

A synthetic ID on a fresh install typically triggers <plugin>_<resource>_data_unavailable or an upstream-equivalent code. Both are acceptable for Level 1 — they mean "ability dispatched cleanly, the backing reported no data," which is the smoke signal.

Level 2 — high-confidence verification (representative seeded data)

Synthetic inputs catch fatals and gross errors. They do NOT catch wrong IDs returning the wrong record, cached sentinel values being served instead of fresh data, permission gates appearing correct against a synthetic ID but not against a real one, filtered labels diverging from the unfiltered claim, missing capabilities surfacing only when a real record is in scope, or curated output drift (a new field added to the controller that the ability inherits and now leaks). These are the failure modes that matter and they only fall out when the ability runs against the data shape it will see in production.

For each ability whose audit entry declares a non-null seed_data_needs, seed the environment per that field, then call the ability with representative inputs (a real id, a real slug — not a synthetic placeholder), and assert the output shape AND the privacy contract:

<env-cli> wp --user=admin eval '
// Seed once at the top of the harness run, per the audit doc:
// e.g. wp post create, wp user create, wp option update, factory helpers.

$ability = wp_get_ability( "<plugin>/<read-ability>" );
$result  = $ability->execute( array( "<field>" => "<real-id-from-the-seeded-data>" ) );

if ( is_wp_error( $result ) ) {
    echo "FAIL: " . $result->get_error_code() . PHP_EOL;
    exit;
}

// Assert the documented output shape — keys present, types correct.
$expected_keys = array( "id", "label", "status" );  // from the ability schema or audit return_type
foreach ( $expected_keys as $k ) {
    if ( ! array_key_exists( $k, (array) $result ) ) {
        echo "FAIL: missing output key " . $k . PHP_EOL;
        exit;
    }
}

// Assert the privacy contract: sensitive fields the contract does NOT
// promise must not appear (e.g. full PAN, full bank account, raw token,
// internal-only debug fields).
$forbidden_keys = array( "full_pan", "card_number", "bank_account_number", "iban" );
foreach ( $forbidden_keys as $k ) {
    if ( array_key_exists( $k, (array) $result ) ) {
        echo "FAIL: privacy leak — " . $k . " present in output." . PHP_EOL;
        exit;
    }
}

echo "PASS: shape OK, privacy OK." . PHP_EOL;
'

Adapt $expected_keys and $forbidden_keys to each ability. The audit doc's return_type field hints at the shape; the privacy keys depend on the plugin's domain. For payments-family plugins, full PANs / bank numbers / raw tokens are the canonical forbidden set; other families substitute appropriately. The plugin's in-tree contract tests (the overlay's test-the-public-contract.md for WooCommerce extensions) are the durable home for these assertions on every CI run — this Level 2 check is the one-off harness run that produces the PR artifact.

When the audit doc declares seed_data_needs: null, Level 2 is not yet runnable: the auditor has not identified the seed shape. The harness reports LEVEL 2: pending (seed_data_needs is null — ask the implementer) and proceeds. When seed_data_needs is a string, the harness operator seeds per that description before running the representative-input block above.

Check 4 — each write ability's missing-input returns ability_invalid_input or <plugin>_missing_<field>

<env-cli> wp --user=admin eval '
$a = wp_get_ability( "<plugin>/<write-ability>" );

$r1 = $a->execute( array() );
echo "missing: " . ( is_wp_error( $r1 ) ? "WP_Error(" . $r1->get_error_code() . ")" : "UNEXPECTED_OK" ) . PHP_EOL;

$r2 = $a->execute( array( "<required_field>" => 123 ) );
echo "non-string: " . ( is_wp_error( $r2 ) ? "WP_Error(" . $r2->get_error_code() . ")" : "UNEXPECTED_OK" ) . PHP_EOL;
'

Acceptable codes, per ../../wp-abilities-api/references/error-code-vocabulary.md:

  • ability_invalid_input — the Abilities API's schema validator fired first (normal REST-bridge path; emitted by WP_Ability::validate_input() in core).

  • <plugin>_missing_<field> — the execute callback's own guard fired (direct-invocation path).

  • <plugin>_invalid_<field> — same, for the wrong-type case.

UNEXPECTED_OK → FAIL. Validation is missing; the ability accepted no-input and proceeded to do something it shouldn't have.

Check 5 — permission gate denies subscriber, allows admin

<env-cli> wp --user=admin eval '
$ability = wp_get_ability( "<plugin>/<any-ability>" );
$input   = array(); // representative input; substitute for non-object root schemas.

// Admin path.
wp_set_current_user( 1 );
$admin_result = $ability->check_permissions( $input );

// Subscriber path.
$sub_login = "verify_sub_" . time();
$sub_id    = wp_create_user( $sub_login, "x", $sub_login . "@example.com" );
if ( ! is_wp_error( $sub_id ) ) {
    $user = get_user_by( "id", $sub_id );
    $user->set_role( "subscriber" );
    wp_set_current_user( $sub_id );
    $sub_result = $ability->check_permissions( $input );
} else {
    $sub_result = $sub_id; // surface the create_user error in the report
}

foreach ( array( "admin" => $admin_result, "subscriber" => $sub_result ) as $context => $r ) {
    if ( true === $r ) {
        $printable = "true";
    } elseif ( is_wp_error( $r ) ) {
        $printable = "WP_Error(" . $r->get_error_code() . ")";
    } else {
        $printable = var_export( $r, true );
    }
    echo $context . ": " . $printable . PHP_EOL;
}

// Cleanup the test subscriber so repeated harness runs don't accumulate users
// on shared dev environments. Switch back to admin first since we last ran as
// the subscriber and that role doesn't hold delete_users. On multisite,
// wp_delete_user() only removes the user from the current site's membership —
// wpmu_delete_user() in wp-admin/includes/ms.php is the network-wide delete.
if ( isset( $sub_id ) && ! is_wp_error( $sub_id ) ) {
    wp_set_current_user( 1 );
    if ( is_multisite() ) {
        require_once ABSPATH . "wp-admin/includes/ms.php";
        wpmu_delete_user( $sub_id );
    } else {
        require_once ABSPATH . "wp-admin/includes/user.php";
        wp_delete_user( $sub_id );
    }
}
'

Expected:

admin: true
subscriber: false

Any inversion is a bug in the registered permission_callback. See permission-roundtrip.md for the deeper cross-checks (audit's declared capability → registered callback → resolved current_user_can(...)).

Public abilities (deliberately ungated) expect subscriber: true AND admin: true. Verify that the ability's permission_callback is '__return_true' in source before accepting this outcome.

check_permissions() returns bool|WP_Error per WP_Ability::check_permissions() in WordPress core. A WP_Error with code ability_invalid_permission_callback means the registration didn't supply a valid callable — a hard FAIL. A WP_Error with code ability_callback_exception means the callback threw — also a hard FAIL.

Check 6 — twin-invocation heuristic for idempotent abilities

Only apply this to abilities annotated idempotent: true whose execute() returned without error in Check 3. Per annotation-correctness.md step "Runtime check complement", this is a heuristic: idempotent in core means "no additional effect on the environment" (per the idempotent annotation's docblock in class-wp-ability.php), not "byte-identical return values."

<env-cli> wp --user=admin eval '
$a  = wp_get_ability( "<plugin>/<idempotent-ability>" );
$r1 = $a->execute();
$r2 = $a->execute();

if ( is_wp_error( $r1 ) || is_wp_error( $r2 ) ) {
    echo "skipped: one or both invocations returned WP_Error" . PHP_EOL;
    if ( is_wp_error( $r1 ) ) { echo "r1=" . $r1->get_error_code() . PHP_EOL; }
    if ( is_wp_error( $r2 ) ) { echo "r2=" . $r2->get_error_code() . PHP_EOL; }
} else {
    $h1 = md5( serialize( $r1 ) );
    $h2 = md5( serialize( $r2 ) );
    echo "match=" . var_export( $h1 === $h2, true ) . PHP_EOL;
    echo "h1=" . $h1 . PHP_EOL;
    echo "h2=" . $h2 . PHP_EOL;
}
'

Interpretation:

  • match=true → cheap PASS. Same input produced the same response, and any environmental writes (write abilities) were the same on both calls.

  • match=false → inspect what changed before deciding:

    • Response embeds a per-call timestamp, nonce, or random ID → environment unchanged. Still idempotent under core's reading. Optionally remove the field if the agent doesn't need it; the annotation stays idempotent: true.

    • Response reflects a counter or sequence that grew between calls → real environmental change. FAIL: drop the idempotent: true annotation or fix the underlying write to be input-determined.

For ambiguous cases (response varies but no obvious counter), supplement with a state diff: snapshot a representative table or option before call 1, snapshot after call 2, diff. If state changed by more than the input writes would explain, the ability is non-idempotent.

Output format

The runtime harness writes a dedicated section in the run report:

## Runtime harness

**Env:** wp-env (Docker), WordPress 7.0, <plugin> <version>
**Captured:** <YYYY-MM-DD HH:MM>

### Check 1 — enumeration

count=7 (expected 7 from static inventory)
<sorted list>

### Check 2 — annotations

| Ability | readonly | destructive | idempotent | Matches source? |
|---|---|---|---|---|

### Check 3 — read execution

| Ability | Result |
|---|---|

### Check 4 — write input validation

| Ability | Missing-input code | Wrong-type code |
|---|---|---|

### Check 5 — permission gate

| Ability | admin | subscriber | Expected |
|---|---|---|---|

### Check 6 — idempotency

| Ability | match | h1 | h2 |
|---|---|---|---|

### Notes / surprises

<Anything unexpected that didn't block.>

When the harness catches a bug

Observed pattern:

  1. Harness surfaces a PHP fatal (e.g. ArgumentCountError: Too few arguments to function <controller>::__construct).

  2. Implementer fixes the bug in a focused commit.

  3. Harness re-runs; write the post-fix output as the headline status.

  4. Preserve the pre-fix trace in the report under a "Pre-fix status" section so reviewers can see what verify caught.

This is the highest-leverage signal the runtime harness produces: bootstrap-ordering and missing-dependency bugs that pass static review because the source declares the right shape — they only manifest when the registration runs against a booted WordPress.

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Node.js

The author says: 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.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Published by
WordPress
Publisher
WordPress (Official)
Source
WordPress/agent-skills · skills/wp-abilities-verify · commit 7374e6f
Licence
GNU General Public License v2.0 or later (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by WordPress or WordPress.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download wp-abilities-verify.zip