Skip to content
WP Visibility

Working with an assistant guide

Resume a Rate Limited SEO Batch Without Repeating Completed Changes

Keep a per-object work log, sort failures into retryable and final, and re-read each target before the next attempt, so a stopped assistant batch resumes without duplicates.

Published

On this page

When an assistant’s SEO batch stops at a rate limit, do not replay it from the start. Keep a work log with one row per target and its confirmed outcome, sort each failure into retryable or final, and before the next attempt re-read the target and check whether a proposal already exists for it. Then resume only the rows that are still open, after the limit has cleared.

Replaying is the common mistake because the assistant’s own memory of the run is not a record. It may have summarized, lost the thread after an error, or counted a queued proposal as a failure. In WP Visibility, repeated calls to a held write ability are not merged: each call creates another proposal. A blind replay fills the review queue with duplicates.

How the limit behaves in 2.10.3

The Assistant write limit (per hour) caps write requests per WordPress user and client label (the Application Password’s name). The default is 100. Zero turns it off. A few details decide how you plan a batch:

  • Only writes count. Reads such as get-post-seo, serialize-content, and audit-post do not spend the limit.
  • Queued proposals count. With Hold for my review selected, a held update-post-seo call is still a write request.
  • Bulk dry runs count. bulk-update-seo is a write ability, so a dry run spends one unit even though it writes nothing.
  • The window slides. Each accepted write sets the counter to expire an hour later. It clears an hour after the last accepted write, not at the top of the hour. Refused requests are not counted and do not extend it.
  • A refusal writes nothing. Over the limit, the request is refused before the ability runs. Through the plugin’s MCP endpoint it comes back as a tool error beginning rate_limited; over the core Abilities REST route it is an HTTP 429.

Stop the Assistant Now documents the setting alongside the pause control. The limit bounds how much one runaway session can do. Raising it or setting it to zero to finish a batch faster removes that bound, so change it deliberately, not as a retry tactic.

Resume instead of replay. Log each target: One row per object with its confirmed state. Sort failures: Retryable, unknown, or final. Re-read, then resume: Check queue, field and log before sending.
The recovery order for an interrupted batch. WP Visibility 2.10.3 keeps no progress record for assistant batches, so the work log is kept outside it.

Record per-object completion state

Before the batch starts, create the work log outside the assistant: a spreadsheet or CSV that you or the client keeps. WP Visibility 2.10.3 has no job orchestration of its own, so this file is the batch’s memory.

post_id intended_change state proposal_id last_checked
112 description proposed 5501 2026-09-27 14:02
118 description proposed 5502 2026-09-27 14:02
121 description failed: rate_limited 2026-09-27 14:03
130 description open

(Illustrative rows.) Use a small set of states: open, proposed, applied, failed-retryable, failed-final, unknown. Ask the assistant to report its result after every call in a form you can paste into the log, and update the log before the next call, not at the end.

Separate retryable and final failures

Every failure falls into one of three groups, and only one of them should be retried as is.

Result Group What to do
rate_limited Retryable later Stop the batch. Resume after the window clears.
agent_paused Wait for a person Someone paused the assistant. Do not resume until they do.
Timeout or connection error Unknown The call may have succeeded. Check before retrying.
Permission error (ability_invalid_permissions, rest_ability_cannot_execute, wpvis_forbidden) Final The user’s role does not cover this target or tool.
Invalid input or schema error Final until fixed Correct the request; do not repeat it unchanged.
wpvis_not_a_draft, wpvis_unsupported_markdown Final until fixed Draft tools refuse these by design.
A proposal ID Success Record it. Never retry.

One catch: through the plugin’s MCP endpoint, WordPress core (7.0 and 7.1) replaces the pause error with its generic ability_invalid_permissions error (7.0 source, 7.1 source, checked September 27, 2026), so a pause shows up as a permission error on every tool, reads included. Core Abilities REST passes agent_paused through, and answers a plain refusal with rest_ability_cannot_execute (REST controller source, checked September 27, 2026). A permission error on a read that worked earlier in the run means stop and ask, not a final failure.

WP Visibility’s capability reference also warns that create-draft is not idempotent: a retry after a timeout can leave a second draft behind. Treat any draft-creation timeout as unknown.

Re-read before the next attempt

For every row that is failed-retryable or unknown, check the current state before sending anything:

  1. Is there already a proposal? An administrator can list pending proposals:

    wp visibility proposals list --status=pending

    Match each row’s post ID against the list. An assistant connected as an administrator can do the same with list-proposals; one connected as an Editor cannot, because the queue abilities check manage_options.

  2. Did the value change? Call get-post-seo for the target (a read, so it does not spend the limit) and compare with the log. If Apply immediately was selected, a successful write shows up here rather than in the queue.

  3. What does the log say? WP Visibility → Review queue → Activity log lists completed calls with the time, actor (the client label), ability, target (such as post:121) and outcome. It does not show proposal IDs. A row for the write ability on that target settles an unknown: the call went through. Refused calls and calls that returned an error, including rate_limited, normally leave no row. See See What the Assistant Did.

Update the log from what you found, then build the next request from the rows that are still open or confirmed failed-retryable.

Resume the batch

Wait until the window has cleared: an hour after the last accepted write. Then send a new, explicit request instead of “continue”:

Resume the description job. Work only on post IDs 121, 130, and 134. For each, call get-post-seo first and stop if the description is no longer empty. Report the result of each call before the next. If you get rate_limited or a permission error, stop and report; do not retry.

Size the rest of the batch to fit under the limit with room to spare, and to fit the time you have to review. The longer proposals wait, the more likely a target changes underneath them. If it does, the queue stops the approval and asks you to refresh the diff. Approve or Reject a Proposal covers stale proposals.

Clean up duplicates if they happened

If a replay already created duplicate proposals, keep one per target and reject the rest in the queue. Rejecting changes nothing on the site. If two duplicates proposed against the same starting value are both approved, the second approval compares the post’s SEO state with the state recorded at proposal time, finds it changed, and stops as stale rather than applying on top.

Checklist for the next batch:

  • Work log created before the first call and updated after each one.
  • Batch size set below the hourly limit and within review capacity.
  • Stop rule for rate_limited, agent_paused and permission errors written into the request.
  • Unknown outcomes checked in the queue, the field, and the activity log before any retry.
  • Resume request lists the exact remaining targets.

The broader description workflow is in Bulk Draft Missing Meta Descriptions.

Read next

WordPress SEO with your own assistant.

WP Visibility is $99 a year for unlimited sites, client sites included, with a 30-day refund. Use its SEO tools in WordPress or connect a supported assistant. Read how proposal review and permissions work.