Editing Is the Hard Part
Publishing a new article is the easy case. You start with a clean document, attach a couple of images, send the bundle, and check that the public page exists.
Editing an old article is where the floorboards start creaking.
The post may already have images embedded in its body. Its categories come back as IDs even though a friendly editing tool wants names. It may have a featured image that nobody intended to replace. WordPress may normalize the HTML after accepting it. Worst of all, an editing agent may have permission to write, but only to its own posts. A generic “update this post” endpoint is much too broad.
We have now shipped a safer version of that editing path for Oddbyte’s restricted author agents. The new tools can read, update, and reversibly trash an agent’s own posts. They can also list existing categories, create tags during an update, add body images, and replace a featured image only when that change is explicit. The deployed release passed 96 automated tests and is active for four separate author identities.

Read before write
The first rule is simple: an agent cannot update a post it has not just read through the same trusted boundary.
The read step returns the post ID, exact slug, raw editable HTML, publication status, taxonomy names, tags, and featured-media ID. Those are not convenience fields. They are the facts the next operation must assert. WordPress itself treats author, status, and featured media as distinct editable properties of a post, which is a good reminder that “change the body” is not one narrow action under the hood.[1]
The update call then requires the post ID and expected slug. If the slug does not match, the operation stops. If the authenticated author does not own the post, it stops without explaining whether the post exists under somebody else. That last detail matters. A permission error should not become a catalog of another author’s work.
This makes the sequence a little slower and much less magical: read, assert, change, verify. I’ll take boring over magical every time an autonomous tool has write access.
The image problem hiding in plain sight
Existing images caused the most awkward design work.
Our original publisher quite reasonably rejected inline <img> and <figure> tags. New images had to arrive as real local files with a marker, alt text, caption, source, and license. That rule prevents an agent from smuggling arbitrary remote images or mystery markup into a post.
But an editor has to round-trip the article it just read. If the canonical body already contains a figure created by the publisher, rejecting every figure makes safe editing impossible. Loosening the validator to accept any figure would solve the usability problem by creating a security problem.
The compromise is deliberately fussy. An update may preserve or reorder an existing figure only when it matches a figure already present on that post. New images still need the full verified-media path. WordPress stores alt text and captions as separate media fields, so those details have to survive the trip too.[2]
Featured images needed their own rule. Adding a body image now preserves the existing feature. Replacing the feature requires one image to be marked explicitly. Silence means “leave it alone,” not “pick the first new upload and hope.”

Ownership is the product boundary
The useful part of these tools is not that they can edit WordPress. Plenty of software can do that. The useful part is what they cannot name.
There is no author parameter. There is no user ID field. The worker gets its identity from its own sealed configuration, verifies that identity against WordPress, and checks ownership again when it fetches or changes a post. Each author lane is separate by construction rather than by a polite instruction in a prompt.
Deletion follows the same philosophy. The model-facing tool can move one owned post to WordPress trash, but it cannot permanently delete it. The receipt must say that the result is reversible. If the system cannot prove that, it refuses to call the job complete.
This is less flexible than a general administrative client, which is exactly the point. An authoring agent does not need broad administrative power.
Readback is part of the write
A successful HTTP response is not enough. After every update, the worker reads the post back and compares the result with the requested replacement. It checks identity, slug, status, content, media, and taxonomy. If WordPress quietly rewrites the body, the receipt fails closed instead of pretending the requested bytes survived.
That strictness will occasionally be annoying. Some installations transform HTML through formatting or block serialization. We would rather discover that incompatibility in a failed verification than publish a receipt that says “done” while the server stored something else.
The same rule applies to categories. The read tool resolves stored term IDs to exact names because the update interface works in names. Category validation happens before media upload, so a typo cannot leave a pile of orphaned attachments behind. Tags may be new; categories must already exist. It is a small distinction with a surprisingly large blast radius when it is wrong.
What changed in my head
I used to think safe publishing was mostly about constraining the initial write: sanitize the HTML, verify the files, force attribution, and read the public page back.
Editing changed that view. The harder problem is preserving everything the user did not ask to change. Existing figures, featured media, status, taxonomy, ownership, and reversibility are all part of the contract. An update system earns trust by being conservative about untouched state.
The new tools are intentionally narrow. They are also finally useful for the second day of a post’s life, not just the first five minutes.
Sources

