[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-wordpress-wp-abilities-verify":3,"mdc--b6bvwq-key":46,"related-repo-wordpress-wp-abilities-verify":881,"related-org-wordpress-wp-abilities-verify":993},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":35,"repoUrl":36,"updatedAt":37,"license":38,"forks":39,"topics":40,"repo":41,"sourceUrl":44,"mdContent":45},"wp-abilities-verify","verify WordPress plugin Abilities API registrations","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.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},"wordpress","WordPress","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fwordpress.png",[12,16,19,22,23,26,29,32],{"name":13,"slug":14,"type":15},"Security","security","tag",{"name":17,"slug":18,"type":15},"Validation","validation",{"name":20,"slug":21,"type":15},"Abilities API","abilities-api",{"name":9,"slug":8,"type":15},{"name":24,"slug":25,"type":15},"Plugin Development","plugin-development",{"name":27,"slug":28,"type":15},"REST API","rest-api",{"name":30,"slug":31,"type":15},"Code Analysis","code-analysis",{"name":33,"slug":34,"type":15},"Testing","testing",1892,"https:\u002F\u002Fgithub.com\u002FWordPress\u002Fagent-skills","2026-05-28T06:48:50.590811",null,284,[],{"repoUrl":36,"stars":35,"forks":39,"topics":42,"description":43},[],"Expert-level WordPress knowledge for AI coding assistants - blocks, themes, plugins, and best practices","https:\u002F\u002Fgithub.com\u002FWordPress\u002Fagent-skills\u002Ftree\u002FHEAD\u002Fskills\u002Fwp-abilities-verify","---\nname: wp-abilities-verify\ndescription: \"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.\"\ncompatibility: \"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.\"\n---\n\n# WP Abilities Verify\n\nVerify a WordPress plugin's Abilities API registrations. The\ncenterpiece is the **adversarial annotation correctness check**: a\n`readonly: true` ability that actually writes (via `$wpdb->update`,\n`update_option`, a non-GET delegate, etc.) is a security and UX\ndisaster because agents plan actions on the basis of the annotations\nthey introspect. This skill catches those lies by reading the callback\nbody and comparing what it does against what the annotation claims.\n\nThe skill also validates audit docs produced by `wp-abilities-audit`,\nchecks permission gates and schema hygiene, and optionally executes\neach ability against a live environment.\n\n## When to use\n\n- After abilities have been registered in a plugin but before a PR\n  lands.\n- As a health-check on an already-shipped plugin (catch regressions\n  where a refactor turned a readonly ability into a writing one).\n- To validate an audit document before handing it to an implementer.\n\n## Two modes\n\n- **Static mode** — runs from the plugin checkout. No env. Enumerates\n  via source inspection, runs the adversarial correctness check, runs\n  schema and permission lints, and validates audit docs.\n- **Runtime mode** — requires a running env. Does everything static\n  does PLUS: `wp_get_abilities()` for authoritative enumeration,\n  executes each ability with curated inputs, confirms permission\n  roundtrip against real users, and runs a twin-invocation heuristic\n  on `idempotent: true` abilities to flag candidates for review\n  (return-value equality is a signal, not a verdict — core defines\n  idempotent as \"no additional effect on the environment\").\n\nBoth modes produce the same structured report format.\n\nA static-mode PASS means \"no obvious-shape violations,\" not \"verified\nwrite-free.\" For high-stakes plugins, run runtime mode before landing\n— it catches bootstrap-order, permission-roundtrip, and idempotency\nissues that static can't. See `references\u002Fannotation-correctness.md`\nfor the static blind spots.\n\n## Inputs required\n\n1. **Plugin checkout path** — working tree to verify.\n2. **Mode** — `static` or `runtime`. Default to static if unspecified.\n3. **(Runtime only) Env-up command** — read the plugin's `AGENTS.md`.\n   Common patterns: `npm run wp-env start`, `npx wp-env start`, or a\n   composer-based bring-up. Plugin families with their own dev tooling\n   will document their own command. Do NOT assume `npm run wp-env`\n   works.\n4. **(Optional) Audit doc path** — enables cross-checks between the\n   audit and the registered abilities, and validates the audit itself.\n5. **Report output path** — explicit path, typically the user's vault.\n\n## Prerequisites\n\n- `wp-project-triage` has been run on the plugin.\n- The plugin has at least one registered ability in source. Zero hits\n  on `wp_register_ability(` → return a clear \"no abilities registered\"\n  report, not an empty PASS.\n\n## Procedure\n\n### 1. (If audit provided) Validate the audit doc\n\nRead `references\u002Faudit-schema-validation.md`. Validate the audit\nagainst the canonical schema owned by `wp-abilities-audit`. Surface\nmissing required fields, multiple `reference_ability: true`, and\n`backing: null` entries that aren't paired with a `surfaced_gaps`\nentry. `backing: null` alone is WARN (intentional gap output), not\nFAIL.\n\n### 2. Enumerate abilities statically\n\nRead `references\u002Fstatic-enumeration.md`. Find each\n`wp_register_ability(` call, extract the name, the annotation block,\nand the execute-callback location. Use a multi-line tool (`rg\n--multiline --pcre2`) — the canonical formatting splits the call\nacross lines. Record each ability's source-file + line + annotations +\ncallback byte range.\n\n### 3. (Runtime only) Enumerate via REST + wp-cli\n\nRead `references\u002Fruntime-harness.md`. Bring the env up using the\ncommand from `AGENTS.md`, then enumerate via `wp_get_abilities()` over\nwp-cli and cross-check against the static inventory. Source-only →\nFAIL (registration not firing). Runtime-only → WARN (dynamic\nregistration path).\n\n### 4. Annotation correctness (the adversarial core)\n\nRead `references\u002Fannotation-correctness.md`. Read each callback body\nand verify it matches the annotation claim:\n\n- `readonly: true` → callback must not write to the database, the\n  options table, post \u002F user \u002F term \u002F comment data, the filesystem,\n  cron, or via non-GET HTTP \u002F REST delegates.\n- `destructive: false` → callback must not delete, refund, void,\n  cancel, or trash.\n- `idempotent: true` → repeated calls with the same input have no\n  additional effect on the environment (per the `idempotent`\n  annotation's docblock in `class-wp-ability.php`). Static catches\n  counter writes and per-call cron schedules; runtime adds a\n  twin-invocation heuristic for visible state changes.\n\nThe reference lists common write patterns as a starting set, not a\nchecklist — plugin vocabularies vary, and the agent extends with verbs\nspecific to the plugin under verification.\n\nFalse positives get suppressed via an inline `\u002F\u002F verify-ignore:\n\u003Cannotation> -- \u003Creason>` comment.\n\n### 5. Permission roundtrip\n\nRead `references\u002Fpermission-roundtrip.md`. Static: classify each\n`permission_callback` against the six shapes (preferred Shape A\n`current_user_can(...)`; FAIL on Shape B-bad `WP_REST_Request`\npatterns or Shape E literal `true`). Runtime: anon and subscriber\ndenied; admin allowed (unless deliberately public). When an audit was\nprovided, cross-check the registered cap against the audit's declared\ngate.\n\n### 6. Schema lints\n\nRead `references\u002Fschema-lints.md`. Six small principles applied to\neach ability's `input_schema`: object schemas declare\n`additionalProperties`; required fields have descriptions; enums\nnon-empty; no `$ref`; defaults are statically constant (including\n`(object) array()`); reference abilities have no required inputs.\n\nCross-reference `..\u002Fwp-abilities-api\u002Freferences\u002Finput-schema-gotchas.md`\nfor the four runtime gotchas (defaults not injected on the\nproperty-level path, pagination key drift, `empty()` on string IDs,\ndirect vs indirect invocation strictness).\n\n### 7. Error-code vocabulary\n\nCross-reference `..\u002Fwp-abilities-api\u002Freferences\u002Ferror-code-vocabulary.md`.\nInspect each callback's `WP_Error` returns; non-vocabulary codes →\nWARN.\n\n## Verification\n\nThe run produces a structured markdown report at the user-specified\npath:\n\n```\n---\nLast updated: \u003CYYYY-MM-DD HH:MM>\n---\n\n# \u003CPlugin> Abilities Verification — \u003CStatic|Runtime> Mode\n\n## Status: \u003CPASS|WARN|FAIL>\n\n## Audit doc validation (if provided)\n\n## Static inventory\n\n## Annotation correctness\n| Ability | Claim | Result | Evidence |\n|---|---|---|---|\n\n## Permission gates\n\n## Schema lints\n\n## Error-code vocabulary\n```\n\nEvery ability is OK, WARN, or FAIL. A single FAIL → top-line FAIL;\nWARNs without FAILs → WARN; otherwise PASS.\n\n## Failure modes \u002F debugging\n\n- **Env not reachable (runtime)** — env-up failed or Docker isn't\n  running. Re-run `wp-project-triage`, then fix the env. Don't fall\n  back silently to static without noting it in the report.\n- **No abilities in source** — return a clear \"nothing to verify\"\n  report.\n- **Audit schema mismatch** — point at\n  `references\u002Faudit-schema-validation.md`; don't auto-fix the audit.\n- **False positive on readonly-writes** — see the `\u002F\u002F verify-ignore`\n  mechanism in `references\u002Fannotation-correctness.md`. Document why\n  each suppression is legitimate.\n- **Runtime enumeration smaller than static** — registration hook\n  isn't firing. Check init hook timing, activation state, autoloader\n  order.\n\n## Escalation\n\n- Recurring legitimate pattern that trips the adversarial check across\n  multiple plugins → propose adding it to the suppression guidance in\n  `annotation-correctness.md`. Don't broaden the candidate-pattern\n  list speculatively.\n- Audit-schema validator rejects a legitimate audit → the canonical\n  schema in `..\u002Fwp-abilities-audit\u002Freferences\u002Faudit-schema.md` has\n  evolved. Update `references\u002Faudit-schema-validation.md` to match.\n\n## Out of scope\n\nToken-budget measurement is a separate verification axis — an\nannotation-clean, schema-clean, runtime-passing ability set can still\nbe unshippable if its `tools\u002Flist` form burns through an agent's\ncontext budget. That axis is tracked separately. Do not aggregate\nmanual or external measurement into this skill's PASS \u002F FAIL verdict.\n",{"data":47,"body":49},{"name":4,"description":6,"compatibility":48},"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.",{"type":50,"children":51},"root",[52,60,99,112,119,139,145,184,189,202,208,310,316,343,349,356,407,413,440,446,472,478,489,539,544,557,563,607,613,657,678,684,704,710,715,727,732,738,820,826,862,868],{"type":53,"tag":54,"props":55,"children":56},"element","h1",{"id":4},[57],{"type":58,"value":59},"text","WP Abilities Verify",{"type":53,"tag":61,"props":62,"children":63},"p",{},[64,66,72,74,81,83,89,91,97],{"type":58,"value":65},"Verify a WordPress plugin's Abilities API registrations. The\ncenterpiece is the ",{"type":53,"tag":67,"props":68,"children":69},"strong",{},[70],{"type":58,"value":71},"adversarial annotation correctness check",{"type":58,"value":73},": a\n",{"type":53,"tag":75,"props":76,"children":78},"code",{"className":77},[],[79],{"type":58,"value":80},"readonly: true",{"type":58,"value":82}," ability that actually writes (via ",{"type":53,"tag":75,"props":84,"children":86},{"className":85},[],[87],{"type":58,"value":88},"$wpdb->update",{"type":58,"value":90},",\n",{"type":53,"tag":75,"props":92,"children":94},{"className":93},[],[95],{"type":58,"value":96},"update_option",{"type":58,"value":98},", a non-GET delegate, etc.) is a security and UX\ndisaster because agents plan actions on the basis of the annotations\nthey introspect. This skill catches those lies by reading the callback\nbody and comparing what it does against what the annotation claims.",{"type":53,"tag":61,"props":100,"children":101},{},[102,104,110],{"type":58,"value":103},"The skill also validates audit docs produced by ",{"type":53,"tag":75,"props":105,"children":107},{"className":106},[],[108],{"type":58,"value":109},"wp-abilities-audit",{"type":58,"value":111},",\nchecks permission gates and schema hygiene, and optionally executes\neach ability against a live environment.",{"type":53,"tag":113,"props":114,"children":116},"h2",{"id":115},"when-to-use",[117],{"type":58,"value":118},"When to use",{"type":53,"tag":120,"props":121,"children":122},"ul",{},[123,129,134],{"type":53,"tag":124,"props":125,"children":126},"li",{},[127],{"type":58,"value":128},"After abilities have been registered in a plugin but before a PR\nlands.",{"type":53,"tag":124,"props":130,"children":131},{},[132],{"type":58,"value":133},"As a health-check on an already-shipped plugin (catch regressions\nwhere a refactor turned a readonly ability into a writing one).",{"type":53,"tag":124,"props":135,"children":136},{},[137],{"type":58,"value":138},"To validate an audit document before handing it to an implementer.",{"type":53,"tag":113,"props":140,"children":142},{"id":141},"two-modes",[143],{"type":58,"value":144},"Two modes",{"type":53,"tag":120,"props":146,"children":147},{},[148,158],{"type":53,"tag":124,"props":149,"children":150},{},[151,156],{"type":53,"tag":67,"props":152,"children":153},{},[154],{"type":58,"value":155},"Static mode",{"type":58,"value":157}," — runs from the plugin checkout. No env. Enumerates\nvia source inspection, runs the adversarial correctness check, runs\nschema and permission lints, and validates audit docs.",{"type":53,"tag":124,"props":159,"children":160},{},[161,166,168,174,176,182],{"type":53,"tag":67,"props":162,"children":163},{},[164],{"type":58,"value":165},"Runtime mode",{"type":58,"value":167}," — requires a running env. Does everything static\ndoes PLUS: ",{"type":53,"tag":75,"props":169,"children":171},{"className":170},[],[172],{"type":58,"value":173},"wp_get_abilities()",{"type":58,"value":175}," for authoritative enumeration,\nexecutes each ability with curated inputs, confirms permission\nroundtrip against real users, and runs a twin-invocation heuristic\non ",{"type":53,"tag":75,"props":177,"children":179},{"className":178},[],[180],{"type":58,"value":181},"idempotent: true",{"type":58,"value":183}," abilities to flag candidates for review\n(return-value equality is a signal, not a verdict — core defines\nidempotent as \"no additional effect on the environment\").",{"type":53,"tag":61,"props":185,"children":186},{},[187],{"type":58,"value":188},"Both modes produce the same structured report format.",{"type":53,"tag":61,"props":190,"children":191},{},[192,194,200],{"type":58,"value":193},"A static-mode PASS means \"no obvious-shape violations,\" not \"verified\nwrite-free.\" For high-stakes plugins, run runtime mode before landing\n— it catches bootstrap-order, permission-roundtrip, and idempotency\nissues that static can't. See ",{"type":53,"tag":75,"props":195,"children":197},{"className":196},[],[198],{"type":58,"value":199},"references\u002Fannotation-correctness.md",{"type":58,"value":201},"\nfor the static blind spots.",{"type":53,"tag":113,"props":203,"children":205},{"id":204},"inputs-required",[206],{"type":58,"value":207},"Inputs required",{"type":53,"tag":209,"props":210,"children":211},"ol",{},[212,222,248,290,300],{"type":53,"tag":124,"props":213,"children":214},{},[215,220],{"type":53,"tag":67,"props":216,"children":217},{},[218],{"type":58,"value":219},"Plugin checkout path",{"type":58,"value":221}," — working tree to verify.",{"type":53,"tag":124,"props":223,"children":224},{},[225,230,232,238,240,246],{"type":53,"tag":67,"props":226,"children":227},{},[228],{"type":58,"value":229},"Mode",{"type":58,"value":231}," — ",{"type":53,"tag":75,"props":233,"children":235},{"className":234},[],[236],{"type":58,"value":237},"static",{"type":58,"value":239}," or ",{"type":53,"tag":75,"props":241,"children":243},{"className":242},[],[244],{"type":58,"value":245},"runtime",{"type":58,"value":247},". Default to static if unspecified.",{"type":53,"tag":124,"props":249,"children":250},{},[251,256,258,264,266,272,274,280,282,288],{"type":53,"tag":67,"props":252,"children":253},{},[254],{"type":58,"value":255},"(Runtime only) Env-up command",{"type":58,"value":257}," — read the plugin's ",{"type":53,"tag":75,"props":259,"children":261},{"className":260},[],[262],{"type":58,"value":263},"AGENTS.md",{"type":58,"value":265},".\nCommon patterns: ",{"type":53,"tag":75,"props":267,"children":269},{"className":268},[],[270],{"type":58,"value":271},"npm run wp-env start",{"type":58,"value":273},", ",{"type":53,"tag":75,"props":275,"children":277},{"className":276},[],[278],{"type":58,"value":279},"npx wp-env start",{"type":58,"value":281},", or a\ncomposer-based bring-up. Plugin families with their own dev tooling\nwill document their own command. Do NOT assume ",{"type":53,"tag":75,"props":283,"children":285},{"className":284},[],[286],{"type":58,"value":287},"npm run wp-env",{"type":58,"value":289},"\nworks.",{"type":53,"tag":124,"props":291,"children":292},{},[293,298],{"type":53,"tag":67,"props":294,"children":295},{},[296],{"type":58,"value":297},"(Optional) Audit doc path",{"type":58,"value":299}," — enables cross-checks between the\naudit and the registered abilities, and validates the audit itself.",{"type":53,"tag":124,"props":301,"children":302},{},[303,308],{"type":53,"tag":67,"props":304,"children":305},{},[306],{"type":58,"value":307},"Report output path",{"type":58,"value":309}," — explicit path, typically the user's vault.",{"type":53,"tag":113,"props":311,"children":313},{"id":312},"prerequisites",[314],{"type":58,"value":315},"Prerequisites",{"type":53,"tag":120,"props":317,"children":318},{},[319,330],{"type":53,"tag":124,"props":320,"children":321},{},[322,328],{"type":53,"tag":75,"props":323,"children":325},{"className":324},[],[326],{"type":58,"value":327},"wp-project-triage",{"type":58,"value":329}," has been run on the plugin.",{"type":53,"tag":124,"props":331,"children":332},{},[333,335,341],{"type":58,"value":334},"The plugin has at least one registered ability in source. Zero hits\non ",{"type":53,"tag":75,"props":336,"children":338},{"className":337},[],[339],{"type":58,"value":340},"wp_register_ability(",{"type":58,"value":342}," → return a clear \"no abilities registered\"\nreport, not an empty PASS.",{"type":53,"tag":113,"props":344,"children":346},{"id":345},"procedure",[347],{"type":58,"value":348},"Procedure",{"type":53,"tag":350,"props":351,"children":353},"h3",{"id":352},"_1-if-audit-provided-validate-the-audit-doc",[354],{"type":58,"value":355},"1. (If audit provided) Validate the audit doc",{"type":53,"tag":61,"props":357,"children":358},{},[359,361,367,369,374,376,382,384,390,392,398,400,405],{"type":58,"value":360},"Read ",{"type":53,"tag":75,"props":362,"children":364},{"className":363},[],[365],{"type":58,"value":366},"references\u002Faudit-schema-validation.md",{"type":58,"value":368},". Validate the audit\nagainst the canonical schema owned by ",{"type":53,"tag":75,"props":370,"children":372},{"className":371},[],[373],{"type":58,"value":109},{"type":58,"value":375},". Surface\nmissing required fields, multiple ",{"type":53,"tag":75,"props":377,"children":379},{"className":378},[],[380],{"type":58,"value":381},"reference_ability: true",{"type":58,"value":383},", and\n",{"type":53,"tag":75,"props":385,"children":387},{"className":386},[],[388],{"type":58,"value":389},"backing: null",{"type":58,"value":391}," entries that aren't paired with a ",{"type":53,"tag":75,"props":393,"children":395},{"className":394},[],[396],{"type":58,"value":397},"surfaced_gaps",{"type":58,"value":399},"\nentry. ",{"type":53,"tag":75,"props":401,"children":403},{"className":402},[],[404],{"type":58,"value":389},{"type":58,"value":406}," alone is WARN (intentional gap output), not\nFAIL.",{"type":53,"tag":350,"props":408,"children":410},{"id":409},"_2-enumerate-abilities-statically",[411],{"type":58,"value":412},"2. Enumerate abilities statically",{"type":53,"tag":61,"props":414,"children":415},{},[416,417,423,425,430,432,438],{"type":58,"value":360},{"type":53,"tag":75,"props":418,"children":420},{"className":419},[],[421],{"type":58,"value":422},"references\u002Fstatic-enumeration.md",{"type":58,"value":424},". Find each\n",{"type":53,"tag":75,"props":426,"children":428},{"className":427},[],[429],{"type":58,"value":340},{"type":58,"value":431}," call, extract the name, the annotation block,\nand the execute-callback location. Use a multi-line tool (",{"type":53,"tag":75,"props":433,"children":435},{"className":434},[],[436],{"type":58,"value":437},"rg --multiline --pcre2",{"type":58,"value":439},") — the canonical formatting splits the call\nacross lines. Record each ability's source-file + line + annotations +\ncallback byte range.",{"type":53,"tag":350,"props":441,"children":443},{"id":442},"_3-runtime-only-enumerate-via-rest-wp-cli",[444],{"type":58,"value":445},"3. (Runtime only) Enumerate via REST + wp-cli",{"type":53,"tag":61,"props":447,"children":448},{},[449,450,456,458,463,465,470],{"type":58,"value":360},{"type":53,"tag":75,"props":451,"children":453},{"className":452},[],[454],{"type":58,"value":455},"references\u002Fruntime-harness.md",{"type":58,"value":457},". Bring the env up using the\ncommand from ",{"type":53,"tag":75,"props":459,"children":461},{"className":460},[],[462],{"type":58,"value":263},{"type":58,"value":464},", then enumerate via ",{"type":53,"tag":75,"props":466,"children":468},{"className":467},[],[469],{"type":58,"value":173},{"type":58,"value":471}," over\nwp-cli and cross-check against the static inventory. Source-only →\nFAIL (registration not firing). Runtime-only → WARN (dynamic\nregistration path).",{"type":53,"tag":350,"props":473,"children":475},{"id":474},"_4-annotation-correctness-the-adversarial-core",[476],{"type":58,"value":477},"4. Annotation correctness (the adversarial core)",{"type":53,"tag":61,"props":479,"children":480},{},[481,482,487],{"type":58,"value":360},{"type":53,"tag":75,"props":483,"children":485},{"className":484},[],[486],{"type":58,"value":199},{"type":58,"value":488},". Read each callback body\nand verify it matches the annotation claim:",{"type":53,"tag":120,"props":490,"children":491},{},[492,502,513],{"type":53,"tag":124,"props":493,"children":494},{},[495,500],{"type":53,"tag":75,"props":496,"children":498},{"className":497},[],[499],{"type":58,"value":80},{"type":58,"value":501}," → callback must not write to the database, the\noptions table, post \u002F user \u002F term \u002F comment data, the filesystem,\ncron, or via non-GET HTTP \u002F REST delegates.",{"type":53,"tag":124,"props":503,"children":504},{},[505,511],{"type":53,"tag":75,"props":506,"children":508},{"className":507},[],[509],{"type":58,"value":510},"destructive: false",{"type":58,"value":512}," → callback must not delete, refund, void,\ncancel, or trash.",{"type":53,"tag":124,"props":514,"children":515},{},[516,521,523,529,531,537],{"type":53,"tag":75,"props":517,"children":519},{"className":518},[],[520],{"type":58,"value":181},{"type":58,"value":522}," → repeated calls with the same input have no\nadditional effect on the environment (per the ",{"type":53,"tag":75,"props":524,"children":526},{"className":525},[],[527],{"type":58,"value":528},"idempotent",{"type":58,"value":530},"\nannotation's docblock in ",{"type":53,"tag":75,"props":532,"children":534},{"className":533},[],[535],{"type":58,"value":536},"class-wp-ability.php",{"type":58,"value":538},"). Static catches\ncounter writes and per-call cron schedules; runtime adds a\ntwin-invocation heuristic for visible state changes.",{"type":53,"tag":61,"props":540,"children":541},{},[542],{"type":58,"value":543},"The reference lists common write patterns as a starting set, not a\nchecklist — plugin vocabularies vary, and the agent extends with verbs\nspecific to the plugin under verification.",{"type":53,"tag":61,"props":545,"children":546},{},[547,549,555],{"type":58,"value":548},"False positives get suppressed via an inline ",{"type":53,"tag":75,"props":550,"children":552},{"className":551},[],[553],{"type":58,"value":554},"\u002F\u002F verify-ignore: \u003Cannotation> -- \u003Creason>",{"type":58,"value":556}," comment.",{"type":53,"tag":350,"props":558,"children":560},{"id":559},"_5-permission-roundtrip",[561],{"type":58,"value":562},"5. Permission roundtrip",{"type":53,"tag":61,"props":564,"children":565},{},[566,567,573,575,581,583,589,591,597,599,605],{"type":58,"value":360},{"type":53,"tag":75,"props":568,"children":570},{"className":569},[],[571],{"type":58,"value":572},"references\u002Fpermission-roundtrip.md",{"type":58,"value":574},". Static: classify each\n",{"type":53,"tag":75,"props":576,"children":578},{"className":577},[],[579],{"type":58,"value":580},"permission_callback",{"type":58,"value":582}," against the six shapes (preferred Shape A\n",{"type":53,"tag":75,"props":584,"children":586},{"className":585},[],[587],{"type":58,"value":588},"current_user_can(...)",{"type":58,"value":590},"; FAIL on Shape B-bad ",{"type":53,"tag":75,"props":592,"children":594},{"className":593},[],[595],{"type":58,"value":596},"WP_REST_Request",{"type":58,"value":598},"\npatterns or Shape E literal ",{"type":53,"tag":75,"props":600,"children":602},{"className":601},[],[603],{"type":58,"value":604},"true",{"type":58,"value":606},"). Runtime: anon and subscriber\ndenied; admin allowed (unless deliberately public). When an audit was\nprovided, cross-check the registered cap against the audit's declared\ngate.",{"type":53,"tag":350,"props":608,"children":610},{"id":609},"_6-schema-lints",[611],{"type":58,"value":612},"6. Schema lints",{"type":53,"tag":61,"props":614,"children":615},{},[616,617,623,625,631,633,639,641,647,649,655],{"type":58,"value":360},{"type":53,"tag":75,"props":618,"children":620},{"className":619},[],[621],{"type":58,"value":622},"references\u002Fschema-lints.md",{"type":58,"value":624},". Six small principles applied to\neach ability's ",{"type":53,"tag":75,"props":626,"children":628},{"className":627},[],[629],{"type":58,"value":630},"input_schema",{"type":58,"value":632},": object schemas declare\n",{"type":53,"tag":75,"props":634,"children":636},{"className":635},[],[637],{"type":58,"value":638},"additionalProperties",{"type":58,"value":640},"; required fields have descriptions; enums\nnon-empty; no ",{"type":53,"tag":75,"props":642,"children":644},{"className":643},[],[645],{"type":58,"value":646},"$ref",{"type":58,"value":648},"; defaults are statically constant (including\n",{"type":53,"tag":75,"props":650,"children":652},{"className":651},[],[653],{"type":58,"value":654},"(object) array()",{"type":58,"value":656},"); reference abilities have no required inputs.",{"type":53,"tag":61,"props":658,"children":659},{},[660,662,668,670,676],{"type":58,"value":661},"Cross-reference ",{"type":53,"tag":75,"props":663,"children":665},{"className":664},[],[666],{"type":58,"value":667},"..\u002Fwp-abilities-api\u002Freferences\u002Finput-schema-gotchas.md",{"type":58,"value":669},"\nfor the four runtime gotchas (defaults not injected on the\nproperty-level path, pagination key drift, ",{"type":53,"tag":75,"props":671,"children":673},{"className":672},[],[674],{"type":58,"value":675},"empty()",{"type":58,"value":677}," on string IDs,\ndirect vs indirect invocation strictness).",{"type":53,"tag":350,"props":679,"children":681},{"id":680},"_7-error-code-vocabulary",[682],{"type":58,"value":683},"7. Error-code vocabulary",{"type":53,"tag":61,"props":685,"children":686},{},[687,688,694,696,702],{"type":58,"value":661},{"type":53,"tag":75,"props":689,"children":691},{"className":690},[],[692],{"type":58,"value":693},"..\u002Fwp-abilities-api\u002Freferences\u002Ferror-code-vocabulary.md",{"type":58,"value":695},".\nInspect each callback's ",{"type":53,"tag":75,"props":697,"children":699},{"className":698},[],[700],{"type":58,"value":701},"WP_Error",{"type":58,"value":703}," returns; non-vocabulary codes →\nWARN.",{"type":53,"tag":113,"props":705,"children":707},{"id":706},"verification",[708],{"type":58,"value":709},"Verification",{"type":53,"tag":61,"props":711,"children":712},{},[713],{"type":58,"value":714},"The run produces a structured markdown report at the user-specified\npath:",{"type":53,"tag":716,"props":717,"children":721},"pre",{"className":718,"code":720,"language":58},[719],"language-text","---\nLast updated: \u003CYYYY-MM-DD HH:MM>\n---\n\n# \u003CPlugin> Abilities Verification — \u003CStatic|Runtime> Mode\n\n## Status: \u003CPASS|WARN|FAIL>\n\n## Audit doc validation (if provided)\n\n## Static inventory\n\n## Annotation correctness\n| Ability | Claim | Result | Evidence |\n|---|---|---|---|\n\n## Permission gates\n\n## Schema lints\n\n## Error-code vocabulary\n",[722],{"type":53,"tag":75,"props":723,"children":725},{"__ignoreMap":724},"",[726],{"type":58,"value":720},{"type":53,"tag":61,"props":728,"children":729},{},[730],{"type":58,"value":731},"Every ability is OK, WARN, or FAIL. A single FAIL → top-line FAIL;\nWARNs without FAILs → WARN; otherwise PASS.",{"type":53,"tag":113,"props":733,"children":735},{"id":734},"failure-modes-debugging",[736],{"type":58,"value":737},"Failure modes \u002F debugging",{"type":53,"tag":120,"props":739,"children":740},{},[741,758,768,785,810],{"type":53,"tag":124,"props":742,"children":743},{},[744,749,751,756],{"type":53,"tag":67,"props":745,"children":746},{},[747],{"type":58,"value":748},"Env not reachable (runtime)",{"type":58,"value":750}," — env-up failed or Docker isn't\nrunning. Re-run ",{"type":53,"tag":75,"props":752,"children":754},{"className":753},[],[755],{"type":58,"value":327},{"type":58,"value":757},", then fix the env. Don't fall\nback silently to static without noting it in the report.",{"type":53,"tag":124,"props":759,"children":760},{},[761,766],{"type":53,"tag":67,"props":762,"children":763},{},[764],{"type":58,"value":765},"No abilities in source",{"type":58,"value":767}," — return a clear \"nothing to verify\"\nreport.",{"type":53,"tag":124,"props":769,"children":770},{},[771,776,778,783],{"type":53,"tag":67,"props":772,"children":773},{},[774],{"type":58,"value":775},"Audit schema mismatch",{"type":58,"value":777}," — point at\n",{"type":53,"tag":75,"props":779,"children":781},{"className":780},[],[782],{"type":58,"value":366},{"type":58,"value":784},"; don't auto-fix the audit.",{"type":53,"tag":124,"props":786,"children":787},{},[788,793,795,801,803,808],{"type":53,"tag":67,"props":789,"children":790},{},[791],{"type":58,"value":792},"False positive on readonly-writes",{"type":58,"value":794}," — see the ",{"type":53,"tag":75,"props":796,"children":798},{"className":797},[],[799],{"type":58,"value":800},"\u002F\u002F verify-ignore",{"type":58,"value":802},"\nmechanism in ",{"type":53,"tag":75,"props":804,"children":806},{"className":805},[],[807],{"type":58,"value":199},{"type":58,"value":809},". Document why\neach suppression is legitimate.",{"type":53,"tag":124,"props":811,"children":812},{},[813,818],{"type":53,"tag":67,"props":814,"children":815},{},[816],{"type":58,"value":817},"Runtime enumeration smaller than static",{"type":58,"value":819}," — registration hook\nisn't firing. Check init hook timing, activation state, autoloader\norder.",{"type":53,"tag":113,"props":821,"children":823},{"id":822},"escalation",[824],{"type":58,"value":825},"Escalation",{"type":53,"tag":120,"props":827,"children":828},{},[829,842],{"type":53,"tag":124,"props":830,"children":831},{},[832,834,840],{"type":58,"value":833},"Recurring legitimate pattern that trips the adversarial check across\nmultiple plugins → propose adding it to the suppression guidance in\n",{"type":53,"tag":75,"props":835,"children":837},{"className":836},[],[838],{"type":58,"value":839},"annotation-correctness.md",{"type":58,"value":841},". Don't broaden the candidate-pattern\nlist speculatively.",{"type":53,"tag":124,"props":843,"children":844},{},[845,847,853,855,860],{"type":58,"value":846},"Audit-schema validator rejects a legitimate audit → the canonical\nschema in ",{"type":53,"tag":75,"props":848,"children":850},{"className":849},[],[851],{"type":58,"value":852},"..\u002Fwp-abilities-audit\u002Freferences\u002Faudit-schema.md",{"type":58,"value":854}," has\nevolved. Update ",{"type":53,"tag":75,"props":856,"children":858},{"className":857},[],[859],{"type":58,"value":366},{"type":58,"value":861}," to match.",{"type":53,"tag":113,"props":863,"children":865},{"id":864},"out-of-scope",[866],{"type":58,"value":867},"Out of scope",{"type":53,"tag":61,"props":869,"children":870},{},[871,873,879],{"type":58,"value":872},"Token-budget measurement is a separate verification axis — an\nannotation-clean, schema-clean, runtime-passing ability set can still\nbe unshippable if its ",{"type":53,"tag":75,"props":874,"children":876},{"className":875},[],[877],{"type":58,"value":878},"tools\u002Flist",{"type":58,"value":880}," form burns through an agent's\ncontext budget. That axis is tracked separately. Do not aggregate\nmanual or external measurement into this skill's PASS \u002F FAIL verdict.",{"items":882,"total":992},[883,894,911,925,945,956,976],{"slug":884,"name":884,"fn":885,"description":886,"org":887,"tags":888,"stars":35,"repoUrl":36,"updatedAt":893},"blueprint","create WordPress Playground blueprint files","Use when the deliverable is WordPress Playground Blueprint JSON or a Blueprint bundle, including creating, editing, reviewing, validating schema keys, choosing steps\u002Fresources, and debugging Blueprint files. For only running or sharing a Playground environment, use wp-playground.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[889,890],{"name":9,"slug":8,"type":15},{"name":891,"slug":892,"type":15},"WordPress Playground","wordpress-playground","2026-07-27T06:08:32.306955",{"slug":895,"name":895,"fn":896,"description":897,"org":898,"tags":899,"stars":35,"repoUrl":36,"updatedAt":910},"wordpress-router","route WordPress codebase tasks","Use when the user asks about WordPress codebases (plugins, themes, block themes, Gutenberg blocks, WP core checkouts) and you need to quickly classify the repo and route to the correct workflow\u002Fskill (blocks, theme.json, REST API, WP-CLI, performance, security, testing, release packaging).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[900,903,906,907],{"name":901,"slug":902,"type":15},"Engineering","engineering",{"name":904,"slug":905,"type":15},"Triage","triage",{"name":9,"slug":8,"type":15},{"name":908,"slug":909,"type":15},"Workflow Automation","workflow-automation","2026-04-06T18:58:21.644368",{"slug":912,"name":912,"fn":913,"description":914,"org":915,"tags":916,"stars":35,"repoUrl":36,"updatedAt":924},"wp-abilities-api","manage WordPress Abilities API definitions","Use when working with the WordPress Abilities API (wp_register_ability, wp_register_ability_category, \u002Fwp-json\u002Fwp-abilities\u002Fv1\u002F*, @wordpress\u002Fabilities) including defining abilities, categories, meta, REST exposure, and permissions checks for clients.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[917,920,923],{"name":918,"slug":919,"type":15},"Access Control","access-control",{"name":921,"slug":922,"type":15},"API Development","api-development",{"name":9,"slug":8,"type":15},"2026-04-06T18:58:17.857773",{"slug":109,"name":109,"fn":926,"description":927,"org":928,"tags":929,"stars":35,"repoUrl":36,"updatedAt":944},"audit WordPress plugins for Abilities API registration","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.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[930,931,934,935,938,939,940,941],{"name":20,"slug":21,"type":15},{"name":932,"slug":933,"type":15},"Audit","audit",{"name":30,"slug":31,"type":15},{"name":936,"slug":937,"type":15},"Documentation","documentation",{"name":24,"slug":25,"type":15},{"name":27,"slug":28,"type":15},{"name":9,"slug":8,"type":15},{"name":942,"slug":943,"type":15},"YAML","yaml","2026-05-28T06:48:49.361753",{"slug":4,"name":4,"fn":5,"description":6,"org":946,"tags":947,"stars":35,"repoUrl":36,"updatedAt":37},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[948,949,950,951,952,953,954,955],{"name":20,"slug":21,"type":15},{"name":30,"slug":31,"type":15},{"name":24,"slug":25,"type":15},{"name":27,"slug":28,"type":15},{"name":13,"slug":14,"type":15},{"name":33,"slug":34,"type":15},{"name":17,"slug":18,"type":15},{"name":9,"slug":8,"type":15},{"slug":957,"name":957,"fn":958,"description":959,"org":960,"tags":961,"stars":35,"repoUrl":36,"updatedAt":975},"wp-block-development","develop WordPress Gutenberg blocks","Use when developing WordPress (Gutenberg) blocks: block.json metadata, register_block_type(_from_metadata), attributes\u002Fserialization, supports, dynamic rendering (render.php\u002Frender_callback), deprecations\u002Fmigrations, viewScript vs viewScriptModule, and @wordpress\u002Fscripts\u002F@wordpress\u002Fcreate-block build and test workflows.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[962,965,968,971,974],{"name":963,"slug":964,"type":15},"Frontend","frontend",{"name":966,"slug":967,"type":15},"PHP","php",{"name":969,"slug":970,"type":15},"React","react",{"name":972,"slug":973,"type":15},"UI Components","ui-components",{"name":9,"slug":8,"type":15},"2026-04-06T18:58:24.172876",{"slug":977,"name":977,"fn":978,"description":979,"org":980,"tags":981,"stars":35,"repoUrl":36,"updatedAt":991},"wp-block-themes","develop WordPress block themes","Use when developing WordPress block themes: theme.json (global settings\u002Fstyles), templates and template parts, patterns, style variations, and Site Editor troubleshooting (style hierarchy, overrides, caching).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[982,985,986,989,990],{"name":983,"slug":984,"type":15},"Design","design",{"name":963,"slug":964,"type":15},{"name":987,"slug":988,"type":15},"Themes","themes",{"name":972,"slug":973,"type":15},{"name":9,"slug":8,"type":15},"2026-04-06T18:58:27.909889",18,{"items":994,"total":992},[995,1000,1007,1013,1024,1035,1043,1051,1064,1079,1099,1112],{"slug":884,"name":884,"fn":885,"description":886,"org":996,"tags":997,"stars":35,"repoUrl":36,"updatedAt":893},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[998,999],{"name":9,"slug":8,"type":15},{"name":891,"slug":892,"type":15},{"slug":895,"name":895,"fn":896,"description":897,"org":1001,"tags":1002,"stars":35,"repoUrl":36,"updatedAt":910},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1003,1004,1005,1006],{"name":901,"slug":902,"type":15},{"name":904,"slug":905,"type":15},{"name":9,"slug":8,"type":15},{"name":908,"slug":909,"type":15},{"slug":912,"name":912,"fn":913,"description":914,"org":1008,"tags":1009,"stars":35,"repoUrl":36,"updatedAt":924},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1010,1011,1012],{"name":918,"slug":919,"type":15},{"name":921,"slug":922,"type":15},{"name":9,"slug":8,"type":15},{"slug":109,"name":109,"fn":926,"description":927,"org":1014,"tags":1015,"stars":35,"repoUrl":36,"updatedAt":944},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1016,1017,1018,1019,1020,1021,1022,1023],{"name":20,"slug":21,"type":15},{"name":932,"slug":933,"type":15},{"name":30,"slug":31,"type":15},{"name":936,"slug":937,"type":15},{"name":24,"slug":25,"type":15},{"name":27,"slug":28,"type":15},{"name":9,"slug":8,"type":15},{"name":942,"slug":943,"type":15},{"slug":4,"name":4,"fn":5,"description":6,"org":1025,"tags":1026,"stars":35,"repoUrl":36,"updatedAt":37},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1027,1028,1029,1030,1031,1032,1033,1034],{"name":20,"slug":21,"type":15},{"name":30,"slug":31,"type":15},{"name":24,"slug":25,"type":15},{"name":27,"slug":28,"type":15},{"name":13,"slug":14,"type":15},{"name":33,"slug":34,"type":15},{"name":17,"slug":18,"type":15},{"name":9,"slug":8,"type":15},{"slug":957,"name":957,"fn":958,"description":959,"org":1036,"tags":1037,"stars":35,"repoUrl":36,"updatedAt":975},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1038,1039,1040,1041,1042],{"name":963,"slug":964,"type":15},{"name":966,"slug":967,"type":15},{"name":969,"slug":970,"type":15},{"name":972,"slug":973,"type":15},{"name":9,"slug":8,"type":15},{"slug":977,"name":977,"fn":978,"description":979,"org":1044,"tags":1045,"stars":35,"repoUrl":36,"updatedAt":991},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1046,1047,1048,1049,1050],{"name":983,"slug":984,"type":15},{"name":963,"slug":964,"type":15},{"name":987,"slug":988,"type":15},{"name":972,"slug":973,"type":15},{"name":9,"slug":8,"type":15},{"slug":1052,"name":1052,"fn":1053,"description":1054,"org":1055,"tags":1056,"stars":35,"repoUrl":36,"updatedAt":1063},"wp-interactivity-api","build interactive features with WordPress Interactivity API","Use when building or debugging WordPress Interactivity API features (data-wp-* directives, @wordpress\u002Finteractivity store\u002Fstate\u002Factions, block viewScriptModule integration, wp_interactivity_*()) including performance, hydration, and directive behavior.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1057,1058,1059,1062],{"name":921,"slug":922,"type":15},{"name":963,"slug":964,"type":15},{"name":1060,"slug":1061,"type":15},"JavaScript","javascript",{"name":9,"slug":8,"type":15},"2026-04-06T18:58:20.397676",{"slug":1065,"name":1065,"fn":1066,"description":1067,"org":1068,"tags":1069,"stars":35,"repoUrl":36,"updatedAt":1078},"wp-patterns","generate WordPress block patterns","Generate technically correct, design-distinctive WordPress block patterns. Use when creating block patterns, starter page patterns, template patterns, template part patterns, or improving pattern design quality. Covers pattern registration (PHP headers, auto\u002Fmanual), block markup syntax, theme.json design tokens, categories, template types, accessibility, and i18n\u002Fescaping.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1070,1073,1074,1077],{"name":1071,"slug":1072,"type":15},"Block Editor","block-editor",{"name":983,"slug":984,"type":15},{"name":1075,"slug":1076,"type":15},"Templates","templates",{"name":9,"slug":8,"type":15},"2026-07-24T05:38:43.101238",{"slug":1080,"name":1080,"fn":1081,"description":1082,"org":1083,"tags":1084,"stars":35,"repoUrl":36,"updatedAt":1098},"wp-performance","investigate and improve WordPress performance","Use when investigating or improving WordPress performance (backend-only agent): profiling and measurement (WP-CLI profile\u002Fdoctor, Server-Timing, Query Monitor via REST headers), database\u002Fquery optimization, autoloaded options, object caching, cron, HTTP API calls, and safe verification.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1085,1088,1091,1094,1097],{"name":1086,"slug":1087,"type":15},"Backend","backend",{"name":1089,"slug":1090,"type":15},"Database","database",{"name":1092,"slug":1093,"type":15},"Performance","performance",{"name":1095,"slug":1096,"type":15},"SQL","sql",{"name":9,"slug":8,"type":15},"2026-04-06T18:58:22.909053",{"slug":1100,"name":1100,"fn":1101,"description":1102,"org":1103,"tags":1104,"stars":35,"repoUrl":36,"updatedAt":1111},"wp-phpstan","run PHPStan static analysis on WordPress projects","Use when configuring, running, or fixing PHPStan static analysis in WordPress projects (plugins\u002Fthemes\u002Fsites): phpstan.neon setup, baselines, WordPress-specific typing, and handling third-party plugin classes.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1105,1106,1107,1110],{"name":30,"slug":31,"type":15},{"name":966,"slug":967,"type":15},{"name":1108,"slug":1109,"type":15},"QA","qa",{"name":9,"slug":8,"type":15},"2026-04-06T18:58:15.318063",{"slug":1113,"name":1113,"fn":1114,"description":1115,"org":1116,"tags":1117,"stars":35,"repoUrl":36,"updatedAt":1126},"wp-playground","manage WordPress Playground instances","Use as the WordPress Playground routing wrapper for ambiguous Playground work, local CLI runs with @wp-playground\u002Fcli, playground.wordpress.net share links, browser previews, snapshots, mounts, version switching, and Xdebug. For Blueprint JSON authoring or review, use the blueprint skill directly.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1118,1121,1124,1125],{"name":1119,"slug":1120,"type":15},"Local Development","local-development",{"name":1122,"slug":1123,"type":15},"Sandboxing","sandboxing",{"name":9,"slug":8,"type":15},{"name":891,"slug":892,"type":15},"2026-07-27T06:08:31.31025"]