{"id":337342,"date":"2026-07-15T17:47:50","date_gmt":"2026-07-15T17:47:50","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/agent-toolbelt-safe-site-operations-for-ai-agents\/"},"modified":"2026-07-15T21:39:11","modified_gmt":"2026-07-15T21:39:11","slug":"agent-toolbelt","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/agent-toolbelt\/","author":15605758,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.3.1","stable_tag":"1.3.1","tested":"7.0.1","requires":"6.9","requires_php":"7.4","requires_plugins":null,"header_name":"Agent Toolbelt \u2013 Safe Site Operations for AI Agents","header_author":"Kostya Tereshchuk","header_description":"Guardrailed WordPress abilities (purge caches, maintenance mode, plugin updates and more) for AI agents and automation, with dry-run, confirm tokens and a full audit log.","assets_banners_color":"074356","last_updated":"2026-07-15 21:39:11","external_support_url":"","external_repository_url":"","donate_link":"https:\/\/tutori.org\/donate\/","header_plugin_uri":"","header_author_uri":"https:\/\/tutori.org\/kostya\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":46,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"kostyatereshchuk","date":"2026-07-15 17:47:38"},"1.1.0":{"tag":"1.1.0","author":"kostyatereshchuk","date":"2026-07-15 18:14:34"},"1.2.0":{"tag":"1.2.0","author":"kostyatereshchuk","date":"2026-07-15 19:44:01"},"1.3.0":{"tag":"1.3.0","author":"kostyatereshchuk","date":"2026-07-15 21:14:22"},"1.3.1":{"tag":"1.3.1","author":"kostyatereshchuk","date":"2026-07-15 21:39:11"}},"upgrade_notice":{"1.3.1":"<p>The plugin page moved from Tools to Settings (Settings \u2192 Agent Toolbelt), with a Settings link on the Plugins row. No functional changes; existing settings are preserved.<\/p>","1.3.0":"<p>Three diagnosis upgrades: read-debug-log (redacted, bounded, on by default), plugin checksum verification (scope=plugin), and list-available-updates; plus full MCP annotation hints and an agent_protocol block in site-status. No breaking changes; existing settings are preserved.<\/p>","1.2.0":"<p>MCP-native (official MCP Adapter picks up enabled abilities automatically), three new read-only diagnostics (inspect-cron, verify-checksums, run-site-health-checks), and a Connect-your-agent onboarding section. No breaking changes; existing settings are preserved.<\/p>","1.1.0":"<p>Two new abilities (thumbnail regeneration; opt-in database cleanup) and stronger guardrails: observe mode, hourly rate budgets, denied-attempt logging, and high-risk email notifications. No breaking changes; existing settings are preserved.<\/p>","1.0.0":"<p>First release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3609269,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3609269,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3609269,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3609269,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0","1.1.0","1.2.0","1.3.0","1.3.1"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3609425,"resolution":"1","location":"assets","locale":"","width":2176,"height":3106},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3609306,"resolution":"2","location":"assets","locale":"","width":2176,"height":636},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3609269,"resolution":"3","location":"assets","locale":"","width":1896,"height":1462},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3609442,"resolution":"4","location":"assets","locale":"","width":2176,"height":1550}},"screenshots":{"1":"The ability checklist with risk badges \u2014 enable exactly what your agent may do.","2":"The audit log \u2014 every operation with caller, user, input digest and result.","3":"Dry-run first, then the one-time confirm token, then execute: a safe plugin update round-trip.","4":"Connect your agent \u2014 your site's endpoints, a one-click application-password link, and a copyable agent briefing."}},"plugin_section":[],"plugin_tags":[251511,232494,8534,1281,242115],"plugin_category":[],"plugin_contributors":[270067],"plugin_business_model":[],"class_list":["post-337342","plugin","type-plugin","status-publish","hentry","plugin_tags-abilities","plugin_tags-ai-agent","plugin_tags-audit-log","plugin_tags-maintenance-mode","plugin_tags-mcp","plugin_contributors-kostyatereshchuk","plugin_committers-kostyatereshchuk"],"banners":{"banner":"https:\/\/ps.w.org\/agent-toolbelt\/assets\/banner-772x250.png?rev=3609269","banner_2x":"https:\/\/ps.w.org\/agent-toolbelt\/assets\/banner-1544x500.png?rev=3609269","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/agent-toolbelt\/assets\/icon-128x128.png?rev=3609269","icon_2x":"https:\/\/ps.w.org\/agent-toolbelt\/assets\/icon-256x256.png?rev=3609269","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/agent-toolbelt\/assets\/screenshot-1.png?rev=3609425","caption":"The ability checklist with risk badges \u2014 enable exactly what your agent may do."},{"src":"https:\/\/ps.w.org\/agent-toolbelt\/assets\/screenshot-2.png?rev=3609306","caption":"The audit log \u2014 every operation with caller, user, input digest and result."},{"src":"https:\/\/ps.w.org\/agent-toolbelt\/assets\/screenshot-3.png?rev=3609269","caption":"Dry-run first, then the one-time confirm token, then execute: a safe plugin update round-trip."},{"src":"https:\/\/ps.w.org\/agent-toolbelt\/assets\/screenshot-4.png?rev=3609442","caption":"Connect your agent \u2014 your site's endpoints, a one-click application-password link, and a copyable agent briefing."}],"raw_content":"<!--section=description-->\n<p>AI agents can now operate WordPress sites \u2014 through the WordPress Abilities API, MCP, and WP-CLI. That's powerful, and it's also exactly how a confused or manipulated agent breaks a site.<\/p>\n\n<p>Agent Toolbelt gives your agent a small set of maintenance operations it can use <strong>safely<\/strong>: every operation can be previewed without changing anything, the dangerous ones require an explicit look-then-act confirmation, everything is recorded in an audit log you can read later, and the riskiest abilities are off until you personally turn them on.<\/p>\n\n<p>Content-focused MCP plugins let agents edit posts and products. Agent Toolbelt is the <strong>operations layer<\/strong>: plugin updates with automatic rollback, caches, maintenance windows, database cleanup, and diagnosis \u2014 the debug log (with secrets redacted), pending updates, cron, Site Health, and file-integrity checks for core and plugins \u2014 with the guardrails as the product.<\/p>\n\n<h4>The abilities<\/h4>\n\n<ul>\n<li><strong>Site status<\/strong> <em>(read-only)<\/em> \u2014 WordPress\/PHP\/database versions, environment, active theme, plugin counts, pending updates, the latest Site Health summary, which toolbelt abilities are enabled, and whether observe mode is on. The agent's natural first call.<\/li>\n<li><strong>Purge all caches<\/strong> <em>(low risk)<\/em> \u2014 clears the page cache (12 supported cache plugins: WP Rocket, LiteSpeed Cache, W3 Total Cache, WP Super Cache, WP Fastest Cache, WP-Optimize, Breeze, Cache Enabler, Hummingbird, SiteGround Optimizer, Swift Performance, Comet Cache), the object cache, and expired transients.<\/li>\n<li><strong>Flush rewrite rules<\/strong> <em>(low risk)<\/em> \u2014 fixes pretty permalinks returning 404 after plugins or post types change.<\/li>\n<li><strong>Maintenance mode<\/strong> <em>(medium risk)<\/em> \u2014 turns the visitor-facing maintenance page on or off. <strong>It always auto-expires<\/strong> (5 minutes by default, 60 max): even if the agent forgets to turn it off, your site can never stay locked. Logged-in administrators keep seeing the normal site, and the REST API and wp-admin stay reachable the whole time.<\/li>\n<li><strong>Read audit log<\/strong> <em>(read-only)<\/em> \u2014 what ran, when, by which caller, and the result. Lets the agent (or you) review and explain past actions, and filter for refused (<code>denied<\/code>) attempts.<\/li>\n<li><strong>Inspect cron<\/strong> <em>(read-only)<\/em> \u2014 lists WP-Cron scheduled events with next-run times and an overdue count. The first thing to check when scheduled posts, emails, or backups seem stuck. Event arguments are digested, never exposed raw.<\/li>\n<li><strong>Verify checksums<\/strong> <em>(read-only)<\/em> \u2014 checks files against the official WordPress.org checksums and reports modified, missing, and unexpected files. Covers WordPress core, and \u2014 new in 1.3 \u2014 <strong>installed plugins<\/strong> (one or all): plugins WordPress.org has no checksums for (premium, custom, single-file) are honestly reported as skipped, never as clean. For \"was this site tampered with?\" moments.<\/li>\n<li><strong>Run Site Health checks<\/strong> <em>(read-only)<\/em> \u2014 runs WordPress's own Site Health tests server-side and returns fresh, timestamped results. WordPress only refreshes Site Health when a human opens wp-admin, so a site managed by an agent otherwise reports stale numbers \u2014 this closes that gap.<\/li>\n<li><strong>Read debug log<\/strong> <em>(read-only)<\/em> \u2014 the newest entries from wp-content\/debug.log with PHP stack traces grouped to their error, filterable by severity, time, or substring. Secrets (API keys, tokens, cookies), absolute paths, emails, and IP addresses are redacted before the content leaves your site. When the site errors, this is the agent's \"what is actually broken?\" call.<\/li>\n<li><strong>List available updates<\/strong> <em>(read-only)<\/em> \u2014 the actionable list of pending plugin, theme, and core updates with current and new versions, active and auto-update flags. site-status gives the counts; this gives the plan \u2014 and pairs with update-plugin to apply it safely.<\/li>\n<li><strong>Regenerate thumbnails<\/strong> <em>(medium risk)<\/em> \u2014 finds image attachments whose registered thumbnail sizes are missing and generates ONLY the missing files. It never deletes or overwrites existing images; work is batched with a time budget, so the agent simply calls again to continue.<\/li>\n<li><strong>Update plugin<\/strong> <em>(high risk, disabled by default)<\/em> \u2014 updates one plugin with a safety net; see below.<\/li>\n<li><strong>Clean up database<\/strong> <em>(high risk, disabled by default)<\/em> \u2014 deletes database clutter by category: post revisions, abandoned auto-drafts (older than 7 days), trashed posts, spam and trashed comments, expired transients, and orphaned meta rows whose parent object is gone. The dry-run reports exact per-category counts and returns a confirm token; execution requires that token with the same input. Deletions are batched (500 posts\/comments, 2,000 meta rows per category per call) and content always goes through core functions, so delete hooks fire and caches stay consistent.<\/li>\n<\/ul>\n\n<h4>Safe plugin updates with automatic rollback<\/h4>\n\n<p>The flagship ability. When you enable it, an agent can update a plugin like this \u2014 and only like this:<\/p>\n\n<ol>\n<li><strong>Dry-run first (forced).<\/strong> The ability defaults to preview mode: it reports the installed and available versions and returns a one-time confirm token. Nothing changes.<\/li>\n<li><strong>Confirm to execute.<\/strong> The real update requires that token back. It is bound to the exact plugin, the exact user, and expires in 15 minutes. A single injected prompt cannot one-shot an update \u2014 the agent must look, then act.<\/li>\n<li><strong>Backup, update, health check.<\/strong> The update runs on WordPress core's own upgrader, which keeps a temporary backup of the current version. Afterwards the plugin checks that your site still responds: it fetches the home page and the REST API as an anonymous visitor and scans for fatal errors.<\/li>\n<li><strong>Automatic rollback.<\/strong> If the site broke, the previous version is restored automatically \u2014 and the audit log records <code>rolled_back<\/code> so everyone knows what happened.<\/li>\n<\/ol>\n\n<p>The ability refuses to update Agent Toolbelt itself, refuses single-file plugins (WordPress core cannot back them up, so the rollback promise can't be kept), refuses when no update is available, and refuses on multisite.<\/p>\n\n<h4>Built for the prompt-injection era<\/h4>\n\n<p>The canonical agent-security failure is indirect prompt injection: malicious content on a page tricks your own agent into calling destructive tools (see OWASP LLM Top 10, LLM01). No plugin can make a gullible agent smart \u2014 what it can do is shrink the blast radius:<\/p>\n\n<ul>\n<li><strong>Non-destructive by default.<\/strong> Read-only and low-risk operations only, until you opt in to more.<\/li>\n<li><strong>Dry-run everywhere.<\/strong> Every mutating ability accepts a preview mode; the high-risk ones default to it.<\/li>\n<li><strong>Look-then-act confirmation<\/strong> for the destructive abilities \u2014 one-time, input-bound, expiring tokens.<\/li>\n<li><strong>Observe mode.<\/strong> One checkbox (or the <code>AGENT_TOOLBELT_OBSERVE<\/code> constant) makes the whole toolbelt read-only: agents can still inspect the site and preview operations, but every real change is refused with a clear reason until you switch it back.<\/li>\n<li><strong>Hourly rate budget.<\/strong> Real executions are capped per user per hour (5 high-risk, 30 total by default; filterable) \u2014 a runaway or manipulated agent stalls at the circuit breaker instead of stampeding through your site. Dry-runs and read-only calls are never limited, so diagnosis stays free.<\/li>\n<li><strong>Least privilege.<\/strong> Every call requires a logged-in user with <code>manage_options<\/code>; plugin updates additionally require <code>update_plugins<\/code>. Anonymous callers can't even see the abilities.<\/li>\n<li><strong>Disabled means invisible.<\/strong> An ability you turn off is not registered at all \u2014 agents don't see a \"forbidden\" tool, they see no tool.<\/li>\n<li><strong>Everything audited \u2014 including refusals.<\/strong> Each execution writes who called (REST, WP-CLI, admin), as what user, with what input digest, and the result \u2014 kept 90 days, capped at 2,000 rows. Refused attempts (disabled ability, observe mode, over-budget, bad confirm token) are logged as <code>denied<\/code>, with anti-flood capping.<\/li>\n<li><strong>Email heads-up.<\/strong> After every real high-risk execution the site admin gets a plain-text email with the who\/what\/result (on by default, one checkbox to turn off).<\/li>\n<li><strong>Kill switch.<\/strong> Add <code>define( 'AGENT_TOOLBELT_DISABLED', true );<\/code> to <code>wp-config.php<\/code> and nothing registers anywhere \u2014 abilities, REST, WP-CLI, all gone until you remove the line.<\/li>\n<\/ul>\n\n<h4>Connect your AI agent<\/h4>\n\n<p>The abilities are standard WordPress Abilities, so anything that speaks the Abilities API can use them. The fastest path, with no extra plugins, is the WordPress REST API:<\/p>\n\n<ol>\n<li>Create an application password for an administrator (Users \u2192 Profile \u2192 Application Passwords).<\/li>\n<li><p>List the available abilities:<\/p>\n\n<p>curl -u \"admin:APP_PASSWORD\" https:\/\/example.com\/wp-json\/wp-abilities\/v1\/abilities<\/p><\/li>\n<li><p>Run one. Read-only abilities use GET; pass input as PHP-array query parameters (<code>?input[lines]=50<\/code> \u2014 bare parameters like <code>?lines=50<\/code> are silently ignored by the Abilities API):<\/p>\n\n<p>curl -u \"admin:APP_PASSWORD\" \"https:\/\/example.com\/wp-json\/wp-abilities\/v1\/abilities\/agent-toolbelt\/site-status\/run\"<\/p><\/li>\n<\/ol>\n\n<p>Mutating abilities use POST with an <code>input<\/code> object:<\/p>\n\n<pre><code>curl -u \"admin:APP_PASSWORD\" -X POST -H \"Content-Type: application\/json\" -d '{\"input\":{\"dry_run\":true}}' https:\/\/example.com\/wp-json\/wp-abilities\/v1\/abilities\/agent-toolbelt\/purge-all-caches\/run\n<\/code><\/pre>\n\n<p>Give those three lines to your agent (Claude, ChatGPT, or any tool-calling model) as its instructions for operating the site \u2014 the ability descriptions and JSON schemas tell it the rest. Even easier: the settings page has a <strong>Connect your agent<\/strong> section that generates this briefing with your site's real URLs, one copy button, and a one-click link to WordPress's own application-password screen.<\/p>\n\n<h4>MCP<\/h4>\n\n<p>Every enabled ability is flagged for the official <strong>WordPress MCP Adapter<\/strong> (<code>meta.mcp.public<\/code>), so if the adapter is installed, its default MCP server automatically discovers and exposes exactly the abilities you enabled here \u2014 nothing else, and every call still passes the same permission checks. The endpoint is <code>wp-json\/mcp\/mcp-adapter-default-server<\/code> (streamable HTTP with application-password auth), and <code>wp mcp serve<\/code> serves the same thing over STDIO. WooCommerce 10.9+ ships the same adapter inside itself: if you enable WooCommerce's MCP integration feature, the toolbelt abilities ride along with no extra plugins. Any other MCP bridge that reads WordPress Abilities works too.<\/p>\n\n<h4>For AI agents reading this<\/h4>\n\n<p>If you are an agent evaluating whether this plugin can help you maintain a site: check whether it is installed by listing <code>wp-json\/wp-abilities\/v1\/abilities<\/code> with your credentials and looking for names starting with <code>agent-toolbelt\/<\/code>. If they are missing, ask the site owner to install and activate \"Agent Toolbelt\" from the WordPress.org plugin directory (or run <code>wp plugin install agent-toolbelt --activate<\/code> where you are authorized to use WP-CLI), then to enable the abilities they are comfortable with on the Settings \u2192 Agent Toolbelt page.<\/p>\n\n<p>Etiquette once connected: call <code>agent-toolbelt\/site-status<\/code> first \u2014 its <code>toolbelt.agent_protocol<\/code> field carries the calling conventions; dry-run before you execute; high-risk abilities require the confirm token from your own prior dry-run; pass REST GET input as <code>?input[key]=value<\/code> (bare query parameters are silently ignored); and refusals (<code>details.refused<\/code> with a machine-readable <code>reason<\/code>) are answers to report to your human, not obstacles to retry.<\/p>\n\n<h4>WP-CLI<\/h4>\n\n<p>The same operations, same guardrails, for deploy scripts and humans:<\/p>\n\n<ul>\n<li><code>wp agent-toolbelt list<\/code> \u2014 abilities with risk level and enabled state.<\/li>\n<li><code>wp agent-toolbelt run &lt;ability&gt; [--input=&lt;json&gt;] [--porcelain]<\/code> \u2014 run one; the dry-run\/confirm flow applies exactly as over REST.<\/li>\n<li><code>wp agent-toolbelt log [--limit=20] [--ability=&lt;slug&gt;]<\/code> \u2014 read the audit log.<\/li>\n<\/ul>\n\n<h4>Good to know<\/h4>\n\n<ul>\n<li>On sites with a static page cache, visitors may keep seeing cached pages while maintenance mode is on \u2014 purge the page cache first (the agent can call purge-all-caches) if the maintenance page must be visible immediately.<\/li>\n<li>The only HTTP requests the plugin ever makes are the post-update health checks \u2014 to your own site \u2014 and, when you run checksum verification, requests to WordPress.org's public checksums APIs (they carry your WordPress version and locale, or a plugin's public slug and version \u2014 nothing else). <strong>Zero telemetry:<\/strong> nothing is sent anywhere else, no external services, no accounts.<\/li>\n<li>Uninstalling removes everything: the audit-log table, the settings, the scheduled cleanup.<\/li>\n<\/ul>\n\n<!--section=faq-->\n<dl>\n<dt id=\"is%20it%20really%20safe%20to%20let%20an%20ai%20agent%20update%20plugins%3F\"><h3>Is it really safe to let an AI agent update plugins?<\/h3><\/dt>\n<dd><p>\"Safe\" here means: previewed, confirmed, backed up, health-checked, and rolled back automatically if the site breaks \u2014 with an audit trail. That's more protection than a human clicking \"Update now\" gets. It's still a change to your site, which is why the ability ships disabled and you must enable it deliberately.<\/p><\/dd>\n<dt id=\"what%20stops%20a%20prompt-injected%20agent%20from%20wrecking%20my%20site%3F\"><h3>What stops a prompt-injected agent from wrecking my site?<\/h3><\/dt>\n<dd><p>Several layers: the destructive abilities are off by default; if you enabled them, execution needs a fresh one-time confirm token from a prior dry-run of the same request (a single malicious instruction can't do both steps blindly); every call needs an authenticated administrator \u2014 content on your pages can't call anything by itself; the hourly rate budget stalls a stampede; and observe mode lets you cut all write access with one checkbox while you investigate. The honest part: if your agent has admin credentials and is fully compromised, no plugin can save you \u2014 the toolbelt's job is to make the destructive path narrow, slow, and visible.<\/p><\/dd>\n<dt id=\"why%20does%20update-plugin%20refuse%20single-file%20plugins%20like%20hello%20dolly%3F\"><h3>Why does update-plugin refuse single-file plugins like Hello Dolly?<\/h3><\/dt>\n<dd><p>WordPress core's temporary-backup mechanism skips plugins that live in a single file, so there would be no backup to roll back to. Rather than update without a safety net, the ability refuses and tells the agent to use wp-admin or WP-CLI instead.<\/p><\/dd>\n<dt id=\"does%20it%20work%20on%20multisite%3F\"><h3>Does it work on multisite?<\/h3><\/dt>\n<dd><p>Everything except plugin updates. Network-wide update semantics deserve their own careful design, so on multisite the update ability refuses with a clear reason instead of guessing.<\/p><\/dd>\n<dt id=\"can%20visitors%20or%20logged-out%20agents%20see%20or%20call%20the%20abilities%3F\"><h3>Can visitors or logged-out agents see or call the abilities?<\/h3><\/dt>\n<dd><p>No. Every ability requires a logged-in user with <code>manage_options<\/code> (updates also need <code>update_plugins<\/code>). Anonymous REST calls get a 401, and the abilities don't even appear in the listing for unauthorized users.<\/p><\/dd>\n<dt id=\"how%20do%20i%20turn%20everything%20off%20in%20an%20emergency%3F\"><h3>How do I turn everything off in an emergency?<\/h3><\/dt>\n<dd><p>Two ways: untick abilities on the Settings \u2192 Agent Toolbelt page (they unregister instantly), or add <code>define( 'AGENT_TOOLBELT_DISABLED', true );<\/code> to wp-config.php \u2014 the kill switch unregisters everything: abilities, REST exposure, and the WP-CLI command. There is also a softer option: observe mode (see below) keeps the abilities visible but read-only.<\/p><\/dd>\n<dt id=\"what%20is%20observe%20mode%3F\"><h3>What is observe mode?<\/h3><\/dt>\n<dd><p>A read-only switch for the whole toolbelt. While it is on (checkbox on the settings page, or force it with <code>define( 'AGENT_TOOLBELT_OBSERVE', true );<\/code> in wp-config.php), agents can still call read-only abilities and preview any operation with dry-run, but every real change is refused with the machine-readable reason <code>observe_mode<\/code> and a message telling the agent to ask you. Useful while you are getting to know a new agent, or any time you want eyes-only access without hiding the tools.<\/p><\/dd>\n<dt id=\"can%20a%20runaway%20agent%20execute%20operations%20in%20a%20loop%3F\"><h3>Can a runaway agent execute operations in a loop?<\/h3><\/dt>\n<dd><p>Not for long. Real executions are rate-limited per user with a fixed hourly budget: 5 high-risk and 30 total mutating executions per hour by default (the <code>agent_toolbelt_rate_budgets<\/code> filter changes the numbers; <code>define( 'AGENT_TOOLBELT_NO_RATE_LIMIT', true );<\/code> disables the limit for supervised bulk-maintenance sessions). Over-budget calls are refused with the reason <code>rate_budget<\/code> and a <code>retry_after_s<\/code> hint, and land in the audit log as <code>denied<\/code> \u2014 so a stampeding agent both stalls and leaves a visible trail. Dry-runs and read-only abilities are never counted: diagnosis stays free.<\/p><\/dd>\n<dt id=\"why%20is%20the%20database%20cleanup%20disabled%20by%20default%3F\"><h3>Why is the database cleanup disabled by default?<\/h3><\/dt>\n<dd><p>Because it deletes content \u2014 revisions, trashed posts, spam, orphaned rows. That is exactly what you want from a cleanup, but a tool that can delete rows the moment the plugin activates would contradict what this plugin promises. So you enable it consciously, once, on the settings page. After that the usual guardrails apply: dry-run with exact per-category counts, a one-time confirm token bound to the same input, batched deletes through core functions, and an audit-log entry plus an email for every real execution.<\/p><\/dd>\n<dt id=\"what%20exactly%20does%20cleanup-database%20delete%3F\"><h3>What exactly does cleanup-database delete?<\/h3><\/dt>\n<dd><p>Only well-defined garbage, by category \u2014 and you can pass a <code>categories<\/code> list to run any subset: post revisions; auto-drafts older than 7 days; trashed posts; spam and trashed comments; expired transients; and orphaned post\/comment\/term\/user meta rows whose parent object no longer exists. It never touches published content, drafts, users, terms, or settings. Posts and comments are deleted through WordPress core functions (<code>wp_delete_post<\/code>, <code>wp_delete_comment<\/code>), so cleanup hooks fire and caches stay consistent.<\/p><\/dd>\n<dt id=\"why%20don%27t%20i%20see%20maintenance%20mode%20when%20i%20turn%20it%20on%3F\"><h3>Why don't I see maintenance mode when I turn it on?<\/h3><\/dt>\n<dd><p>If you are logged in as an administrator, that's on purpose \u2014 administrators always see the normal site. Open a private\/incognito window to see what visitors get. Otherwise, a static page cache is probably serving visitors a cached copy: purge the page cache (there's an ability for that) and reload. Maintenance mode always auto-expires, so a forgotten \"on\" can never lock the site permanently.<\/p><\/dd>\n<dt id=\"how%20does%20my%20agent%20discover%20the%20abilities%3F\"><h3>How does my agent discover the abilities?<\/h3><\/dt>\n<dd><p>Three doors, all showing exactly (and only) what you enabled: the WordPress REST API listing at <code>wp-json\/wp-abilities\/v1\/abilities<\/code>; the official MCP Adapter's default server, which picks up the toolbelt's abilities automatically because they carry the <code>meta.mcp.public<\/code> flag; and the Abilities Explorer in the official <code>ai<\/code> plugin, if you use it. The Connect your agent section on the settings page turns this into a copy-paste briefing with your site's real URLs.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20the%20official%20wordpress%20mcp%20adapter%3F\"><h3>Does it work with the official WordPress MCP Adapter?<\/h3><\/dt>\n<dd><p>Yes, out of the box. Enabled abilities are flagged <code>meta.mcp.public<\/code>, which is precisely what the adapter's default server exposes; disabled abilities are not registered at all, so no transport can see them. Every MCP call still runs through the same permission checks, dry-run defaults, confirm tokens, rate budget, and audit log as REST \u2014 the transport changes, the guardrails don't. If you want an ability callable over REST but hidden from MCP, the <code>agent_toolbelt_mcp_public<\/code> filter does that per ability.<\/p><\/dd>\n<dt id=\"can%20read-debug-log%20leak%20my%20secrets%20to%20the%20agent%3F\"><h3>Can read-debug-log leak my secrets to the agent?<\/h3><\/dt>\n<dd><p>The debug log is the one file on a WordPress site that routinely catches secrets \u2014 API keys inside stack traces, database credentials in connection errors, customer emails in mailer failures. That's why redaction is built in and cannot be turned off: provider API keys, JWTs and bearer tokens, database credentials, URL query secrets, auth cookies and nonces, absolute filesystem paths, emails, and IP addresses are all masked before the content leaves your site. Two honest caveats: redaction is best-effort pattern matching (a secret in a format nobody has seen before can slip through \u2014 the response says so), and the search filter deliberately matches the redacted text, so an agent cannot use it to probe whether a specific secret value appears in the log. If that residual risk is still too much for your site, untick the ability \u2014 like everything else, disabled means invisible.<\/p><\/dd>\n<dt id=\"why%20does%20verify-checksums%20skip%20my%20premium%20plugins%3F\"><h3>Why does verify-checksums skip my premium plugins?<\/h3><\/dt>\n<dd><p>WordPress.org only publishes checksums for plugins it distributes. Premium, custom, and single-file plugins have no official reference to compare against, so the ability reports them as <code>skipped<\/code> with a machine-readable reason \u2014 deliberately not as \"clean\", because no evidence is not a clean bill. Agents are told the same in the ability description.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20send%20any%20data%20anywhere%3F\"><h3>Does the plugin send any data anywhere?<\/h3><\/dt>\n<dd><p>Almost never, and never about you. The only HTTP requests it makes are health-check requests to your own site after a plugin update, and \u2014 only when you run verify-checksums \u2014 requests to WordPress.org's public checksums APIs carrying your WordPress version and locale (core scope) or a plugin's public slug and version (plugin scope). There is no telemetry, no phoning home, no external service.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.3.1<\/h4>\n\n<ul>\n<li>The plugin page moved from Tools to Settings (Settings \u2192 Agent Toolbelt) \u2014 where the refusal messages and the high-risk email already pointed, and where users expect a plugin's settings to live.<\/li>\n<li>The Plugins screen row now has a Settings action link next to Deactivate.<\/li>\n<li>Connect your agent: the application-password explanation moved to its own line under the button.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>New ability: read-debug-log (read-only, on by default) \u2014 the newest debug-log entries with stack traces grouped to their error and filters for severity, time, and substring. Secrets (API keys, JWTs, bearer tokens, database credentials, cookies, nonces), absolute paths, emails, and IPs are redacted before the content leaves the site; the substring filter matches the redacted text, so it cannot be used to probe for raw secret values. Reads are bounded (a tail of at most 1 MB), so huge logs are safe to query.<\/li>\n<li>verify-checksums now also covers plugins: scope=plugin verifies one named plugin or every installed plugin against WordPress.org's plugin-checksums API, with per-plugin results, unexpected-file detection inside each plugin directory, and honest skipped-with-reason reporting for premium\/custom\/single-file plugins (skipped is not clean).<\/li>\n<li>New ability: list-available-updates (read-only) \u2014 pending plugin, theme, and core updates with current\/new versions and active\/auto-update flags; the actionable companion to site-status's counts and update-plugin's execution.<\/li>\n<li>site-status now includes toolbelt.agent_protocol \u2014 the dry-run, confirm-token, refusal, and REST calling conventions travel with the first call every agent makes.<\/li>\n<li>Every ability now exposes the complete readonly\/destructive\/idempotent annotation set, so MCP clients receive full ToolAnnotations hints (readOnlyHint, destructiveHint, idempotentHint) through the official adapter.<\/li>\n<li>Documentation now spells out the Abilities API GET input syntax (?input[key]=value \u2014 bare query parameters are silently ignored) in the readme, the Connect-your-agent briefing, and agent_protocol.<\/li>\n<li>Fixed an outdated code comment claiming confirm-token refusals are not logged (they are logged as denied since 1.1.0; the behavior was always correct, the comment was not).<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>MCP-native: every enabled ability now carries the meta.mcp.public flag, so the official WordPress MCP Adapter's default server (and WooCommerce's bundled MCP integration) discovers and exposes it automatically; the agent_toolbelt_mcp_public filter can keep any ability REST-only.<\/li>\n<li>New ability: inspect-cron (read-only) \u2014 WP-Cron events with next-run times and an overdue count, for \"scheduled things seem stuck\" diagnosis; event args are digested, never exposed.<\/li>\n<li>New ability: verify-checksums (read-only) \u2014 verifies core files against official WordPress.org checksums; reports modified, missing, and unexpected files under wp-admin\/wp-includes; time-budgeted with a resume cursor.<\/li>\n<li>New ability: run-site-health-checks (read-only) \u2014 runs Site Health's direct tests server-side with a real timestamp (core only refreshes them when a human visits wp-admin); site-status now reports the fresh counts as health_fresh.<\/li>\n<li>Connect your agent: a new settings-page section with your site's actual endpoint URLs, a one-click link to WordPress's own application-password screen, MCP status, and a copyable agent briefing.<\/li>\n<li>Readme: a \"For AI agents reading this\" section and refreshed MCP documentation.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>New ability: regenerate-thumbnails (medium risk) \u2014 finds image attachments with missing thumbnail sizes and generates only the missing files; batched, time-budgeted, never deletes or overwrites.<\/li>\n<li>New ability: cleanup-database (high risk, disabled by default) \u2014 deletes revisions, old auto-drafts, trashed posts, spam\/trashed comments, expired transients, and orphaned meta rows; exact per-category dry-run counts, confirm token bound to the same input, batched deletes through core APIs.<\/li>\n<li>Observe mode: a read-only switch for the whole toolbelt (settings checkbox or the AGENT_TOOLBELT_OBSERVE constant) \u2014 agents can look and preview, nothing mutates.<\/li>\n<li>Hourly rate budget for real executions (5 high-risk \/ 30 total per user per hour, filterable via agent_toolbelt_rate_budgets; AGENT_TOOLBELT_NO_RATE_LIMIT bypass) with retry_after_s in the refusal.<\/li>\n<li>Denied attempts (disabled ability, observe mode, over-budget, bad confirm token) are now recorded in the audit log as <code>denied<\/code>, with anti-flood capping.<\/li>\n<li>Audit log can be filtered by result on every surface: the read-audit-log ability, <code>wp agent-toolbelt log --result=denied<\/code>, and the reader API.<\/li>\n<li>Email notification to the site admin after every real high-risk execution (on by default; settings checkbox).<\/li>\n<li>site-status now reports observe_mode alongside the toolbelt version and enabled abilities, so agents learn the safety state on their first call.<\/li>\n<li>Permission gate is per-operation: update-plugin still requires <code>update_plugins<\/code>; cleanup-database needs only <code>manage_options<\/code>, so it keeps working on hosts that set DISALLOW_FILE_MODS.<\/li>\n<li>High-risk dry-runs no longer issue a confirm token when the request is refused or observe mode is on (a token that can never execute would only mislead the agent).<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>Six abilities: site-status, purge-all-caches, flush-rewrite-rules, maintenance-mode (auto-expiring), read-audit-log, and update-plugin (opt-in) with backup, loopback health check and automatic rollback.<\/li>\n<li>Guardrails: dry-run on every mutating ability, one-time confirm tokens for high-risk execution, per-ability enable\/disable (disabled = invisible), audit log with 90-day\/2,000-row retention, kill-switch constant.<\/li>\n<li>Surfaces: WordPress Abilities API (REST <code>wp-abilities\/v1<\/code>, MCP-ready), WP-CLI (<code>wp agent-toolbelt<\/code>), and an admin page under Tools.<\/li>\n<\/ul>","raw_excerpt":"Safe hands for your site&#039;s AI agent: guarded maintenance operations with dry-run, confirm tokens, a full audit log, and automatic rollback.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/337342","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=337342"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/kostyatereshchuk"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=337342"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=337342"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=337342"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=337342"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=337342"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=337342"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}