wordpress-agent-kit 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/.agents/skills/blueprint/SKILL.md +418 -0
  2. package/.agents/skills/wordpress-router/SKILL.md +52 -0
  3. package/.agents/skills/wordpress-router/references/decision-tree.md +55 -0
  4. package/.agents/skills/wp-abilities-api/SKILL.md +108 -0
  5. package/.agents/skills/wp-abilities-api/references/delegate-helper-pattern.md +241 -0
  6. package/.agents/skills/wp-abilities-api/references/domain-vs-projection.md +113 -0
  7. package/.agents/skills/wp-abilities-api/references/error-code-vocabulary.md +123 -0
  8. package/.agents/skills/wp-abilities-api/references/grouping-heuristic.md +89 -0
  9. package/.agents/skills/wp-abilities-api/references/input-schema-gotchas.md +265 -0
  10. package/.agents/skills/wp-abilities-api/references/php-registration.md +94 -0
  11. package/.agents/skills/wp-abilities-api/references/plugin-family-patterns.md +233 -0
  12. package/.agents/skills/wp-abilities-api/references/rest-api.md +13 -0
  13. package/.agents/skills/wp-abilities-api/references/shared-core-service.md +184 -0
  14. package/.agents/skills/wp-abilities-audit/SKILL.md +199 -0
  15. package/.agents/skills/wp-abilities-audit/references/audit-schema.md +300 -0
  16. package/.agents/skills/wp-abilities-audit/references/capability-gate-tracing.md +197 -0
  17. package/.agents/skills/wp-abilities-audit/references/controller-enumeration.md +116 -0
  18. package/.agents/skills/wp-abilities-verify/SKILL.md +215 -0
  19. package/.agents/skills/wp-abilities-verify/references/annotation-correctness.md +154 -0
  20. package/.agents/skills/wp-abilities-verify/references/audit-schema-validation.md +131 -0
  21. package/.agents/skills/wp-abilities-verify/references/permission-roundtrip.md +190 -0
  22. package/.agents/skills/wp-abilities-verify/references/runtime-harness.md +462 -0
  23. package/.agents/skills/wp-abilities-verify/references/schema-lints.md +118 -0
  24. package/.agents/skills/wp-abilities-verify/references/static-enumeration.md +126 -0
  25. package/.agents/skills/wp-block-development/SKILL.md +175 -0
  26. package/.agents/skills/wp-block-development/references/attributes-and-serialization.md +22 -0
  27. package/.agents/skills/wp-block-development/references/block-json.md +49 -0
  28. package/.agents/skills/wp-block-development/references/creating-new-blocks.md +46 -0
  29. package/.agents/skills/wp-block-development/references/debugging.md +36 -0
  30. package/.agents/skills/wp-block-development/references/deprecations.md +24 -0
  31. package/.agents/skills/wp-block-development/references/dynamic-rendering.md +23 -0
  32. package/.agents/skills/wp-block-development/references/inner-blocks.md +25 -0
  33. package/.agents/skills/wp-block-development/references/registration.md +30 -0
  34. package/.agents/skills/wp-block-development/references/supports-and-wrappers.md +18 -0
  35. package/.agents/skills/wp-block-development/references/tooling-and-testing.md +21 -0
  36. package/.agents/skills/wp-block-development/scripts/list_blocks.mjs +121 -0
  37. package/.agents/skills/wp-block-themes/SKILL.md +117 -0
  38. package/.agents/skills/wp-block-themes/references/creating-new-block-theme.md +37 -0
  39. package/.agents/skills/wp-block-themes/references/debugging.md +24 -0
  40. package/.agents/skills/wp-block-themes/references/patterns.md +18 -0
  41. package/.agents/skills/wp-block-themes/references/style-variations.md +14 -0
  42. package/.agents/skills/wp-block-themes/references/templates-and-parts.md +16 -0
  43. package/.agents/skills/wp-block-themes/references/theme-json.md +59 -0
  44. package/.agents/skills/wp-block-themes/scripts/detect_block_themes.mjs +117 -0
  45. package/.agents/skills/wp-interactivity-api/SKILL.md +180 -0
  46. package/.agents/skills/wp-interactivity-api/references/debugging.md +29 -0
  47. package/.agents/skills/wp-interactivity-api/references/directives-quickref.md +30 -0
  48. package/.agents/skills/wp-interactivity-api/references/server-side-rendering.md +310 -0
  49. package/.agents/skills/wp-performance/SKILL.md +147 -0
  50. package/.agents/skills/wp-performance/references/autoload-options.md +24 -0
  51. package/.agents/skills/wp-performance/references/cron.md +20 -0
  52. package/.agents/skills/wp-performance/references/database.md +20 -0
  53. package/.agents/skills/wp-performance/references/http-api.md +15 -0
  54. package/.agents/skills/wp-performance/references/measurement.md +21 -0
  55. package/.agents/skills/wp-performance/references/object-cache.md +24 -0
  56. package/.agents/skills/wp-performance/references/query-monitor-headless.md +38 -0
  57. package/.agents/skills/wp-performance/references/server-timing.md +22 -0
  58. package/.agents/skills/wp-performance/references/wp-cli-doctor.md +24 -0
  59. package/.agents/skills/wp-performance/references/wp-cli-profile.md +32 -0
  60. package/.agents/skills/wp-performance/scripts/perf_inspect.mjs +128 -0
  61. package/.agents/skills/wp-phpstan/SKILL.md +98 -0
  62. package/.agents/skills/wp-phpstan/references/configuration.md +52 -0
  63. package/.agents/skills/wp-phpstan/references/third-party-classes.md +76 -0
  64. package/.agents/skills/wp-phpstan/references/wordpress-annotations.md +124 -0
  65. package/.agents/skills/wp-phpstan/scripts/phpstan_inspect.mjs +263 -0
  66. package/.agents/skills/wp-playground/SKILL.md +233 -0
  67. package/.agents/skills/wp-playground/references/blueprints.md +36 -0
  68. package/.agents/skills/wp-playground/references/cli-commands.md +39 -0
  69. package/.agents/skills/wp-playground/references/debugging.md +16 -0
  70. package/.agents/skills/wp-playground/references/e2e-playwright.md +115 -0
  71. package/.agents/skills/wp-plugin-development/SKILL.md +113 -0
  72. package/.agents/skills/wp-plugin-development/references/data-and-cron.md +19 -0
  73. package/.agents/skills/wp-plugin-development/references/debugging.md +19 -0
  74. package/.agents/skills/wp-plugin-development/references/lifecycle.md +33 -0
  75. package/.agents/skills/wp-plugin-development/references/security.md +29 -0
  76. package/.agents/skills/wp-plugin-development/references/settings-api.md +22 -0
  77. package/.agents/skills/wp-plugin-development/references/structure.md +16 -0
  78. package/.agents/skills/wp-plugin-development/scripts/detect_plugins.mjs +122 -0
  79. package/.agents/skills/wp-plugin-directory-guidelines/SKILL.md +133 -0
  80. package/.agents/skills/wp-plugin-directory-guidelines/references/gpl-compliance.md +217 -0
  81. package/.agents/skills/wp-plugin-directory-guidelines/references/guideline-review-checklist.md +592 -0
  82. package/.agents/skills/wp-plugin-directory-guidelines/references/naming-rules.md +121 -0
  83. package/.agents/skills/wp-project-triage/SKILL.md +39 -0
  84. package/.agents/skills/wp-project-triage/references/triage.schema.json +143 -0
  85. package/.agents/skills/wp-project-triage/scripts/detect_wp_project.mjs +610 -0
  86. package/.agents/skills/wp-rest-api/SKILL.md +115 -0
  87. package/.agents/skills/wp-rest-api/references/authentication.md +18 -0
  88. package/.agents/skills/wp-rest-api/references/custom-content-types.md +20 -0
  89. package/.agents/skills/wp-rest-api/references/discovery-and-params.md +20 -0
  90. package/.agents/skills/wp-rest-api/references/responses-and-fields.md +30 -0
  91. package/.agents/skills/wp-rest-api/references/routes-and-endpoints.md +36 -0
  92. package/.agents/skills/wp-rest-api/references/schema.md +22 -0
  93. package/.agents/skills/wp-wpcli-and-ops/SKILL.md +126 -0
  94. package/.agents/skills/wp-wpcli-and-ops/references/automation.md +30 -0
  95. package/.agents/skills/wp-wpcli-and-ops/references/cron-and-cache.md +23 -0
  96. package/.agents/skills/wp-wpcli-and-ops/references/debugging.md +17 -0
  97. package/.agents/skills/wp-wpcli-and-ops/references/multisite.md +22 -0
  98. package/.agents/skills/wp-wpcli-and-ops/references/packages-and-updates.md +22 -0
  99. package/.agents/skills/wp-wpcli-and-ops/references/safety.md +30 -0
  100. package/.agents/skills/wp-wpcli-and-ops/references/search-replace.md +40 -0
  101. package/.agents/skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs +90 -0
  102. package/.agents/skills/wp-wpengine/SKILL.md +398 -0
  103. package/.agents/skills/wp-wpengine/references/ci-gate.md +469 -0
  104. package/.agents/skills/wp-wpengine/references/github-actions-deploy.md +736 -0
  105. package/.agents/skills/wp-wpengine/scripts/ci-gate.sh +118 -0
  106. package/.agents/skills/wp-wpengine/scripts/wpe-check.sh +89 -0
  107. package/.agents/skills/wp-wpengine/scripts/wpe-preflight.sh +104 -0
  108. package/.agents/skills/wpds/SKILL.md +59 -0
  109. package/.github/agents/wp-architect.agent.md +1 -2
  110. package/.github/copilot-instructions.md +1 -1
  111. package/.github/instructions/wordpress-workflow.instructions.md +3 -3
  112. package/AGENTS.md +22 -10
  113. package/AGENTS.template.md +20 -10
  114. package/README.md +89 -85
  115. package/dist/cli.js +5 -1
  116. package/dist/commands/clean-skills.js +64 -0
  117. package/dist/commands/setup.js +6 -2
  118. package/dist/commands/sync-skills.js +3 -0
  119. package/dist/lib/api.js +164 -5
  120. package/dist/lib/installer.js +166 -2
  121. package/extensions/wp-agent-kit/index.ts +185 -10
  122. package/package.json +10 -14
  123. package/skills-custom/wp-wpengine/SKILL.md +299 -28
  124. package/skills-custom/wp-wpengine/references/ci-gate.md +469 -0
  125. package/skills-custom/wp-wpengine/references/github-actions-deploy.md +736 -0
  126. package/skills-custom/wp-wpengine/scripts/ci-gate.sh +118 -0
  127. package/skills-custom/wp-wpengine/scripts/wpe-check.sh +89 -0
  128. package/skills-custom/wp-wpengine/scripts/wpe-preflight.sh +104 -0
  129. package/.github/workflows/ci.yml +0 -44
  130. package/.husky/pre-commit +0 -7
  131. package/CLI_REVIEW.md +0 -250
  132. package/biome.json +0 -39
@@ -0,0 +1,184 @@
1
+ # Shared core service — keeping abilities in lockstep with REST and UI
2
+
3
+ When an ability mirrors something a human can already do through a supported UI or workflow, the ability MUST consume the same code path as that UI or workflow — same permissions, same validation, same business rules. Three call sites for the same operation (UI, REST, ability — possibly CLI too) drift apart over time unless they all delegate to a shared service.
4
+
5
+ The default shape this reference recommends is a shared service that the ability, the REST controller, and the UI all consume. Routing the ability through the existing REST controller (the "delegation pattern" below) is a conditional shortcut — fine when the controller is a pure data-fetch and the ability runs predominantly inside REST contexts, but the wrong default for any ability with real growth surface. This reference covers when the shortcut is safe, when it isn't, and the side effects on the existing REST path that most often disqualify it.
6
+
7
+ Read `domain-vs-projection.md` first — abilities are use-case contracts at the domain layer; UI/REST/CLI/MCP are projections. This reference is the implementation mechanism that keeps those projections honest.
8
+
9
+ ## Why this matters
10
+
11
+ A registered ability that re-implements logic instead of calling into existing code paths is a drift hazard. The drift surfaces in predictable ways:
12
+
13
+ - A new filter added to the UI listing doesn't propagate to the ability.
14
+ - A permission tightened on the REST controller leaves the ability under-gated.
15
+ - A validation rule added to the admin form is missing from the ability.
16
+ - A status transition gains a side-effect (audit log, webhook) that fires on UI-driven writes but not ability-driven writes.
17
+
18
+ None of these break the ability immediately. They become discoverable only when an agent invokes the ability and the result quietly diverges from what the same operation in the UI would produce. By that point the ability is in production and the divergence is hard to detect without a contract test you almost certainly do not have.
19
+
20
+ The fix is to keep one source of business logic and treat ability/REST/UI/CLI as adapters over it.
21
+
22
+ ## Three shapes for the ability execute callback
23
+
24
+ | Shape | Example | Verdict |
25
+ |---|---|---|
26
+ | **Re-implement** the logic in the execute callback. | The callback runs its own SQL, applies its own permission checks, builds its own response. | **Avoid.** Guaranteed drift the first time the original code path changes. |
27
+ | **Delegate to the existing REST controller** via `WP_REST_Request`. | The ability builds a `WP_REST_Request` from its input, dispatches via `rest_do_request()`, and returns the response data. The dispatched request flows through the registered controller's permission check, validation, and handler. | **Conditional shortcut.** Acceptable only when *all three* hold: the backing handler is a pure data-fetch (read-only, no side effects), the operation is itself a read, and the ability runs predominantly inside REST contexts. Read "Side effects on the existing REST path" below before assuming the conditions hold. |
28
+ | **Extract a service class** that ability + REST controller + UI handler all consume. | `My_Plugin::get_things_service()->list( $args )` called from the ability, the REST controller, and an admin-side handler. | **Default.** Choose this unless every delegation condition above holds. It is the only shape that removes drift entirely and the only shape that scales when an endpoint later grows a side effect, a write counterpart, or a non-REST caller. |
29
+
30
+ The third row is the default because it is the only one that decouples the ability (a domain-layer capability) from the REST transport. The middle row is a real shortcut — there is no point extracting a service class for `get_option('something')` — but its applicability is bounded enough that it should be reached for deliberately, not by default. Extracting a service is more invasive at first (it usually means refactoring the existing REST controller to call the service rather than embed the logic), but it is also the move that holds up under change.
31
+
32
+ ## What the delegation pattern looks like
33
+
34
+ The middle row of the table — "delegate to the existing REST controller" — is a pattern, not a single canonical helper. The minimal shape is small enough to inline in an ability's `execute_callback`:
35
+
36
+ ```php
37
+ public static function execute_get_things( $input = null ) {
38
+ $request = new WP_REST_Request( 'GET', '/my-plugin/v1/things' );
39
+ $request->set_query_params( (array) $input );
40
+
41
+ $response = rest_do_request( $request );
42
+ if ( $response->is_error() ) {
43
+ return $response->as_error();
44
+ }
45
+
46
+ return $response->get_data();
47
+ }
48
+ ```
49
+
50
+ The five moves: construct the `WP_REST_Request` with the right HTTP method and route; copy the ability's `$input` onto the request as query params (or body params for writes); dispatch via `rest_do_request()`, which routes through the registered controller including its `permission_callback` and any side effects; convert an error response back to a `WP_Error` so the ability's caller sees a normal error; otherwise return the data.
51
+
52
+ In a real codebase you would usually extract this into a small private helper so multiple ability callbacks can share the boilerplate. The shape of that helper is out of scope for this reference — the point here is that the delegation pattern is mechanically simple and does not depend on any particular framework helper to be in place.
53
+
54
+ ## Side effects on the existing REST path
55
+
56
+ A delegating ability re-uses the REST controller's full code path, including any side effects the controller emits on every call:
57
+
58
+ - **Usage telemetry / analytics events** — the ability inflates dashboards with agent traffic and the human-vs-agent provenance signal is lost. Metric double-counting is the silent failure mode — the system "works" while the dashboards drift.
59
+ - **Audit logs** — entries get attributed to a "REST" actor that is actually an agent. Forensics gets noisier.
60
+ - **Custom-event hooks** (`do_action(...)`) — listeners on those hooks now fire on every ability invocation, with surprise side-effects in unrelated subsystems.
61
+ - **Email / notification dispatch** — agent-driven calls trigger user-visible notifications that should not have been sent.
62
+ - **Cache invalidation, schedule rescheduling, lock acquisition** — harmless when intended; harmful when fired by traffic the original handler did not anticipate.
63
+ - **First-call REST bootstrap cost** (performance, not semantics). `rest_do_request()` calls `rest_get_server()`, which lazily instantiates `WP_REST_Server` and fires `rest_api_init` the first time it's invoked in a request lifecycle. In a normal HTTP REST request the cost is paid before the abilities layer even runs; in CLI / cron / agent / non-REST MCP transports, the *first* ability that delegates pays it — every plugin's `register_rest_route()` callback wires up at this point. The cost is one-time per request lifecycle (`rest_get_server()` guards on `if ( empty( $wp_rest_server ) )`), but on a cold path the first invocation is measurably slow. If the ability is expected to run predominantly outside REST contexts, prefer calling the underlying service or request class directly over going through `rest_do_request()`.
64
+
65
+ The fix is the third row of the table above:
66
+
67
+ - Extract the business logic into a service class.
68
+ - Have the REST controller call the service AND emit its side effects as a thin adapter.
69
+ - Have the ability call the service directly, NOT the REST controller. The ability emits its own ability-tagged side effects, or none.
70
+
71
+ This way side effects stay scoped to the surface that triggers them, and the ability still consumes the same business logic as the UI.
72
+
73
+ If the existing REST endpoint is a pure data-fetch with no side effects, the delegation pattern is a fine shortcut.
74
+
75
+ ## MCP exposure rule
76
+
77
+ Do not expose REST AND ability for the same operation to the same MCP client. Pick one.
78
+
79
+ The ability is the agent contract: schema-typed, permission-gated, semantic-intent-named. The REST endpoint stays in place for non-agent integrations (UI, third-party clients that already exist, internal services that consume the JSON contract). The MCP layer surfaces the ability and elides the REST endpoint.
80
+
81
+ Exposing both produces a "which surface should I use?" question for any LLM that sees both — and the answer affects metrics, logging, and error handling. Pick the ability.
82
+
83
+ ## The `AGENTS.md` rule
84
+
85
+ Add a line to the plugin's `AGENTS.md` (under whichever H2 covers "when changing code in this area"):
86
+
87
+ > When you change the code path behind a registered ability, check whether the ability needs to update too. A new filter on the underlying listing usually means the ability should expose the same filter. A permission change means the ability's gate likely needs to follow. A new side-effect on a write may change what we promise the ability does.
88
+
89
+ This shifts the burden from "remember to update the ability" to "be reminded by the LLM working on the change." It costs nothing at write time and prevents the most common source of drift.
90
+
91
+ ## Worked example — extracting a service
92
+
93
+ Generic plugin with a `Things` resource. Before extraction, the REST controller embeds the listing logic and the ability re-runs the same filter/sort/paginate code:
94
+
95
+ ```php
96
+ // includes/admin/class-rest-things-controller.php
97
+ class My_Plugin_REST_Things_Controller {
98
+ public function get_things( WP_REST_Request $request ) {
99
+ $args = self::sanitize_query_args( $request->get_params() );
100
+ $rows = $this->repo->find( $args );
101
+
102
+ // Side effects (audit log, hooks, notifications) live on the REST adapter.
103
+ do_action( 'my_plugin/things_listed', $rows );
104
+
105
+ return rest_ensure_response( array_map( [ $this, 'format' ], $rows ) );
106
+ }
107
+ }
108
+
109
+ // src/Internal/Abilities/Abilities_Registrar.php
110
+ public static function execute_get_things( $input = null ) {
111
+ // PROBLEM: re-implements sanitization, repo call, formatting.
112
+ // Drifts the first time the controller's get_things() changes.
113
+ $args = MyPlugin\Sanitize::query_args( (array) $input );
114
+ $rows = ( new MyPlugin\Things_Repo() )->find( $args );
115
+ return array_map( [ MyPlugin\Things_Formatter::class, 'format' ], $rows );
116
+ }
117
+ ```
118
+
119
+ After extraction, both paths consume `Things_Service::list()`:
120
+
121
+ ```php
122
+ // src/Service/class-things-service.php
123
+ class Things_Service {
124
+ public function list_things( array $args ) {
125
+ $clean = Sanitize::query_args( $args );
126
+ $rows = $this->repo->find( $clean );
127
+ return array_map( array( Things_Formatter::class, 'format' ), $rows );
128
+ }
129
+ }
130
+
131
+ // includes/admin/class-rest-things-controller.php
132
+ class My_Plugin_REST_Things_Controller {
133
+ public function get_things( WP_REST_Request $request ) {
134
+ $rows = $this->service->list_things( $request->get_params() );
135
+
136
+ // Side effects (audit log, hooks, notifications) stay on the REST adapter — clean.
137
+ do_action( 'my_plugin/things_listed', $rows );
138
+
139
+ return rest_ensure_response( $rows );
140
+ }
141
+ }
142
+
143
+ // src/Internal/Abilities/Abilities_Registrar.php
144
+ public static function execute_get_things( $input = null ) {
145
+ if ( ! class_exists( '\MyPlugin\Things_Service' ) ) {
146
+ return new WP_Error( 'myplugin_not_initialized', __( 'My Plugin is not initialized.', 'my-plugin' ) );
147
+ }
148
+ return MyPlugin::get_things_service()->list_things( (array) $input );
149
+ }
150
+ ```
151
+
152
+ The ability and the REST endpoint now share business logic. Side effects (audit, hooks, notifications, any telemetry) stay on the REST adapter and do not fire on agent-driven invocations. The next person to add a filter parameter changes one place — the service — and both call sites pick it up.
153
+
154
+ ## Rule of thumb
155
+
156
+ Start from the assumption that the ability extracts (or consumes an already-extracted) service. Walk back to delegation only when every condition for it holds.
157
+
158
+ - **Write of any kind** → extract a service. Drift is most damaging on writes (lost validation, missing audit hooks). Non-negotiable.
159
+ - **No existing REST endpoint** → start at the service. The first ability you ship is also the right time to add the structure that a future REST endpoint will consume.
160
+ - **Read where the REST handler does more than data-fetch** (audit, hooks, notifications, telemetry) → extract a service. Don't fire UI-scoped side effects on agent invocations.
161
+ - **Read predominantly invoked outside REST** (CLI, cron, agent, non-REST MCP transport) → prefer direct invocation of the service or the underlying request class. Delegation pays the first-call REST bootstrap cost on every cold path.
162
+ - **Read with no side effects on the REST path, light logic, predominantly invoked through REST** → the delegation pattern is acceptable as a shortcut. Drift risk is bounded because the REST controller is one short hop away — but only as long as those three conditions hold.
163
+
164
+ The bias is intentional. Service-extraction is the only shape that holds up when the REST handler later grows a side effect, when a write counterpart shows up, or when a non-REST caller appears (a new CLI command, a cron job, an agent invocation off a non-REST MCP transport). Delegation re-couples the domain layer to the REST transport; that re-coupling is fine when the conditions hold *and* unlikely to change, but the cost of unwinding it later is higher than starting at the service.
165
+
166
+ ## Escape hatch — when re-implementation is OK
167
+
168
+ Two narrow cases:
169
+
170
+ 1. **The ability is read-only and the backing has no extractable shape.** Sometimes the "logic" is one line — `get_option( 'something' )` — and a service class is overkill. Inline it.
171
+ 2. **The plugin is single-purpose and will not grow surfaces.** A 200-line plugin with one ability and no REST surface to drift against can keep logic in the execute callback. The drift risk only shows up at 2+ adapters.
172
+
173
+ In both cases, leave a `// TODO: extract to service if a REST/UI surface gets added` comment so the next person sees the trigger condition.
174
+
175
+ ## Plugin-family override
176
+
177
+ This reference describes the generic baseline. Specific plugin families can — and routinely do — tighten the rules further. A payments-family plugin might forbid the delegation pattern outright on the grounds that no payments endpoint is safe to treat as side-effect-free. A subscription plugin might require service extraction even for one-line option reads if the option is read in more than one transport. A plugin that ships its own MCP transport might rule out delegation for any ability exposed through it.
178
+
179
+ When the plugin you are working in is one of those, the local rules win. Check the plugin's `AGENTS.md`, contributor guide, or ability-registration playbook before reaching for the delegation shortcut taught here.
180
+
181
+ ## Related references
182
+
183
+ - `domain-vs-projection.md` — the layer model that puts shared services at the domain layer and projections (REST / MCP / CLI / UI) above.
184
+ - `grouping-heuristic.md` — orthogonal: this reference covers "same code path"; that one covers "how many abilities."
@@ -0,0 +1,199 @@
1
+ ---
2
+ name: wp-abilities-audit
3
+ description: "Audit a WordPress plugin's REST surface and produce a standardized audit document proposing Abilities API registrations. Produces a markdown doc with a YAML schema and prose sections that humans and agents can both consume when planning a registration rollout. Works on any WP plugin."
4
+ license: GPL-2.0-or-later
5
+ compatibility: "Targets WordPress 6.9+ (PHP 7.2.24+). Filesystem-based agent with bash + node. Requires access to the plugin checkout; some workflows benefit from WP-CLI but don't require it."
6
+ ---
7
+
8
+ # WP Abilities Audit
9
+
10
+ Produce a standardized audit document for a WordPress plugin's REST surface,
11
+ proposing a set of Abilities API registrations grouped by semantic intent. The
12
+ audit doc is a planning artifact for implementers — humans, agents, or both —
13
+ that captures the controller inventory, capability gates, and proposed
14
+ ability shapes in a structured form. A reviewer reading the doc can scope the
15
+ work without re-deriving the survey.
16
+
17
+ This skill works on any plugin that exposes a REST surface. Plugin
18
+ classification (for purposes of the optional `plugin_family` annotation) is
19
+ the user's call; the workflow itself is plugin-agnostic.
20
+
21
+ ## When to use
22
+
23
+ - The task is "register Abilities API abilities for a WP plugin" and no audit
24
+ doc exists yet.
25
+ - Planning participation in a multi-plugin abilities rollout and need a
26
+ shareable, standardized audit artifact.
27
+ - Pre-flight checking a plugin's agent-readiness before implementing abilities.
28
+ - A PM or non-implementer wants to scope the work before engineering picks it up.
29
+
30
+ ## Inputs required
31
+
32
+ 1. **Plugin checkout path** — working tree of the plugin to audit.
33
+ 2. **Triage output** — run `wp-project-triage` first if not already done. The
34
+ audit consumes `signals.usesAbilitiesApi`, `versions.wordpress`, and
35
+ `project.kind` from the report.
36
+ 3. **Auditor identity** — name and team or context, recorded in the audit's
37
+ `auditor` field.
38
+ 4. **Output path** — where the audit doc should land. Default explicit over
39
+ implicit; ask if not provided rather than writing into the plugin worktree.
40
+
41
+ ## Prerequisites
42
+
43
+ - `wp-project-triage` has run successfully and classified the plugin.
44
+ - The plugin has at least one REST controller. If enumeration finds zero
45
+ controllers, the audit doesn't apply — see "Failure modes" below.
46
+
47
+ ## Procedure
48
+
49
+ ### 1. Enumerate REST controllers
50
+
51
+ Read `references/controller-enumeration.md` now — it covers the two observed
52
+ enumeration paths (glob for standard layouts, grep as the universal fallback)
53
+ and when to use each.
54
+
55
+ Record every controller class + file + REST base + routes in a "Controller
56
+ Inventory" table. The inventory is exhaustive even though only a subset
57
+ becomes proposed abilities.
58
+
59
+ ### 2. For each controller, extract the backing fields
60
+
61
+ For every controller found, extract the fields the audit schema requires:
62
+ class, file, HTTP method, route, route-registration line number, callback
63
+ name, callback line number, permission callback, whether the callback takes
64
+ a `WP_REST_Request` argument or is zero-arg, and the return type.
65
+
66
+ Read `references/audit-schema.md` now for the exact field list and the shape
67
+ of `proposed_abilities` entries. Line-number fields may be `null` for
68
+ inherited callbacks — the schema allows this and pairs it with an optional
69
+ `inherited_from` field.
70
+
71
+ ### 3. Confirm capability gate(s)
72
+
73
+ Trace each controller's `permission_callback` to its `current_user_can()` call
74
+ (or to the post-type capability machinery if the controller extends a
75
+ post-type-backed base).
76
+
77
+ Read `references/capability-gate-tracing.md` now — it documents the two
78
+ common mechanisms (direct `check_permission()` vs post-type-backed
79
+ `wc_rest_check_post_permissions()`) and how to represent each in the schema.
80
+ Note explicitly whether read and write gates differ: compound gates are
81
+ represented as a `{read, write}` object, not a single string.
82
+
83
+ ### 4. Propose abilities using semantic-intent grouping
84
+
85
+ Do NOT atomize one ability per HTTP method. Apply the semantic-intent grouping
86
+ heuristic — it's the only grouping rule this skill uses.
87
+
88
+ Read `../wp-abilities-api/references/grouping-heuristic.md` now — do NOT
89
+ re-derive the rules here. Short version: one ability per real-world question
90
+ or state transition, with filter parameters in `input_schema` collapsing N
91
+ variants into 1.
92
+
93
+ **Apply the use-case sanity check before populating any candidate.** Per
94
+ `../wp-abilities-api/references/domain-vs-projection.md`'s use-case-contract
95
+ test: would a human or agent intentionally perform this behavior through a
96
+ supported plugin workflow? If yes, the candidate is a real ability —
97
+ proceed to fill in fields. If no, the route is internal transport plumbing
98
+ (cache invalidation, scheduler ticks, bookkeeping endpoints, debug
99
+ introspection) — keep it in the Controller Inventory section for
100
+ completeness, but do NOT promote it to `proposed_abilities`. The route may
101
+ be useful to inventory; the proposed ability must represent a real
102
+ user/operator question or action.
103
+
104
+ For each proposed ability that passes the sanity check, fill in every
105
+ field in the `proposed_abilities` schema: `name`, `intent`, `backing`,
106
+ `permission`, `return_type`, `effort` (S/M/L), `annotations`
107
+ (readonly/destructive/idempotent), `notes`, `risks`, `use_case_fit`,
108
+ `side_effects`, `seed_data_needs`.
109
+
110
+ The last three are the implementation-readiness facts the implementer
111
+ and the verify-mode tooling both need: which human/agent workflow this
112
+ ability serves (`use_case_fit`), what the backing path emits on every
113
+ call (`side_effects` — empty array is a fact, not a missing value), and
114
+ what representative data must exist in the test environment for the
115
+ ability to execute through the public boundary (`seed_data_needs`).
116
+
117
+ ### 5. Surface gaps and deferred items
118
+
119
+ Three buckets:
120
+
121
+ - **`excluded_from_mvp`** — candidates intentionally deferred for risk reasons
122
+ (real-money writes, irreversible state changes, or prerequisite design
123
+ work). Each entry gets a one-sentence reason.
124
+ - **`surfaced_gaps`** — MVP candidates with no backing endpoint (ability with
125
+ `backing: null`), plus high-value endpoints discovered during enumeration
126
+ that aren't in the MVP list but would be easy future wins.
127
+ - **Risks per ability** — anything about a backing endpoint that the
128
+ implementer must handle (no idempotency key, two-phase behavior,
129
+ state-transition caveats, zero-arg endpoints registered with
130
+ `permission_callback => '__return_true'` that must NOT copy that into the
131
+ ability registration).
132
+
133
+ ### 6. Write the audit doc
134
+
135
+ Write to the explicit output path collected in "Inputs required". The
136
+ document structure must match `references/audit-schema.md` exactly:
137
+
138
+ 1. `Last updated: YYYY-MM-DD HH:MM` header.
139
+ 2. YAML block with all required top-level metadata + `proposed_abilities`,
140
+ `excluded_from_mvp`, `surfaced_gaps`.
141
+ 3. "Controller Inventory" table.
142
+ 4. "Notes and Surprises" prose section.
143
+
144
+ A copy-pasteable minimal example showing the full shape lives in
145
+ `references/audit-schema.md` under "Minimal valid example" — start there
146
+ when authoring a new audit.
147
+
148
+ ### 7. (Optional) Designate a reference implementation ability
149
+
150
+ Set `reference_ability: true` on the first ability an implementer should
151
+ land — typically the smallest, safest, highest-leverage read. This gives
152
+ downstream workflows a deterministic starting point.
153
+
154
+ ## Verification
155
+
156
+ - The audit conforms to `references/audit-schema.md` (all required top-level
157
+ fields present, at least one entry in `proposed_abilities`, annotations
158
+ complete on every ability).
159
+ - `capability_gate` is a string for single-cap plugins or a `{read, write}`
160
+ object for post-type-backed plugins.
161
+ - Every ability with `backing: null` also appears in `surfaced_gaps`.
162
+ - The doc round-trips through the validator in `audit-schema.md` "Known
163
+ limitations" without errors.
164
+
165
+ ## Failure modes / debugging
166
+
167
+ - **Plugin has no REST controllers** — audit doesn't apply. Consider
168
+ hooks/filters-based abilities (out of scope for this skill's current
169
+ version) or skip abilities adoption for this plugin.
170
+ - **Plugin inherits controllers from another repo** (common for plugins
171
+ extending core post-type-backed controllers like `WP_REST_Posts_Controller`,
172
+ or extension plugins built on a parent's REST classes) — capture with
173
+ `backing.inherited_from: "<parent FQCN>"`. Line-number fields may be
174
+ `null` per the schema.
175
+ - **Compound capability gate (distinct read/write caps)** — use the
176
+ structured `{read, write}` form documented in
177
+ `references/capability-gate-tracing.md`. Don't smuggle a `/`-separated
178
+ string into a field typed as a single cap.
179
+ - **Ambiguous grouping** — route to
180
+ `../wp-abilities-api/references/grouping-heuristic.md`. Do not invent
181
+ alternative grouping rules in the audit doc.
182
+ - **Zero-arg endpoints with `permission_callback => '__return_true'`** —
183
+ legal at the REST layer, but the ability's own `permission_callback` must
184
+ match the plugin's merchant gate. Never promote `'__return_true'` into an
185
+ ability registration. Note this in the ability's `risks`.
186
+ - **Output path defaults to plugin worktree** — always ask the user for an
187
+ explicit output directory (e.g. their vault `plans/`). Writing the audit
188
+ into the plugin's own git history pollutes the worktree and buries the
189
+ artifact.
190
+
191
+ ## Escalation
192
+
193
+ - If the plugin uses an enumeration convention not covered by
194
+ `references/controller-enumeration.md` (neither the standard glob nor the
195
+ grep fallback produces a complete inventory), update that reference with
196
+ the new convention and open a PR so future audits cover it deterministically.
197
+ - If capability tracing hits a mechanism not covered by
198
+ `references/capability-gate-tracing.md`, extend that file rather than
199
+ encoding the new case in the audit's "Notes and Surprises" only.