The loop, end to end
- The agent publishes the deliverable with
agentation: true. - You send the private link. The client opens it in a browser, with no login.
- They select a paragraph and leave a comment, a reaction, or a private note.
- The agent calls
list_feedbackon the next turn and gets the comments as data. - It fixes the page with
update_site— same link — and callsresolve_feedback.
Turn the toolbar on
set_agentation({ site_id: "…", agentation: true })Or at publish time:
publish_html({ content: "…", agentation: true, reactions: true })agentation and reactions are independent switches. A client review
usually wants both; a status page shared with fifty people often wants reactions only.
What the reviewer gets
What the agent reads back
list_feedback({ site_id: "…", unresolved_only: true })Or over HTTP:
curl https://read.botook.ai/sites/SITE_ID/feedback \
-H "Authorization: Bearer otr_live_YOUR_KEY"The shape of one item
| Field | Meaning |
|---|---|
id | Stable id — what you pass to resolve or delete. |
kind | comment, reaction or note. |
anchor | The element the reviewer had selected. This is the whole trick. |
body | What they wrote. |
severity | How strongly it was flagged, when the reviewer said. |
resolved | Whether anyone has acted on it. |
created_at | Unix seconds. |
Why the anchor matters
The third chart looks off is a puzzle. The same sentence attached to the third chart is an instruction. The anchor is what makes the feedback usable as agent input rather than as something a human has to interpret first.
Resolving
resolve_feedback({ feedback_id: "…" })Or from either REST shape:
curl -X POST https://read.botook.ai/feedback/FEEDBACK_ID/resolve \
-H "Authorization: Bearer otr_live_YOUR_KEY"
curl -X DELETE https://read.botook.ai/feedback/FEEDBACK_ID \
-H "Authorization: Bearer otr_live_YOUR_KEY"Resolve keeps the record and marks it done. Delete removes it. Most loops only ever resolve.
Fix in place, do not resend
The revision goes behind the same token, so the client refreshes the link they already have:
update_site({ site_id: "…", content: "<!doctype html>…" })Unresolved counts follow the page
unresolved_feedback and reactions_count hang off the site object, so
a list of your pages doubles as a queue of what still needs attention.
curl https://read.botook.ai/sites -H "Authorization: Bearer otr_live_YOUR_KEY" \
| jq '.sites[] | {title, unresolved_feedback}'Where it lands for you
In the dashboard: one activity feed across every page — opens, reactions, comments — plus an optional daily digest email so a quiet review does not go unnoticed for a week.
Reviewer privacy
A comment is content the reviewer chose to send you. A private note is not: it stays with the person who wrote it. Nothing here records what anyone looked at beyond the aggregate counts on the engagement page.
Compared with the usual review round
| Route | Cost |
|---|---|
| Email with an attachment | Comments arrive as prose about a file version nobody can name. |
| A shared document | The client needs an account in a tool they do not use. |
| A screen-share call | Works, but only at a time you both have. |
| An anchored comment on the deliverable | No account, no version confusion, and it is already structured. |
Turning it off
For a page going to a wide audience, leave the toolbar off. Nothing is injected and the document is served exactly as written:
set_agentation({ site_id: "…", agentation: false })Does the toolbar change my page?
It adds a small script on the viewer response only. The stored document is untouched — what
you get from /sites/:id/content is exactly what you published.
Reactions and comments are different records
They arrive from the same toolbar and they are stored apart, because they mean different things. A comment is a task: it has an anchor, a body, and a resolved state. A reaction is an opinion: it has a count and nothing to do. Merging them would put "someone liked the chart" into the same queue as "the chart is wrong".
| Comment | Reaction | |
|---|---|---|
| Carries | Text plus the element it was left on | One emoji |
| Has a state | Unresolved until you resolve it | None — it is a tally |
| Switch | set_agentation | reactions, separately |
| Read with | list_feedback | GET /sites/:id/reactions |
Telling two audiences apart
One page often goes to two sets of people — the client and the subcontractor, or design and legal. Mint a labelled share token for each and the comments arrive tagged with which link they came through, so you can act on one group without guessing:
curl -X POST https://read.botook.ai/share-tokens \
-H "Authorization: Bearer otr_live_YOUR_KEY" \
-H "content-type: application/json" \
-d '{"site_id":"SITE_ID","label":"client-review"}'Revoking one token ends that audience's access without disturbing the other, which is the polite way to close a review round early.
When the page is behind a gate
Feedback still works with a password or an email-domain gate in front of the page — the reader passes the gate first, then sees the toolbar. The email gate is the only route that gives you anything about who is talking: the page was opened by somebody who could receive mail at the domain you allowed. A password tells you only that they had the password.
A review round that outlives the link
The most common way this loop breaks is boring: the default expiry runs out on Friday while the client reads it on Monday. Match the expiry to the review, not to the publish, and extend it if the round drags:
set_expiry({ site_id: "…", expires_in_hours: 336 })Expiry here is deletion, so an expired review page is gone rather than gone quiet — the feedback you already collected survives, because it belongs to the account, not to the link.
Feeding it back into the next run
The point of anchored, structured feedback is that the next turn can consume it without a human paraphrasing. In an unattended loop that is two commands — read the open items, and close them once the revision that answers them is published:
curl -s https://read.botook.ai/sites/SITE_ID/feedback?unresolved_only=true \
-H "Authorization: Bearer otr_live_YOUR_KEY" \
| jq -r '.feedback[] | "\(.anchor): \(.body)"'Questions
Can clients see each other's comments?
Comments are for you and the agent. Private notes are visible only to their author.
Does the client need an account?
No, ever.
Can I export the feedback?
It is JSON from the API — pipe it wherever you like.
Can two clients review the same page?
Yes. Give each a share token so you can tell the audiences apart and cut one off alone.