Wp Abilities Audit
WordPressOfficialPublished by WordPress
- Skill
- Workflow
- Software development
- GPL-2.0-or-later
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The wp-abilities-audit skill provides a systematic procedure for auditing a WordPress plugin's REST API surface. It guides the user through enumerating controllers, tracing capability gates, and applying semantic-intent grouping to propose Abilities API registrations. The output is a standardized markdown document containing a YAML schema and prose sections, serving as a comprehensive planning artifact for developers and AI agents to implement the Abilities API.
What it does
- Enumerates all REST controller classes, routes, and methods within a plugin.
- Traces permission callbacks to identify underlying capability gates.
- Groups REST endpoints into semantic abilities based on real-world user intent.
- Generates a structured audit document with YAML metadata and implementation notes.
- Identifies gaps, risks, and deferred items for the MVP rollout.
- Provides a standardized format for both human and agent-driven implementation.
When to use it
- When planning to implement the Abilities API for a WordPress plugin.
- When you need a shareable, standardized audit artifact for a multi-plugin rollout.
- When assessing a plugin's readiness for agent-based interaction.
- When a project manager needs to scope the implementation effort for REST surface integration.
Advantages
- Ensures consistency across different plugin audits.
- Reduces manual effort by providing a clear, step-by-step audit procedure.
- Produces machine-readable YAML for downstream automation.
- Separates internal plumbing from user-facing abilities via semantic grouping.
- Captures critical implementation details like capability gates and side effects.
Usage examples
- “Run the wp-abilities-audit on the plugin located in ./wp-content/plugins/my-custom-plugin and save the report to ./plans/audit-my-plugin.md”
- The agent performs a full audit of the plugin's REST surface, generates the required YAML schema, and saves the structured markdown report to the specified path.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/wordpress/wp-abilities-audit/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip wp-abilities-audit.zip -d .agents/skills
Documentation by WordPress
WP Abilities Audit
Produce a standardized audit document for a WordPress plugin's REST surface, proposing a set of Abilities API registrations grouped by semantic intent. The audit doc is a planning artifact for implementers — humans, agents, or both — that captures the controller inventory, capability gates, and proposed ability shapes in a structured form. A reviewer reading the doc can scope the work without re-deriving the survey.
This skill works on any plugin that exposes a REST surface. Plugin
classification (for purposes of the optional plugin_family annotation) is
the user's call; the workflow itself is plugin-agnostic.
When to use
The task is "register Abilities API abilities for a WP plugin" and no audit doc exists yet.
Planning participation in a multi-plugin abilities rollout and need a shareable, standardized audit artifact.
Pre-flight checking a plugin's agent-readiness before implementing abilities.
A PM or non-implementer wants to scope the work before engineering picks it up.
Inputs required
Plugin checkout path — working tree of the plugin to audit.
Triage output — run
wp-project-triagefirst if not already done. The audit consumessignals.usesAbilitiesApi,versions.wordpress, andproject.kindfrom the report.Auditor identity — name and team or context, recorded in the audit's
auditorfield.Output path — where the audit doc should land. Default explicit over implicit; ask if not provided rather than writing into the plugin worktree.
Prerequisites
wp-project-triagehas run successfully and classified the plugin.The plugin has at least one REST controller. If enumeration finds zero controllers, the audit doesn't apply — see "Failure modes" below.
Procedure
1. Enumerate REST controllers
Read references/controller-enumeration.md now — it covers the two observed
enumeration paths (glob for standard layouts, grep as the universal fallback)
and when to use each.
Record every controller class + file + REST base + routes in a "Controller Inventory" table. The inventory is exhaustive even though only a subset becomes proposed abilities.
2. For each controller, extract the backing fields
For every controller found, extract the fields the audit schema requires:
class, file, HTTP method, route, route-registration line number, callback
name, callback line number, permission callback, whether the callback takes
a WP_REST_Request argument or is zero-arg, and the return type.
Read references/audit-schema.md now for the exact field list and the shape
of proposed_abilities entries. Line-number fields may be null for
inherited callbacks — the schema allows this and pairs it with an optional
inherited_from field.
3. Confirm capability gate(s)
Trace each controller's permission_callback to its current_user_can() call
(or to the post-type capability machinery if the controller extends a
post-type-backed base).
Read references/capability-gate-tracing.md now — it documents the two
common mechanisms (direct check_permission() vs post-type-backed
wc_rest_check_post_permissions()) and how to represent each in the schema.
Note explicitly whether read and write gates differ: compound gates are
represented as a {read, write} object, not a single string.
4. Propose abilities using semantic-intent grouping
Do NOT atomize one ability per HTTP method. Apply the semantic-intent grouping heuristic — it's the only grouping rule this skill uses.
Read ../wp-abilities-api/references/grouping-heuristic.md now — do NOT
re-derive the rules here. Short version: one ability per real-world question
or state transition, with filter parameters in input_schema collapsing N
variants into 1.
Apply the use-case sanity check before populating any candidate. Per
../wp-abilities-api/references/domain-vs-projection.md's use-case-contract
test: would a human or agent intentionally perform this behavior through a
supported plugin workflow? If yes, the candidate is a real ability —
proceed to fill in fields. If no, the route is internal transport plumbing
(cache invalidation, scheduler ticks, bookkeeping endpoints, debug
introspection) — keep it in the Controller Inventory section for
completeness, but do NOT promote it to proposed_abilities. The route may
be useful to inventory; the proposed ability must represent a real
user/operator question or action.
For each proposed ability that passes the sanity check, fill in every
field in the proposed_abilities schema: name, intent, backing,
permission, return_type, effort (S/M/L), annotations
(readonly/destructive/idempotent), notes, risks, use_case_fit,
side_effects, seed_data_needs.
The last three are the implementation-readiness facts the implementer
and the verify-mode tooling both need: which human/agent workflow this
ability serves (use_case_fit), what the backing path emits on every
call (side_effects — empty array is a fact, not a missing value), and
what representative data must exist in the test environment for the
ability to execute through the public boundary (seed_data_needs).
5. Surface gaps and deferred items
Three buckets:
excluded_from_mvp— candidates intentionally deferred for risk reasons (real-money writes, irreversible state changes, or prerequisite design work). Each entry gets a one-sentence reason.surfaced_gaps— MVP candidates with no backing endpoint (ability withbacking: null), plus high-value endpoints discovered during enumeration that aren't in the MVP list but would be easy future wins.Risks per ability — anything about a backing endpoint that the implementer must handle (no idempotency key, two-phase behavior, state-transition caveats, zero-arg endpoints registered with
permission_callback => '__return_true'that must NOT copy that into the ability registration).
6. Write the audit doc
Write to the explicit output path collected in "Inputs required". The
document structure must match references/audit-schema.md exactly:
Last updated: YYYY-MM-DD HH:MMheader.YAML block with all required top-level metadata +
proposed_abilities,excluded_from_mvp,surfaced_gaps."Controller Inventory" table.
"Notes and Surprises" prose section.
A copy-pasteable minimal example showing the full shape lives in
references/audit-schema.md under "Minimal valid example" — start there
when authoring a new audit.
7. (Optional) Designate a reference implementation ability
Set reference_ability: true on the first ability an implementer should
land — typically the smallest, safest, highest-leverage read. This gives
downstream workflows a deterministic starting point.
Verification
The audit conforms to
references/audit-schema.md(all required top-level fields present, at least one entry inproposed_abilities, annotations complete on every ability).capability_gateis a string for single-cap plugins or a{read, write}object for post-type-backed plugins.Every ability with
backing: nullalso appears insurfaced_gaps.The doc round-trips through the validator in
audit-schema.md"Known limitations" without errors.
Failure modes / debugging
Plugin has no REST controllers — audit doesn't apply. Consider hooks/filters-based abilities (out of scope for this skill's current version) or skip abilities adoption for this plugin.
Plugin inherits controllers from another repo (common for plugins extending core post-type-backed controllers like
WP_REST_Posts_Controller, or extension plugins built on a parent's REST classes) — capture withbacking.inherited_from: "<parent FQCN>". Line-number fields may benullper the schema.Compound capability gate (distinct read/write caps) — use the structured
{read, write}form documented inreferences/capability-gate-tracing.md. Don't smuggle a/-separated string into a field typed as a single cap.Ambiguous grouping — route to
../wp-abilities-api/references/grouping-heuristic.md. Do not invent alternative grouping rules in the audit doc.Zero-arg endpoints with
permission_callback => '__return_true'— legal at the REST layer, but the ability's ownpermission_callbackmust match the plugin's merchant gate. Never promote'__return_true'into an ability registration. Note this in the ability'srisks.Output path defaults to plugin worktree — always ask the user for an explicit output directory (e.g. their vault
plans/). Writing the audit into the plugin's own git history pollutes the worktree and buries the artifact.
Escalation
If the plugin uses an enumeration convention not covered by
references/controller-enumeration.md(neither the standard glob nor the grep fallback produces a complete inventory), update that reference with the new convention and open a PR so future audits cover it deterministically.If capability tracing hits a mechanism not covered by
references/capability-gate-tracing.md, extend that file rather than encoding the new case in the audit's "Notes and Surprises" only.
Files
- ATTRIBUTION.mdAdded by AutoGineer900 B
- LICENSELicence file added by AutoGineer750 B
- SKILL.md9.6 KiB
- references/audit-schema.md17.4 KiB
- references/capability-gate-tracing.md8.4 KiB
- references/controller-enumeration.md4.9 KiB
references/controller-enumeration.md
Controller Enumeration
How to produce an exhaustive list of a plugin's REST controllers — the first
step of every audit. Plugin family classification is handled separately by
wp-project-triage; this reference covers the mechanics of finding controller
classes inside whatever layout the plugin happens to use.
Two enumeration paths
Observed across the plugins audited to date, there are exactly two paths that together cover every layout seen in the wild:
| Path | When it works | How it works |
|---|---|---|
| Glob | Plugins that follow the standard includes/admin/class-*-rest-*-controller.php layout (WooCommerce core extensions, classic WooPayments). | Fast, deterministic, easy to script. Returns a complete list in one shell call. |
| Grep | Any non-standard layout — includes/api/, includes/rest-api/, src/rest/, monorepo package directories, or anything else. | Universal fallback: grep every PHP file under the plugin root for register_rest_route( call sites, then collect the enclosing class for each hit. |
Default order
Try glob first — it's faster and produces a cleaner inventory.
Fall back to grep if glob returns zero hits (or clearly undercounts against what you see in the plugin's public documentation / admin UI).
Running both and de-duplicating is legal; it catches monorepos that have some controllers under the standard layout and others under a package directory.
Glob — standard layout
# From the plugin root:
ls includes/admin/class-*-rest-*-controller.php 2>/dev/null
ls includes/reports/class-*-rest-*-controller.php 2>/dev/nullWhat you'll see in repos that match this convention:
WooPayments (
Automattic/woocommerce-payments) — every controller underincludes/admin/class-wc-rest-payments-*-controller.phpplus some underincludes/reports/.WooCommerce core's internal REST controllers use the same pattern.
If glob returns 5+ hits, it's almost always the complete inventory. If it returns 0-2, fall through to grep.
Grep — universal fallback
# From the plugin root:
grep -rn --include='*.php' 'register_rest_route(' .For each hit:
Open the file.
Walk up to the enclosing class declaration.
Record
(class, file, route, callback, permission_callback).
This path matters because it's the only one that finds controllers in non-standard locations:
WooCommerce Subscriptions — controllers live under
includes/api/andincludes/api/legacy/. The standard WooPayments glob returns zero; grep is mandatory.Jetpack Forms (and most Jetpack packages) — controllers live under
projects/packages/<name>/src/with no conventional filename. Grep is again mandatory.Custom plugin layouts — anything with
src/Rest/,lib/rest/,api/v1/, etc. Grep catches them all.
Inherited routes
A controller can extend a base class in a different repo — typically the
parent plugin (for extensions built on top of another plugin) or WordPress
core itself (for plugins extending WP_REST_Posts_Controller or other core
REST bases). The parent::register_routes() dispatch appears in the
extending plugin's source, but the literal register_rest_route( call lives
in the parent. WooCommerce extensions extending
WC_REST_Orders_Controller, plugins built on Jetpack package REST classes,
and CPT plugins inheriting from WP_REST_Posts_Controller all hit this
pattern.
Handling:
Record the route on the child class (that's where the plugin's REST surface actually exposes it).
Set
backing.route_registration_line: nullandbacking.callback_line: nullin the audit schema.Add
backing.inherited_from: "<parent FQCN>"so downstream skills can tell the inheritance case from a plain missing line number.Consider running grep against the parent repo too when you need to confirm the callback's request handling — inherited callbacks behave as whatever the parent defines, not what the plugin repo documents.
See audit-schema.md for the exact field shapes.
Exhaustiveness is the goal
The "Controller Inventory" table in the audit doc must list every controller the enumeration found — not just ones backing proposed abilities. A reviewer asking "why isn't controller X in the MVP?" should be able to point at the inventory and see the explicit answer (usually: "excluded from MVP because…" or "surfaced as a gap because…").
If your inventory has 3 entries and the plugin clearly exposes more, either the enumeration is incomplete (re-run grep with broader patterns) or you're filtering the inventory instead of the proposal list. Fix the inventory first; filter after.
Escalation
If neither glob nor grep produces a complete inventory — for example a
plugin that registers routes dynamically from config or via a factory that
does not contain a literal register_rest_route( string — document the
enumeration gap in "Notes and Surprises", and extend this reference with the
new pattern once understood.
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.
The author says: Targets WordPress 7.0+ (PHP 7.4.0+). Filesystem-based agent with bash + node. Requires access to the plugin checkout; some workflows benefit from WP-CLI but don't require it.
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-audit · 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.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download wp-abilities-audit.zip