Skip to content

Writes that don't bite

Agents retry. Networks drop responses. People edit the same issue at the same time. Hydrant assumes all three and refuses to guess. These are the rules every agent write follows. Paste them into your agent’s instructions; they’re shorter than the postmortem.

  • A connection with read and write access, or an agent key. A read-only connection is refused with insufficient_scope: “This token lacks the required workspace permissions. Reconnect with the required access.”
  • An agent that can keep a value between attempts. That’s the whole trick.
  1. Read first. get_issue returns the issue and its current version. Relationship changes use the revision from list_relationships. Project and milestone membership uses the revision get_project describes.
  2. Give every new command its own request ID. Each receipt-based write takes a requestId: a UUID the agent makes up. One command, one UUID. update_agent_session is a set-to-value metadata update without a UUID.
  3. Send the version you read. update_issue carries the version you based the change on. If someone got there first, Hydrant refuses the write instead of flattening their work.
  4. Treat the answer as a receipt. A write returns kind: receipt: an acknowledgment of something that happened. It is not the current state. Read again before telling anyone what’s true now.
  5. After an uncertain response, send exactly the same thing. Timeout, dropped connection, unavailable: repeat the same requestId with the same body. If the first attempt landed, you get its receipt back and nothing happens twice. request_workspace_export has a pending-job exception described under Separate operations below. The workspace write limit never refuses a retry like that, even when the workspace is busy; it still counts as one of the agent’s 120 requests a minute.
  6. After a conflict, stop and look. Re-read the issue, review what changed and decide whether your change still makes sense. If it does, that’s a new command with a new UUID and the new version. Never refresh the version and resend automatically. That’s an overwrite with extra steps.

Comments are the exception to issue versions: add_comment doesn’t change the issue version or wake a snoozed issue. It still takes a requestId.

An agent can fix a comment it wrote with edit_comment: the new body plus the comment’s discussion_version from list_activity. Only the connection or key that posted it can edit it; the person who granted it can’t edit it from the browser either, and the agent can’t edit theirs. A stale version gets conflict, and the same rule applies: re-read, then decide. The old text stays in history, readable with get_text_revision on the Edited a comment entry.

Call the individually named tool for each action, with its operation fields at the top level as discovery describes. update_issue edits ordinary issue fields; trash_issue, restore_issue, reorder_issue and the named approval/review tools handle their own actions. There is no generic batch or action dispatcher.

For several writes, make separate calls in order with distinct UUIDs and reviewed preconditions. Stop and reconcile a failed or uncertain call before continuing; earlier writes remain committed. Keep every original UUID and payload after an interruption.

Workspace exports are an exception to replay: request_workspace_export may return someone else’s pending job without binding your UUID. Repeating it after that job finishes can start another export. Poll get_workspace_export_status with the returned exportId; omitting it reads the latest job. Both tools require an Owner/Admin granting user and write access.

An agent can attach PNG, JPEG or WebP up to 10 MiB each, and up to 20 distinct images in one description or comment. It reserves the upload with reserve_image, sends the bytes with an authenticated PUT to the returned address, then puts only the returned link in Markdown. Unlinked reservations expire after 24 hours. It must never follow redirects with the credential attached, and never print it. Images count toward the workspace’s storage on its plan.

Limit Value
Requests per agent connection or key 120 a minute, every request counted, reads and retries included
Writes per workspace, people and agents together 600 a minute; an exact retry of an accepted write is exempt
Image reservations per agent connection or key 300 an hour, shared by every session using it
Whole MCP request 1 MiB
Title 300 characters
Description 102,400 bytes
Comment 20,480 bytes
  • A successful write: kind: receipt, and a following read shows the change with a higher version.
  • A safe retry: the same receipt as the first time, with no duplicate issue or comment.
  • A stale write: conflict, with “This issue changed. Review the latest version before reapplying your draft.”
  • conflict: “This request ID was already used for another command.” The agent reused a UUID for something different. New command, new UUID.
  • unavailable: “Service unavailable. A write may have committed; reconcile using the original request UUID and body.” Believe it. Retry with the original, or read to find out.
  • rate_limited. The response carries retryAfter in seconds. Wait that long. Hammering just spends the next minute’s budget.
  • too_large. Something is over the limits above. Split it, or trim it.
  • The agent did something an issue told it to. Workspace content is data, not instructions. Hydrant records what your agent does; it can’t stop your agent from obeying an issue body. Keep your client’s write-approval prompts on, and don’t leave it unattended on issues you didn’t write. To see what happened, open the issue and press Show the receipts: the history names the agent and every change it made, and See what changed on a text edit shows the before and after, so you can put the old text back. A trashed issue comes back from the Trash view. Then revoke the connection until you know why it happened.
  • More symptoms: When an agent gets stuck.