SiteAgent for Aura

Description

SiteAgent turns every WordPress site into one an AI agent can safely operate — update, maintain, audit, and fix. Once the site is connected to Aura and its approval key is provisioned, mutating actions are gated behind human approval and recorded in a full audit trail; safe batch updates and block edits are snapshotted so they can be rolled back. It’s the on-site half of Aura, the governed control room agencies use to run whole fleets of client sites alongside their servers, CDN, and DNS.

Plugin and core updates are the riskiest thing you do on a live client site. SiteAgent makes them safer: safe batch updates run behind health checks and roll back automatically if the site breaks, and every plugin in that path is zip-snapshotted first. With Aura’s approval key in place, an agent can’t silently push a change — mutating actions wait for a human to approve them. Think of it as the undo button for AI on your clients’ sites.

Install this plugin on any WordPress site to connect it to Aura — no SSH, no wp-admin juggling, no manual logins.

What You Can Do

  • Monitor site health — See WordPress version, PHP version, installed plugins & themes, database info, and disk usage in real time.
  • Update plugins, themes & core remotely — Push updates to any connected site from the Aura dashboard, no wp-admin login.
  • Safe batch updates with auto-rollback — Run chunked updates with health checks; if an update breaks the site, the plugin restores the previous version automatically.
  • Per-plugin rollback — Every update is zip-snapshotted first; restore any plugin to its last good state on demand.
  • Bulk translation & database upgrades — Update all language packs and run WordPress database migrations remotely.
  • One-click connect (magic link) — Connect a site to Aura straight from wp-admin — no manual token copy/paste.
  • AI-agent ready (27 MCP tools) — Exposes machine-readable, JSON-schema tools for AI-driven management, including SEO/accessibility/performance/broken-link auditors, on-site SEO-meta read/write (Rank Math, Yoast, SEOPress), and Gutenberg block read/edit. Read tools run on demand; mutating tools are approval-gated through Aura, and every call is audited.
  • Zero frontend impact — The plugin only registers REST API endpoints. No scripts, no styles, no database queries on visitor-facing page loads.

How It Works

After activation, click Connect to Aura on the Settings SiteAgent page for a one-click magic-link connection, or copy the Site Token shown once and paste it into your Aura dashboard manually. From that point, Aura communicates with your site over a signed, authenticated REST API to pull health data and push updates.

Security

Defence-in-depth protects every request:

  1. WordPress Application Password — Standard WordPress auth with capability checks (manage_options / update_*). Only authorized administrators can trigger actions.
  2. Hashed Site Token — A per-site token sent via the X-Aura-Token header. Only a SHA-256 hash is stored (never the raw token), compared timing-safely. Tokens from older versions migrate to a hash automatically.
  3. Brute-force throttling — Repeated bad-token attempts from an IP are blocked.
  4. Signed magic-link connect — The onboarding callback is HMAC-signed with a one-time secret and timestamp, so the token exchange can’t be hijacked or replayed.
  5. IP / Domain allowlist (optional) — Restrict API access to your Aura instance, with Cloudflare and reverse-proxy header support.

You can rotate the token anytime from Settings SiteAgent Regenerate Token.

REST API Endpoints

Core endpoints under /wp-json/aura/v1/:

  • GET /status — Full site health report
  • GET /updates — Check available updates (core, plugins, themes, translations)
  • POST /update/core / /update/plugin / /update/theme / /update/translations — Apply updates
  • POST /update/database — Run WordPress database upgrades
  • POST /connect — Magic-link token exchange (public, HMAC-signed, 10-minute expiry)

Version 2 endpoints under /wp-json/aura/v2/:

  • GET /health — HTTP, PHP fatal, white-screen and DB connectivity checks
  • POST /update/batch — Chunked batch updates with auto-rollback on health failure
  • POST /rollback/{plugin} — Restore a plugin from its most recent backup
  • POST /rules — Receive Aura’s signed operator ruleset; carrying unbind: true it ends this site’s binding instead

While a site is disconnected by Aura, every write endpoint answers
403 aura_site_unbound and reads keep working; the disconnect answer carries
cleanup_complete and leftovers (what the site still holds), and GET /status
reports unbound until the site is reconnected or the remaining Aura data is removed
from the settings screen.

MCP tools under /wp-json/aura/mcp/:

  • POST /tools/list / POST /tools/execute — Enumerate and run AI-agent tools
  • GET /context — Full site context for AI decision-making

AI Agent Tools (MCP)

SiteAgent ships 29 built-in tools for AI agents. Read tools return information and run on demand; write tools change the site and are queued for human approval through Aura — an agent can never silently mutate a production site.

Read tools:

  • get_site_context — WordPress/PHP/theme/plugin/disk/performance snapshot with detected issues
  • get_database_info — Database size, largest tables, autoloaded-options weight, expired transients
  • scan_security — Scored security posture (file-edit lockdown, debug exposure, SSL, default admin/prefix, open registration, PHP version)
  • scan_seo — SEO posture (search-engine visibility, permalinks, XML sitemap, site title) plus a sampled content audit (thin content, missing excerpts/featured images)
  • scan_a11y — Accessibility audit over sampled content (images missing alt text, non-descriptive link text, heading structure, document language)
  • perf_check — Performance posture (persistent object cache, OPcache, page-cache plugin, PHP version, autoload weight, active plugin count, memory limit)
  • scan_broken_links — Link triage over a content sample with no outbound HTTP (empty/anchor-only links, dev/staging hosts, unresolved internal links)
  • list_users — Users with roles and post counts, administrators flagged (never returns secrets)
  • check_health — Live health gate: HTTP status, PHP fatals, white-screen, database connectivity
  • scan_error_log — Tails and severity-groups the error log, surfacing recent fatals
  • check_vulnerabilities — Plugin update-currency check against WordPress.org (a version check, not a vulnerability/CVE feed; covers wp.org-hosted plugins)
  • check_core_checksums — Core-file integrity against the official WordPress.org checksum manifest (modified/missing/unexpected files, fetched over HTTPS only)
  • scan_executable_files — Uploads-directory observations: PHP/executable files, .htaccess overrides, and symlinks (reported, never followed)
  • audit_admin_accounts — Privileged-account facts: administrators with recency, admin capabilities outside the role, application-password counts, multisite super admins
  • audit_cron — Bounded WP-Cron inventory with sub-60-second-schedule and unresolved-callback fact-flags
  • audit_mcp_exposure — Which other MCP servers are registered on this site, and how many abilities pass the discovery rule such a server applies (abilities are registered site-wide, not per-plugin, so a server resolving targets from that registry picks up mutating ones outside SiteAgent’s approval path). The counts describe the abilities, not what any server currently serves. Reports only; changes nothing
  • audit_rules — Whether a signed operator ruleset is present and how old it is, 24h block/warn counts, expired-but-listed rules, and the enforcement points in this build. Reports only; changes nothing
  • get_seo_meta — Read a post/page’s SEO title, description, and focus keyword from the active SEO plugin (Rank Math, Yoast, or SEOPress)
  • list_page_blocks — Read a page’s Gutenberg block structure (block names, attributes, nesting)
  • snapshot_get — Retrieve a stored snapshot of page content (reversible write metadata)

Write tools (approval-gated):

  • elementor_replay_ability — Executes an approved held Elementor write (destructive, requires Aura approval): claims the hold, re-judges it against the current ruleset, and runs the original Elementor mutation as the user who asked
  • update_plugin_safely — Backup, update, health-check, auto-rollback on failure
  • clear_caches — Flush object/opcode caches and detected page-cache plugins
  • cleanup_transients — Remove expired transients to reduce autoload bloat
  • cleanup_orphaned_assets — Find and remove unused media (dry-run by default)
  • backup_plugins — Zip-snapshot one or all active plugins as a rollback safety net
  • set_seo_meta — Write a post/page’s SEO title / description / focus keyword on the active SEO plugin (Rank Math, Yoast, or SEOPress) — on-site, so it works even when a WAF blocks the plugin’s own REST endpoint
  • update_page_block — Update a Gutenberg block’s content or attributes (snapshot-first, reversible)
  • create_page_from_blocks — Create a new page from a Gutenberg block spec (draft-first)

Tools are classified by verb so the Aura Fleet gateway applies the right risk and approval policy automatically.

Pro: the SiteAgent Power Pack

Everything above is free and ships in this plugin. Agencies that need an agent to fix a site — not just report on it — can add the SiteAgent Power Pack, a separate companion plugin that registers higher-capability tools through this plugin’s own tool registry.

It is not included in this download and is not distributed on WordPress.org — the tools it adds execute code, so they don’t belong in a hosted repository. It comes with the Aura Agency and Studio plans, or as SiteAgent Pro.

What it adds:

  • read_file — read a text file from inside wp-content (jailed; refuses wp-config.php).
  • db_query — a single read-only SQL statement (SELECT / SHOW / EXPLAIN), row-capped.
  • write_file — write a file inside wp-content, snapshot-first so it can be rolled back.
  • run_wp_cli — run an allowlisted WP-CLI command, with no shell and no metacharacters.
  • execute_php — run a PHP snippet against the full WordPress API.

These are governed harder than anything in the free set, deliberately:

  1. Off until you arm them. The write and code tools do nothing until the site owner sets an explicit constant in wp-config.php for each one. Installing the Power Pack alone enables no writes and no code execution.
  2. Human approval, cryptographically enforced. Once the site holds Aura’s approval key (provisioned when you connect the site), each of these calls requires a single-use, signed grant bound to that exact tool and its exact parameters — one only the Aura dashboard can mint, after a human approves the action. A leaked Site Token cannot run them. (Until a site has that key, the gate is dormant — so connect the site from Aura before arming anything.)
  3. Reversible where it can be. File writes are snapshotted first, so there’s a previous state to restore.

The safety model is governance, not a sandbox: execute_php is powerful by design. The controls are the constant you set, the human who approves the call, and the audit trail — not a promise that arbitrary code is safe.

Learn more at my-aura.app/siteagent.

About Aura

Aura is a full-stack operations dashboard by Digitizer that brings servers, applications, DNS zones, and CDN pull zones from Cloudways, Hostinger VPS, Cloudflare, and Bunny.net into a single unified interface.

SiteAgent extends that reach into every WordPress installation — so you can manage your entire infrastructure, including WordPress sites, from one place.

Free to Use

The plugin is completely free and open source (GPLv2+). You need a free or paid Aura account to connect your sites. Sign up at my-aura.app.

Links

Screenshots

Installation

Via WordPress Admin (Recommended)

  1. Go to Plugins Add New in your WordPress admin.
  2. Search for SiteAgent.
  3. Click Install Now, then Activate.
  4. Navigate to Settings SiteAgent.
  5. Click Connect to Aura for one-click magic-link onboarding — or copy the Site Token (shown once) and paste it into your Aura dashboard manually.

Via WP-CLI

wp plugin install digitizer-site-worker --activate

Manual Upload

  1. Download the plugin ZIP from WordPress.org.
  2. Go to Plugins Add New Upload Plugin.
  3. Upload the ZIP and click Install Now, then Activate.
  4. Navigate to Settings SiteAgent to connect or get your Site Token.

FAQ

Do I need an Aura account?

Yes, you need an Aura account to connect your WordPress sites. Aura offers a free tier that includes up to 3 WordPress sites. Sign up at my-aura.app.

Is this plugin safe to use?

Yes. The plugin uses defence-in-depth: WordPress Application Passwords (the same standard mechanism used by the block editor), a per-site token stored only as a SHA-256 hash and verified timing-safely, per-IP brute-force throttling, an HMAC-signed onboarding handshake, and an optional IP/domain allowlist. No data is transmitted unless a request is made by your Aura instance.

How do I enable the approval gate for write actions?

SiteAgent can require a per-action, cryptographically signed approval before it runs a state-changing MCP tool (cleanups, cache flushes, SEO writes, safe plugin updates run through the tool interface). Once enabled, each such write must carry a single-use signature that only the Aura dashboard can mint, after a human approves the action — so a leaked Site Token cannot run those tools on its own.

This gate turns on automatically once the site holds Aura’s approval key, which is provisioned securely during connection. If you installed or updated the plugin but have not reconnected the site since, the gate is dormant and the site runs in the standard token-only mode. To activate it, simply reconnect the site from your Aura dashboard — no reinstall is needed.

Note: the approval gate currently covers the MCP tool path. Core, plugin, and theme updates performed over the plugin’s direct REST update endpoints are still authorized by the Site Token alone (the standard site-management model), so treat the Site Token as a sensitive credential regardless. Grant coverage for those update endpoints is on the roadmap.

Does it slow down my site?

No. The plugin registers only REST API endpoints. It does not load any code, scripts, or database queries on frontend page loads. Your visitors experience zero impact.

What WordPress versions are supported?

WordPress 6.2 or higher is required. This is needed for full Application Password support. The plugin has been tested up to WordPress 7.1.

What PHP versions are supported?

PHP 7.4 or higher. PHP 8.0+ is recommended.

Can I restrict which IP addresses can access the API?

Yes. The plugin supports an optional IP whitelist. If configured, only requests from the specified IP addresses will be accepted. Cloudflare and reverse proxy headers (CF-Connecting-IP, X-Forwarded-For, X-Real-IP) are fully supported for IP detection.

Does this work with WordPress multisite?

The plugin is designed for single WordPress installations. Multisite support is not currently available but is on the roadmap.

Where is the Site Token stored?

Only a SHA-256 hash of the Site Token is stored, in the WordPress option aura_worker_site_token — the raw token is never persisted. It is generated on first activation and shown once so you can copy it; the Aura dashboard keeps the only raw copy. Tokens created by older versions are upgraded to a hash automatically on first use.

Can I regenerate the Site Token?

Yes. Use Regenerate Token on the Settings SiteAgent page. The new token is shown once. Regenerating invalidates the old token and disconnects the site from Aura until you reconnect with the new one.

How do I disconnect a site from Aura?

Remove the site from your Aura dashboard, or deactivate or delete the plugin. If you deactivate the plugin, the REST API endpoints are unregistered and Aura can no longer communicate with the site.

Since 2.13.0, disconnecting from the Aura dashboard happens in two phases. The site is marked disconnected immediately and refuses every change from that moment on — reads keep working — and Aura then has it revoke the Application Password it minted, clear the stored ruleset and gateway key, and finally delete the site token. If the site was mid-disconnect when it lost contact, it finishes the job by itself on its next page load.

Aura disconnected my site but something is left behind — what do I do?

Open Settings SiteAgent. A disconnected site says so (“Disconnected by Aura at …”) and offers Remove remaining Aura data, which revokes what is left and clears the disconnect record — but only once everything it names, the site token included, is proven gone. If it tells you it cannot say which user holds an Application Password, revoke it under Users Profile Application Passwords and try again. Reconnecting the site to Aura also clears the record, after settling what the previous connection still owed.

Does Aura store my wp-admin credentials?

No. Aura uses WordPress Application Passwords, not your main admin password. Application Passwords are scoped specifically for REST API access and can be revoked at any time from Users Your Profile in wp-admin.

Is the plugin open source?

Yes. SiteAgent is open source under the GPLv2 or later license. The source code is available on GitHub.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“SiteAgent for Aura” is open source software. The following people have contributed to this plugin.

Contributors

Translate “SiteAgent for Aura” into your language.

Interested in development?

Browse the code, check out the SVN repository, or subscribe to the development log by RSS.

Changelog

2.16.2

  • /status‘s door fragment carries observation, a per-site door-version witness bumped atomically by every door-state mutation (never by a mere poll) and clock-floored so a restored backup can never reissue a value it already served, so Aura can order overlapping polls by the site’s own witness instead of request timestamps; elementor.governor reports the current value. The observation witness requires InnoDB for wp_options and 64-bit PHP; without them ordering falls back to Aura’s own request order for that site (elementor.governor reports why via observation_unsupported: engine or php32).
  • /status also accepts door_observation_seen — Aura’s own last accepted observation, echoed back — so the site can bump its witness forward, clock-floored, when a restore rewound its own copy behind Aura’s. Accepted for ANY non-negative integer the site’s own witness could ever report (no magnitude ceiling — the witness only counts up); honoured only within a fixed headroom below the class ceiling, silently ignored (200, no bump, no error) above it.
  • elementor.governor reports counters_as_of beside the four _30d rolling counters, which observation does not cover; the counters themselves are int|null.
  • interrupted / running / held are null, not [], when their own queue could not be read, and observation is withheld entirely whenever any read behind the fragment was unreadable.
  • New door_write_unsupported reason reconnect_guard_unavailable: a governed write refuses outright on a $wpdb replacement that cannot disable reconnects, rather than risk a mutation replaying on a session this plugin no longer controls.
  • Door writes report a committed tri-state (true / false / unknown) and answer a retryable 503 with may_have_run: true whenever a commit cannot be proven — claims, holds, acks, and rotations alike; replay() now forwards claim()‘s own error instead of a generic one.
  • Hold references and pending log-row reservations are derived from the request’s own identity, so a retry after an ambiguous commit finds and reuses its own prior write instead of risking a duplicate.

2.16.1

  • /status door fragment and audit_mcp_exposure‘s elementor.governor carry binding, the site’s current binding generation, so Aura can label a departed client’s door-log entries without inferring the generation from the rows.

2.16.0

  • Elementor MCP door governance: every write through Elementor >= 4.3’s official MCP server is held for approval in Aura unless an operator allow rule covers it; block refuses; every write that runs is snapshotted first on the site and recorded in a per-site door log Aura drains. New tools elementor_replay_ability, snapshot_get; new routes /aura/v1/door/reject, /aura/v1/door/ack; /status carries door; audit_mcp_exposure carries elementor.governor. Rules gain the allow effect and the design_system / page_create targets.

2.15.0

  • audit_mcp_exposure reports an elementor block: Elementor >= 4.3’s official MCP module state, every elementor_mcp_consent row, every Elementor MCP… Application Password across all users (full detail), and the other Application Passwords of edit_posts users as counts. Every list is bounded (50 / 50 / 200) with a truncation flag beside it; no usermeta value over 256 KB is decoded; a scan that fails is reported as { error } in its place, never as an empty list. Read-only.
  • aura_worker_app_password_list() accepts an optional byte bound, enforced in the same statement that returns the value.

2.14.0

  • Feature: a self-update can now undo itself. Before installing, SiteAgent
    archives its current build — best-effort: a site without ZipArchive or with
    an unwritable backup directory still updates, and the result says
    backed_up: false so the caller knows this one had no way back. After
    installing, SiteAgent asks the new build to prove it came up. The proof is
    written by the build itself: a boot beacon recorded the first time the new
    code serves a request, and a fatal beacon recorded by
    a shutdown guard when the new code dies while loading. A build whose own
    records say it broke is rolled back to the archived one, and compiled
    copies are asked out of the opcode cache (best-effort — a host that
    restricts opcache_invalidate() may serve the old compiled code until its
    cache revalidates). The result reports exactly what happened (backed_up,
    verified, rolled_back). When neither record appears, the update stands
    and says it was not verified, never guessed.
  • Feature: one SiteAgent mutation at a time. Every path that can replace
    SiteAgent’s own files — the self-update, the generic plugin update, a batch
    entry, the rollback endpoint — runs under a single per-site claim: taken by
    a conditional insert, seizable only after its holder has gone silent for ten
    minutes (a request that dies never releases), and released only by its
    owner. The self-update additionally renews the claim between its phases,
    so a slow step costs the lease nothing once the next phase begins. An
    overlapping request is answered “in progress” and touches nothing.
  • Hardening: backups follow a symlink only while its target stays inside the
    plugin folder — a link pointing out of the tree makes the backup report
    itself incomplete instead of copying unrelated files into an archive.
    Restores never delete through a symlink, root or child, and refuse to run at
    all when a link cannot be removed. A package carrying the version already
    running is refused, because its boot records could not be told apart from
    the old build’s. Backup filenames carry a per-operation suffix, so two
    backups started in the same second never overwrite each other.

2.13.0

  • Feature: Aura can now disconnect a site in two phases, and the site
    refuses changes the moment it is told to.
    When Aura sends a disconnect,
    SiteAgent records it and every mutation on the site — SiteAgent’s own write
    endpoints, MCP write tools, grant-signed calls, and any WordPress REST write
    made with the Application Password or site token of the departing connection
    — is answered 403 aura_site_unbound until the site is reconnected. Reads
    keep working, /status keeps answering, and Aura’s own ruleset endpoint
    stays reachable so the disconnect can be finished or retried.
  • Feature: a departing connection’s Application Password stops working
    everywhere, not just on the REST API.
    WordPress authenticates Application
    Passwords on XML-RPC as well, so a credential the disconnect could not revoke
    is now refused where WordPress decides whether it authenticates at all. Your
    own Application Passwords are untouched, and so is admin login.
  • Feature: the cleanup is proven, not assumed. SiteAgent revokes the
    Application Password(s) Aura minted, clears the stored ruleset and the
    gateway public key, forgets the connect bookkeeping, and deletes the site
    token LAST — and only when Aura says the disconnect is final. Every step is
    idempotent, runs in one fixed order, and continues past a step that failed.
    An interrupted disconnect finishes itself on the site’s next page load
    (throttled, at most once every five minutes), so a site Aura can no longer
    reach still converges.
  • Feature: the answer to a disconnect now names what is still owed:
    leftovers lists the credentials or stores this site could not prove it had
    released (app_passwords, options, ruleset, grant_pubkey), alongside
    cleanup_complete. An empty list means only the shared site token was still
    outstanding; a non-empty one means Aura must keep waiting.
  • Feature: the settings screen tells you when Aura disconnected the site
    (“Disconnected by Aura at …”) and offers Remove remaining Aura data — an
    admin-initiated teardown that runs the same proven cleanup, and only clears
    the disconnect record once everything it names, the site token included, is
    gone.
  • Feature: manually connected sites (those with no gateway public key, which
    therefore cannot verify a signed document) can be disconnected with a bare
    { “unbind”: true, … } body on POST /wp-json/aura/v2/rules, authenticated
    by the site token alone. A site that DOES hold a gateway key refuses the
    bare form and requires the signed envelope.
  • Safety: every ruleset push now runs under the site-wide claim the connect
    flow already used, so a push, a disconnect and a reconnect can no longer
    interleave. A site already busy answers 503 aura_site_busy, which is
    retryable. A claim left behind by a killed request is taken over after two
    minutes rather than blocking the site indefinitely.
  • Safety: reconnecting (magic link) and Regenerate Token now settle the
    previous connection’s outstanding cleanup BEFORE installing a new token, and
    release the disconnect record only after the replacement connection is
    installed and read back — so a reconnect that fails halfway leaves the site
    still refusing the departed connection instead of quietly reviving it.
  • Fix: a disconnect record damaged in the database is now REPAIRED — rebuilt
    from the site’s own state, under the claim — and then torn down through the
    ordinary path. Previously a damaged record was a permanent dead end: the
    site refused every change and no control could clear it.
  • Diagnostics: /status reports unbound: { at, site_ref } while a
    disconnect is outstanding, and app_password_probe_unproven:
    { count, at, owner }
    when the site cannot prove an Application Password was
    revoked — the usual reason a disconnect never finishes. Both are bounded and
    contain no secrets.
  • New error codes: aura_site_unbound (403 — the site is disconnected),
    aura_site_busy (503 — retry), aura_unbind_incomplete (409 — something is
    still owed; the answer lists it), aura_unbind_unreadable (409 — the
    disconnect record could not be read, which is NOT the same as an incomplete
    cleanup), aura_unbind_unrepairable (409), aura_unbind_marker_stuck
    (500 — everything was removed but the record itself would not delete),
    aura_unbind_marker_malformed (500), aura_unbind_store_failed (500) and
    aura_ruleset_client_mismatch (409 — a disconnect addressed to a different
    Aura client), which the bare unkeyed form now checks too.
  • Compatibility: a 2.13 site that is never sent a disconnect behaves exactly
    as 2.12 did. Nothing on the site changes until Aura asks for one.

2.12.0

  • Feature: a rule can now apply to some of a client’s sites instead of all
    of them.
    Aura’s signed ruleset names the site each document was issued
    for, SiteAgent stores that identity, and a rule that lists the sites it
    applies to is enforced only where it belongs. Rules that name no sites are
    client-wide exactly as before.
  • Safety: a site that cannot prove its own identity — an older record, a
    document issued before this field existed — enforces EVERY rule rather than
    skipping the ones it cannot place. Scoping only ever narrows on proof.
  • Upgrade: the identity is recovered offline from the ruleset already stored,
    by re-verifying its signature locally. No new network traffic, and a site
    whose ruleset has not changed since the upgrade is repaired on its next
    request rather than waiting for the next push.

2.11.0

  • Feature: the magic-link connect now mints an Application Password for
    the dashboard.
    A magic-link connection could run SiteAgent’s own tools
    but not the builder tools (Elementor MCP and friends) that authenticate
    with WordPress Basic auth — only a manual connect, which never provisions
    the gateway key, could. The signed /connect callback now also mints an
    Application Password named “Aura SiteAgent” for the administrator who
    created the link and returns it once, in the callback’s response, so the
    dashboard stores it encrypted beside the site token. Every connect rotates
    it (earlier ones under that name are deleted first). Where Application
    Passwords are unavailable (no HTTPS, disabled by a filter, no admin user)
    the connect succeeds token-only as before and names the reason.
  • The whole install — token, client binding, gateway key, Application
    Password — runs under one site-wide connect claim, so two callbacks for the
    same site cannot split the credentials the dashboard ends up holding.
    “Regenerate Token” takes the same claim (it is refused while a connect is
    installing). The claim is never taken over by age: a callback the dashboard
    timed out on may still be running. Every write the install makes — the site
    token, the client binding, the dashboard URL, the gateway key — is issued by
    a statement conditional on holding the claim, so a claim that goes away
    mid-request costs that request its connect (retryable) rather than letting it
    overwrite the install that replaced it. If a
    killed request ever leaves a claim behind, every later connect is refused
    until an administrator deactivates and reactivates the plugin, which
    releases it.
    “Regenerate Token” issues its cleanup the same way, and skips revoking the
    Application Password when it no longer owns the claim — the password on the
    site then belongs to whichever connect replaced it. It still reveals the
    token it stored: refusing to would revoke the old token while showing no
    replacement.
  • Deactivating the plugin now also revokes the Application Password Aura
    minted. Unregistering SiteAgent’s routes does not stop an
    administrator-level credential from authenticating to WordPress core and to
    other REST/MCP plugins, so “deactivated” would not have meant
    “disconnected”. If the revocation fails the owner and UUID are kept, and
    reactivating finishes the job (activation retries a revocation deactivation
    could not land), as does uninstalling. The site token binding survives
    deactivation, so the settings screen keeps showing the dashboard it is
    connected to. The Connect button is always reachable there, and the line above
    it says what the site actually holds: a working credential, one that was never
    delivered, none at all, or a site that cannot issue one (token-only).

2.10.3

  • Fix (security): “Regenerate Token” revealed a new site token without ever
    storing it.
    The option was registered as a read-only setting, and the
    callback enforcing that ran on every write — not only on the settings form —
    so the handler’s write was discarded while the one-time reveal still
    appeared. Two consequences: an admin rotating a leaked token was told it was
    revoked when the old token stayed valid, and a site disconnected from the
    dashboard could not be reconnected, because no token the screen displayed
    ever authenticated. The token is no longer registered as a setting (it is
    display-only, so nothing submits it), and regeneration now stores the new
    hash with a single compare-and-swap, out of reach of any option filter — a
    token is revealed only when that one statement reports it wrote the row, and
    a site whose row is missing or empty can be given its first token the same
    way.

2.10.2

  • Fix: a site moved from one Aura client to another while the old client’s
    last push was still in flight could end up holding the old client’s ruleset
    and refuse the new client’s rules until it was reconnected. The connect
    callback now names the client the site belongs to (a signed, optional field
    — older dashboards keep working unchanged) and writes that binding into the
    ruleset store itself, so a ruleset for any other client is refused from then
    on, whatever was in flight.

2.10.1

  • Fix: audit_rules could report zero blocked/warned events for the current
    hour. Reading the counters before the hour’s first refusal put the bucket in
    WordPress’s negative option cache, and the refusal’s atomic insert did not
    clear it — so the count stayed at zero for the rest of the request, and on a
    site with a persistent object cache until the cache was flushed. Enforcement
    was never affected; only what the audit reported.
  • Fix: two rulesets pushed to a site at the same moment, before it held any,
    could answer the loser with 500 instead of the ordinary “a newer ruleset is
    already installed” decision. Aura retries a 500, so no policy was lost; the
    site now classifies the database’s duplicate-key or deadlock answer as the
    lost race it is.

2.10.0

  • New: operator rules, enforced on the site. A rule is an Aura memory entry
    (rule/<slug>) naming a resource — the whole site, a page or post by ID, or a
    plugin by slug — with an effect of block or warn and an optional expiry.
    Aura signs the client’s whole ruleset with the same key that signs approval
    grants and pushes it to every connected site (POST /aura/v2/rules), the site
    verifies it and keeps only a newer one (a replayed older ruleset is refused
    even when validly signed). No ruleset means no policy — nothing is refused. A
    site that has never been reconnected since signed approvals shipped holds no
    gateway key and cannot verify a ruleset; it says so, and Aura tells you to
    reconnect it.
  • Enforcement runs on every path a write can take: inside the tool executor
    before anything runs or is snapshotted; explicitly on the legacy REST update
    routes; and at WordPress core’s own REST API for posts and pages — so a rule on
    a page holds against Aura’s content tools, an assistant with an application
    password, or another plugin’s MCP server alike. A block refuses the call and
    names the rule; a rule outranks an approval — a granted call is still
    refused, and the message says to release the rule first. A warn runs and
    attaches the warning. Previews are never blocked; they now report what a call
    touches and which rule would decide it.
  • New: audit_rules (read-only) — ruleset presence and age, whether the site
    can verify one, 24h block/warn counts, expired-but-listed rules, and the
    enforcement points in this build.
  • Every mutating tool now declares what a call touches; one that does not is
    caught by every rule rather than by none.

2.9.1 and earlier

  • WordPress.org truncates a Changelog over 5,000 words, and this plugin’s history is longer than that.
    The entries for 2.9.1 and every release before it were moved out of this file verbatim and are kept in full at:
    https://github.com/Digitizers/SiteAgent/blob/main/docs/changelog-archive.md