Comments
A comment is a request for attention, anchored to the exact passage it is about. Comments are how a person asks you for something inside a document, how you ask back, and how an agent leaves a question about a passage for whoever works on that document next.
What a thread looks like
A thread hangs off one block of a document and, usually, off a specific passage inside that block. Reading a document returns the open threads as openComments. Each one carries an id, the blockKey it sits on, the quote it anchors to, an anchorStatus, and its messages in order.
Treat open threads as work requests. When you edit a block that carries one, address the thread as part of that edit.
The comment writes
createComment({ documentId, blockKey, body }) opens a thread. Pass
quoteas well to anchor to a passage inside the block rather than to the block as a whole. If the block already has an open thread whose passage overlaps yours, your comment joins the newest such thread as a reply instead: the result returns that thread andappended: true. A comment withoutquoteanchors to the block's text, so it joins most open threads on that block. PassnewThread: trueto open a separate thread. Before you resolve or reply, use the thread id the call returned.replyToComment({ documentId, commentId, body }) adds a message to a thread that already exists.
resolveComment({ documentId, commentId, note }) closes it, with a note saying how it was settled.
claimComment({ documentId, commentId }) says you took a thread over, as a state line rather than a message.
reopenComment({ documentId, commentId }) reopens a resolved thread.
A message body is plain text. Markdown and Markdoc are stored and shown exactly as typed: **bold** shows its asterisks and a {% docref %} tag shows as the tag. To point at evidence, paste the document's address (https://oddlynew.com/d/...) and name the passage in words.
A thread is a conversation, not a verdict. Reply when you need to ask something back or report progress, and resolve only once the request is genuinely settled. Open a thread of your own for a question about what this block says, whose answer is a change to the block or a note that it stays, whether the question is for a person or for the next agent that works on the document: it puts the question in the place it belongs, instead of burying it in chat. A question for a person that reaches beyond the block is kept, with its answer, where the next agent finds it, as Ask a person, and keep the answer describes. For other messages between agents, follow Messages between agents.
Whose turn it is
Every open thread records whose turn it is: waitingOn is agent, person (with that person's user id in waitingOnUserId) or nobody for a note. The server sets it on every write; you never set it yourself. It is stored in the thread document's metadata, so a listing of threads shows it, with hostDocumentId naming the document the thread is on. The openComments of a document read do not carry it; there, the last message's author, its progress flag and claimedBy tell you the same thing.
In the app, a person addresses a new thread to an agent, to one member, or to nobody as a note. A person's message in a thread addressed to an agent gives the turn to an agent.
A thread you open as an agent waits on the person you work for. When that person replies, the turn passes to an agent.
createCommenttakes no addressee, and your own messages keep the turn with an agent only while you are working on the thread, so you cannot hand a thread straight to another agent.A reply is your answer and gives the turn back to the person. Pass
progress: truefor an interim status while you keep working; the turn stays with an agent.A claim keeps the turn with an agent until you reply.
Reopening gives the turn to whoever the thread is addressed to.
orientation.whoami() returns commentsWaitingForAgent, the number of open threads waiting on an agent across all your organizations. It counts threads for any agent, not for you in particular, including threads another agent has claimed or is working on, so check claimedBy and the last message before you take one over. When the count is above zero, its instructions name the call that lists them per organization: documents.listDocuments with the Comment type id in typeIds and the metadata filter waitingOn equal to agent. Threads written before this field existed carry none and are not counted.
Why comments have their own tools
Every thread is itself a document, of the platform Comment type. Reading threads through the ordinary document tools works fine. Writing them that way does not, and you should not do it. The Comment type is not listed by listTypes or searchTypes unless you pass includeServerOwned: true.
Threads are left out of documents.search and documents.listDocuments unless you ask for them, because a thread belongs to its host document and is normally read there through openComments. To find threads by their words or their meaning, pass the Comment type id 00000000-0000-8000-8000-000000000006 in typeIds; every search mode then covers comment threads, open and resolved.
The comment tools stamp authorship server side. A direct edit to a thread document cannot, which would let one author's words be filed under another author's name. Resolving a thread archives its document; reopen one with reopenComment. Everything you write into a thread should go through the comment tools.
Anchors drift, and say so
anchorStatus reports whether the anchor still matches the text as it stands now.
attached: the quoted passage is still present in the block.
drifted: the block is still there, but the quoted words no longer match it. The thread is still about this block; the passage moved or was rewritten.
orphaned: the block itself is gone.
Quotes are matched against the block's plain text, with only whitespace normalized. Store the passage the way a reader sees it, without markup. A quote carrying bold markers or backticks will not match the text it was taken from, and the thread reports as drifted from the moment it is created.
Limits worth knowing
A comment body holds up to 10,000 characters.
A quote holds up to 500 characters.
A document holds up to 100 open threads at once. Resolve what is settled before adding more.
Threads that are already settled
Resolved threads leave openComments entirely. Pass includeResolvedComments to getDocument to get a recent window of them back as resolvedComments. Read that before you re-decide something that was already decided here, including something decided by you in an earlier session. A thread you cannot find has more often been resolved than lost.
Comments and versions
Comments never change the host document's content, and never cut a version of it. They do advance the host document's live revision. So a stale write error can mean nothing worse than a comment arriving while you were working. Re-read the document, see what actually changed, then retry your write.
Write them one at a time
Opening a thread creates a document and then notifies the host document, so it costs meaningfully more than an ordinary write. Several comment writes inside a single run script can exceed the script execution budget. When you have a batch of comments to leave, send one script per comment. Comment writes take an idempotency key: createComment accepts creationId and replyToComment accepts clientKey. Mint the key first with ids.mintOperationIds, keep it outside the sandbox, and if a write reports a timeout, retry the same call with the same key. The write applies at most once, so a timeout never leaves you guessing whether the thread was created.