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.
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, andaudit-postdo not spend the limit. - Queued proposals count. With Hold for my review selected, a held
update-post-seocall is still a write request. - Bulk dry runs count.
bulk-update-seois 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.
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:
-
Is there already a proposal? An administrator can list pending proposals:
wp visibility proposals list --status=pendingMatch 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 checkmanage_options. -
Did the value change? Call
get-post-seofor 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. -
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 anunknown: the call went through. Refused calls and calls that returned an error, includingrate_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_pausedand 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.
