Skip to content

Agent protocol

Protocol version: 3. Agents open the connection to the office; the office never connects to an agent. The messages are defined once, as schemas in the @outstaff/protocol package, which both sides use.

Messages are JSON text frames over a WebSocket. Every message has this shape:

{ "id": "m1", "replyTo": "m0", "type": "heartbeat", "payload": {} }
  • id is unique per sender. replyTo is set on a response and holds the id of the request.
  • A request gets exactly one response: the result message listed for it, ack, or error.
  • The first message from the agent must be hello. Anything else gets an unauthenticated error and the connection closes.
  • A message that is not valid JSON, has an unknown type, or has a payload that does not match gets an error back. The connection stays open.
  • Frames are limited to 1 MiB.
  1. The agent connects and sends hello with its handle, token and protocol version.
  2. The office answers welcome, or error and closes the connection (auth_failed, version_mismatch). The close codes are 4401 and 4426.
  3. The office offers the next work item, or offers again the items that were not accepted before. The agent sends accept (or decline).
  4. While working the agent sends heartbeat at least every heartbeatMs, progress and journal as it goes, and finally handback or fail. The office then offers the next item.
  5. A person has one connection. A new connection with valid credentials replaces the old one, which closes with code 4409.
  6. After a disconnect the agent reconnects with backoff and sends hello again. welcome.resume lists accepted items still unfinished, and unaccepted offers are delivered again.
  7. At any time, also during a run, the office may send act: tracker and knowledge-base changes the event pipeline decided for the person. The agent’s process makes them with the person’s own credentials, without a model run, and answers act_result. An act it has not answered comes again in the next welcome.acts, so an offline agent makes it when it connects.

Delivery is at least once and idempotent by work item id: an offer may arrive twice, and accept, handback and the other item messages may be repeated safely.

malformed, unknown_type, invalid_message, unauthenticated, auth_failed, version_mismatch, replaced, unknown_item, not_found, invalid, unsupported, failed.

First message on every connection. Authenticates the person and checks the protocol version.

Sent by: agent. Answered by: welcome, error.

Field Type Required Description
person string yes Handle of the person this agent runs as.
token string yes The person’s agent token.
protocolVersion integer yes PROTOCOL_VERSION the agent speaks.
agentVersion string yes Version of the agent software.

The connection is accepted. Carries the team config the agent works from, and lists accepted items to resume, the reports to requesters the agent was offline for and the acts it has not answered; the agent posts and makes those itself and confirms each.

Sent by: office.

Field Type Required Description
protocolVersion integer yes PROTOCOL_VERSION the office speaks.
heartbeatMs integer yes Send a heartbeat at least this often.
team object yes The team config the office loaded, validated and with its defaults filled in. The agent validates it again, renders its working files from it and, when a later welcome brings a different one, renders them again between work items. It holds no secrets: the team file names the secrets adapters need, and each agent reads its own from its secret source.
resume list of string yes Ids of accepted, unfinished items the agent should carry on with.
reports list of objects no Reports to a requester that the agent did not post when its item ended, because it was offline. The agent posts each one now, as itself; the office does not send them again.
reports[].id string yes Id of this report. The office sends it again until the agent confirms with report_posted, so the agent skips an id it posted already.
reports[].workItemId string yes Id of the work item.
reports[].kind result or blocked yes How the item ended.
reports[].text string yes What the agent handed back: the summary to report.
reports[].requester string no Id of the requester to mention.
reports[].links list of objects yes The ticket and pull requests of the item.
reports[].links[].url string yes Absolute URL.
reports[].links[].title string no Label for the link.
reports[].threads list of objects no Every thread linked to the item now, to post the report in: the one it came from and the ones attached later. Absent when the report goes to a direct message instead.
reports[].threads[].channel string yes Chat channel of the request.
reports[].threads[].thread string yes Thread the agent answers in.
reports[].threads[].requester object yes
reports[].threads[].requester.id string yes Id of the requester in the chat workspace.
reports[].threads[].requester.name string no
reports[].threads[].direct boolean yes The conversation is a direct message with the requester.
reports[].threads[].participant boolean yes The requester started the thread or replied in it, so the chat already notifies them.
reports[].direct string no For a blocked report on an item without a chat thread: the requester’s chat user id. Open a direct message with them and post the report there.
acts list of objects no Acts the agent has not answered yet, for example because it was offline when the office decided them. The agent makes each one’s changes now, as itself, and answers with act_result.
acts[].id string yes Id of the act. The office sends it again until the agent answers with act_result, so the agent makes an id’s changes once and only answers again.
acts[].ops list of any yes The changes, made in order.

A work item for the agent to take, with its context. Delivered at least once: an offer that was not accepted is sent again after a reconnect, so handle the same id twice.

Sent by: office.

Field Type Required Description
workItem object yes The item to work on.
workItem.id string yes
workItem.kind string yes What the work is, for example a ticket, a review round or a question.
workItem.title string yes
workItem.priority number yes Lower runs first.
workItem.trigger human or agent or automation or schedule yes
workItem.parentId string no The item this one was split from, for questions.
workItem.subject object no
workItem.subject.type string yes
workItem.subject.ref string yes
workItem.origin object no Where the request came from, for items started by a chat message.
workItem.origin.channel string yes Chat channel of the request.
workItem.origin.thread string yes Thread the agent answers in.
workItem.origin.requester object yes
workItem.origin.requester.id string yes Id of the requester in the chat workspace.
workItem.origin.requester.name string no
workItem.origin.direct boolean yes The conversation is a direct message with the requester.
workItem.origin.participant boolean yes The requester started the thread or replied in it, so the chat already notifies them.
workItem.origin.files list of objects no Files shared in the message that started the chat session. Metadata only: the agent fetches the bytes from chat. Data from the requester.
workItem.origin.files[].id string yes Id of the file in the chat workspace.
workItem.origin.files[].name string yes File name, as the sender named it. Data from them.
workItem.origin.files[].mimetype string yes
workItem.origin.files[].size integer yes Size in bytes.
workItem.origin.files[].url string yes Where the chat adapter fetches the bytes from. Only the agent’s chat adapter uses it; the office stores it as it is and never fetches it.
workItem.origin.about object no For a chat session started by a reply in the thread of earlier work: that work item. Its ticket, pull request and journal are in the offer’s context.
workItem.origin.about.id string yes
workItem.origin.about.title string yes
workItem.origin.about.state running or finished yes Whether the work is still running or was handed back, done or canceled.
context object yes What the agent needs to start.
context.journal list of objects yes What earlier rounds of this item recorded.
context.journal[].at string yes ISO-8601 timestamp.
context.journal[].author string yes Handle of the author.
context.journal[].text string yes
context.subjects list of objects yes The tickets, pull requests and people the item concerns.
context.subjects[].type string yes Kind of subject, for example a ticket or a pull request.
context.subjects[].ref string yes Reference of the subject in its system.
context.subjects[].title string no Human-readable title.
context.subjects[].url string no Link to the subject.
context.subjects[].headRef string no For a pull request: the branch it is opened from.
context.subjects[].baseRef string no For a pull request: the branch it targets.
context.subjects[].state open or closed or merged no For a pull request: whether it is open, closed or merged.
context.subjects[].draft boolean no For a pull request: whether it is a draft.
context.subjects[].own boolean no For a pull request: true when the person the item is offered to opened it.
context.links list of objects yes Further links worth opening.
context.links[].url string yes Absolute URL.
context.links[].title string no Label for the link.
context.feedback list of objects no For a review round: the reviews and comments it covers, oldest first. Feedback that arrives while the item is queued is added; what arrives while it runs goes into the one round after its hand-back.
context.feedback[].actor string yes Login of the person who gave the feedback; for a blocked hand-back, the agent.
context.feedback[].kind review or comment or inline_comment or chat or ticket_comment or doc_comment or blocked or ci_failure yes A review with its summary, a comment on the pull request conversation, an inline comment on the diff, a message from a trusted human in chat, a comment on a ticket, a comment or reply on a knowledge document, an agent’s hand-back as blocked (the summary it handed back), or the failing checks of a pull request (names, links and summaries, in the body).
context.feedback[].state string no For a review: approved, changes_requested or commented.
context.feedback[].url string no Link to the feedback.
context.feedback[].commentId string no For a comment or inline comment: its id on the host. The kind tells which kind of comment it is. For a ticket or document comment, its id in the tracker or knowledge base.
context.feedback[].docId string no For a document comment: the id of the document.
context.feedback[].anchorText string no For a document comment: the text of the document it is anchored to. Data from the document.
context.feedback[].at string no When the host reported the feedback (ISO-8601).
context.feedback[].body string yes What the person wrote. Data from that person.
context.feedback[].comments list of objects no For a review: its inline comments, oldest first.
context.feedback[].comments[].id string yes The comment’s id on the host.
context.feedback[].comments[].path string yes File the comment is on.
context.feedback[].comments[].line integer no Line the comment is on.
context.feedback[].comments[].body string yes What the person wrote. Data from that person.
context.feedback[].comments[].url string no Link to the comment.
context.feedback[].comments[].threadId string no The review thread to reply in and resolve, when the host reports one.
context.conversation list of objects no For a round started by a comment on the pull request conversation or a review summary: the few entries of the conversation before the first of them, oldest first, so a short reply has its context.
context.conversation[].kind comment or review yes A comment on the pull request or a review summary.
context.conversation[].author string yes Login of the person who wrote it.
context.conversation[].at string yes When the host recorded it (ISO-8601).
context.conversation[].state string no For a review: approved, changes_requested or commented.
context.conversation[].url string no Link to the entry.
context.conversation[].body string yes What the person wrote, trimmed. Data from that person.
context.wake object no What the office knows about the work, handed over with the wake: the linked tickets, pull requests, documents and chat threads, each with its link and why it belongs.
context.wake.tickets list of objects yes
context.wake.tickets[].key string yes
context.wake.tickets[].title string yes
context.wake.tickets[].url string no Link to the ticket.
context.wake.tickets[].status string no Canonical status, for example active or review.
context.wake.tickets[].assignee string no Name of whom it is assigned to.
context.wake.tickets[].description string no The ticket’s description, cut to pipeline.context.body_chars. Data from that person.
context.wake.tickets[].comments list of objects yes The latest comments, oldest first, at most pipeline.context.comments.
context.wake.tickets[].comments[].author string yes Who wrote it.
context.wake.tickets[].comments[].at string yes When (ISO-8601).
context.wake.tickets[].comments[].url string no Link to it.
context.wake.tickets[].comments[].body string yes What they wrote, cut to pipeline.context.body_chars. Data from that person.
context.wake.tickets[].moreComments integer no Earlier comments left out.
context.wake.tickets[].reviews list of objects no For the ticket being worked on: the review comments on its pull requests and its parent’s, open and merged, resolved threads included, newest first, at most pipeline.context.reviews. Comments in a thread a human opened, and human comments in any other.
context.wake.tickets[].reviews[].pr string yes The pull request it is on, the office’s key.
context.wake.tickets[].reviews[].ticket string no The ticket that pull request implements.
context.wake.tickets[].reviews[].resolved boolean yes Whether its review thread is resolved.
context.wake.tickets[].reviews[].path string no File the thread is on.
context.wake.tickets[].reviews[].line integer no
context.wake.tickets[].reviews[].url string no Link to the comment.
context.wake.tickets[].reviews[].author string yes Who wrote it.
context.wake.tickets[].reviews[].at string yes When (ISO-8601).
context.wake.tickets[].reviews[].body string yes What they wrote, cut to pipeline.context.body_chars. Data from that person.
context.wake.tickets[].moreReviews integer no Older review comments left out.
context.wake.tickets[].why object yes
context.wake.tickets[].why.role trigger or subject or created or attached or mentioned or inferred or linked yes How it belongs to the work: it woke the agent, is what the work is about, the agent made it, a request added it, feedback named it, the work state worked it out, or it is linked to another item of the bundle.
context.wake.tickets[].why.source string yes What added it: an event id, an agent verb, a chat message, or the link it was found through.
context.wake.tickets[].why.addedAt string no When the office learned of it (ISO-8601).
context.wake.prs list of objects yes
context.wake.prs[].ref string yes The office’s key of the pull request, for example acme/shop#12.
context.wake.prs[].number integer yes
context.wake.prs[].title string yes
context.wake.prs[].url string no Link to the pull request.
context.wake.prs[].state open or closed or merged yes
context.wake.prs[].draft boolean yes
context.wake.prs[].ci none or pending or success or failure yes Combined state of its checks.
context.wake.prs[].failing list of string yes Names of the failing checks.
context.wake.prs[].mergeable clean or conflicting or unknown yes
context.wake.prs[].review string no State of the latest submitted review.
context.wake.prs[].unresolvedThreads integer yes How many review threads are unresolved.
context.wake.prs[].threads list of objects yes Unresolved review threads, at most pipeline.context.threads.
context.wake.prs[].threads[].path string no File the thread is on.
context.wake.prs[].threads[].line integer no
context.wake.prs[].threads[].url string no Link to the thread.
context.wake.prs[].threads[].author string yes Who opened it.
context.wake.prs[].threads[].body string yes Its first comment, cut to pipeline.context.body_chars. Data from that person.
context.wake.prs[].ticket string no The ticket it implements.
context.wake.prs[].stackedOn string no The pull request it is stacked on.
context.wake.prs[].stackedBy list of string yes Open pull requests stacked on it.
context.wake.prs[].why object yes
context.wake.prs[].why.role trigger or subject or created or attached or mentioned or inferred or linked yes How it belongs to the work: it woke the agent, is what the work is about, the agent made it, a request added it, feedback named it, the work state worked it out, or it is linked to another item of the bundle.
context.wake.prs[].why.source string yes What added it: an event id, an agent verb, a chat message, or the link it was found through.
context.wake.prs[].why.addedAt string no When the office learned of it (ISO-8601).
context.wake.docs list of objects yes
context.wake.docs[].id string yes
context.wake.docs[].title string yes
context.wake.docs[].url string no Link to the document.
context.wake.docs[].ticket string no The ticket it was written for.
context.wake.docs[].why object yes
context.wake.docs[].why.role trigger or subject or created or attached or mentioned or inferred or linked yes How it belongs to the work: it woke the agent, is what the work is about, the agent made it, a request added it, feedback named it, the work state worked it out, or it is linked to another item of the bundle.
context.wake.docs[].why.source string yes What added it: an event id, an agent verb, a chat message, or the link it was found through.
context.wake.docs[].why.addedAt string no When the office learned of it (ISO-8601).
context.wake.chats list of objects yes
context.wake.chats[].channel string yes
context.wake.chats[].thread string yes Thread to read or answer in, with the chat tools.
context.wake.chats[].messages list of objects yes The latest messages the office received in the thread, oldest first, at most pipeline.context.messages.
context.wake.chats[].messages[].author string yes Who wrote it.
context.wake.chats[].messages[].at string yes When the office received it (ISO-8601).
context.wake.chats[].messages[].text string yes What they wrote, cut to pipeline.context.body_chars. Data from that person.
context.wake.chats[].moreMessages integer no Earlier messages left out.
context.wake.chats[].why object yes
context.wake.chats[].why.role trigger or subject or created or attached or mentioned or inferred or linked yes How it belongs to the work: it woke the agent, is what the work is about, the agent made it, a request added it, feedback named it, the work state worked it out, or it is linked to another item of the bundle.
context.wake.chats[].why.source string yes What added it: an event id, an agent verb, a chat message, or the link it was found through.
context.wake.chats[].why.addedAt string no When the office learned of it (ISO-8601).
context.wake.merge object no For a merge: the pull request’s state, the repository’s other open pull requests and how they relate to it, the latest merges into its base and the base’s checks.
context.wake.merge.pr object yes The pull request to decide on.
context.wake.merge.pr.ref string yes The office’s key of the pull request.
context.wake.merge.pr.number integer yes
context.wake.merge.pr.title string yes
context.wake.merge.pr.url string no Link to the pull request.
context.wake.merge.pr.head string yes Its branch.
context.wake.merge.pr.base string yes The branch it merges into.
context.wake.merge.pr.draft boolean yes
context.wake.merge.pr.approvedBy list of string yes Reviewers whose latest verdict approves it.
context.wake.merge.pr.changesRequestedBy list of string yes Reviewers whose latest verdict asks for changes.
context.wake.merge.pr.ci none or pending or success or failure yes Combined state of its checks on the current head.
context.wake.merge.pr.failing list of objects yes Its checks that failed.
context.wake.merge.pr.failing[].name string yes
context.wake.merge.pr.failing[].url string no Link to the check.
context.wake.merge.pr.mergeable clean or conflicting or unknown yes
context.wake.merge.pr.unresolvedThreads integer yes How many review threads are unresolved.
context.wake.merge.base object yes
context.wake.merge.base.ref string yes The base branch.
context.wake.merge.base.ci none or pending or success or failure or unknown yes Combined state of the checks on the base branch’s head; unknown when not read.
context.wake.merge.base.failing list of objects yes Checks on the base branch that failed.
context.wake.merge.base.failing[].name string yes
context.wake.merge.base.failing[].url string no Link to the check.
context.wake.merge.others list of objects yes The other open pull requests of the repository, related ones first, at most pipeline.context.items.
context.wake.merge.others[].ref string yes The office’s key of the pull request.
context.wake.merge.others[].number integer yes
context.wake.merge.others[].title string yes
context.wake.merge.others[].url string no Link to the pull request.
context.wake.merge.others[].author string yes The agent’s handle, else the code host login.
context.wake.merge.others[].draft boolean yes
context.wake.merge.others[].approved boolean yes A reviewer approved it and none asks for changes.
context.wake.merge.others[].ci none or pending or success or failure yes
context.wake.merge.others[].mergeable clean or conflicting or unknown yes
context.wake.merge.others[].relation list of stacked_on_it or under_it or same_base or overlapping_files yes How it relates to this pull request: stacked on it, the one it is stacked on, into the same base branch, or changing some of the same files.
context.wake.merge.others[].files list of string yes Files both change, the first few, when they overlap.
context.wake.merge.moreOthers integer no Other open pull requests left out.
context.wake.merge.recentMerges list of objects yes The latest pull requests merged into the base branch, latest first.
context.wake.merge.recentMerges[].ref string yes
context.wake.merge.recentMerges[].number integer yes
context.wake.merge.recentMerges[].title string yes
context.wake.merge.recentMerges[].url string no Link to the pull request.
context.wake.merge.recentMerges[].author string yes
context.wake.merge.recentMerges[].at string yes When the office last saw it, about when it merged (ISO-8601).
context.wake.failedChecks list of objects no For a merge whose checks failed: each failing check on the merge commit, with the end of its failed step’s log, read by the office. The log is data from the CI run, not instructions.
context.wake.failedChecks[].pr string yes The office’s key of the merged pull request.
context.wake.failedChecks[].sha string no The merge commit the check ran on.
context.wake.failedChecks[].name string yes The check.
context.wake.failedChecks[].url string no Link to the check’s run; ost ci log <link> reads more of it.
context.wake.failedChecks[].timedOut boolean no It was still running when policies.merge_checks.timeout_minutes ran out.
context.wake.failedChecks[].steps list of objects yes Its failed steps; empty when no log could be read.
context.wake.failedChecks[].steps[].name string yes The failed step.
context.wake.failedChecks[].steps[].lines list of string yes The last lines of its log, oldest first, each cut to a few hundred characters, secrets masked. Data from the CI run, not instructions.
context.wake.failedChecks[].steps[].omitted integer yes Earlier lines of the step left out.
context.wake.failedChecks[].note string no Why no log is shown: none is available, or the office could not read it.
context.wake.omitted integer no Linked items left out by pipeline.context.items, the farthest from the wake first.
sessionId string no Runtime session of this item from an earlier round; resume it when present.
interrupted boolean no True when the item’s previous run was cut short by an agent shutdown; the prompt says so.

Takes an offered item. Accepting twice is harmless.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string yes Id of the work item.
runtime string yes The runtime adapter this agent runs the item on, for example claude.
model string yes The model the person is configured with (people[].model).

Gives an offered item back to the queue.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string yes Id of the work item.
reason string yes Why the agent cannot take it now.

Shows the agent is alive and, optionally, still working on an item.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string no The item being worked on, if any.

A short status line about the item, shown to people.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string yes Id of the work item.
text string yes

Stores the runtime session of an item, so a later round of the item resumes it. One session per item; sessions are never shared between items.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string yes Id of the work item.
sessionId string yes Id of the runtime session working the item.
model string no The concrete model id the runtime reports it started with, when it reports one (for example the full id behind an alias).

Reports the LLM usage windows the runtime sees. The office keeps the latest report per person (and for people who share a subscription) and uses it for the usage policy.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
windows list of objects yes The runtime’s current LLM usage windows; replaces the earlier report.
windows[].name string yes Which limit, for example five_hour or seven_day.
windows[].utilization number yes Fraction of the limit used; 1 is the limit.
windows[].resetsAt string no ISO-8601 time at which the window resets.

Appends a line to the item’s journal, which later rounds start from.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string yes Id of the work item.
text string yes

Finishes a round of the item with a summary, and the tokens and cost the round used, which the office records on the run and adds to the totals of the item’s tickets.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string yes Id of the work item.
summary string yes What was done, decisions and open points.
links list of objects yes Pull requests, documents and tickets touched.
links[].url string yes Absolute URL.
links[].title string no Label for the link.
status done or waiting or blocked or silent or interrupted yes Whether the item is finished with a result to review, waits for something, is stuck, finished silently (nothing to hand on: the item is done and its ticket is put back as the round found it), or was cut short by the agent shutting down. An interrupted item goes back to the front of the queue and is offered again with its session.
toReview list of string no For a done hand-back: what the agent’s check found to review or finished, for example a pull request opened or ready for review, a document linked, the ticket closed, or a kind of work that finishes without one. The office takes a done hand-back without it as blocked when it finds nothing to review itself.
usage list of objects no The usage of the round, per runtime session it used (a lost session restarted gives two), in the latest figures the runtime reported.
usage[].session string yes Id of the runtime session.
usage[].models object yes The session’s running total per model id, as the runtime reports it: a resumed session includes its earlier rounds, and the office counts only what is new since the session’s previous report.

Reports that the agent could not do the item, with the usage of the round, as handback.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string yes Id of the work item.
reason string yes
usage list of objects no The usage of the round, per runtime session it used (a lost session restarted gives two), in the latest figures the runtime reported.
usage[].session string yes Id of the runtime session.
usage[].models object yes The session’s running total per model id, as the runtime reports it: a resumed session includes its earlier rounds, and the office counts only what is new since the session’s previous report.

Asks a teammate a question. The office routes it and may answer later.

Sent by: agent. Answered by: ask_result, error.

Field Type Required Description
to string yes
question string yes
workItemId string no The asker’s current item.

The state of a question: answered, or still pending.

Sent by: office.

Field Type Required Description
id string yes Id of the question.
to string yes
status answered or pending yes
answer string no

Answers a question that was offered as a work item.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
questionId string yes
answer string yes

Asks for the team and what everyone is doing.

Sent by: agent. Answered by: roster_result, error.

No payload fields.

The team.

Sent by: office.

Field Type Required Description
members list of objects yes
members[].handle string yes
members[].name string yes
members[].role string yes
members[].title string no Display title of the role, for example Developer.
members[].summary string no One line on what the role does.
members[].status idle or working or paused or offline yes
members[].current string no What the person is working on.
members[].usage object no The person’s busiest LLM usage window, when it was reported recently.
members[].usage.window string yes The busiest window.
members[].usage.utilization number yes Fraction of that window’s limit used.
members[].usage.resetsAt string no ISO-8601 time at which that window resets.
humans list of objects no The trusted humans of the team.
humans[].name string yes

Tells the office what the caller made in a work item: a ticket it created, or a pull request it opened and the ticket that pull request links to. The office records them on the item, so the item’s hand-back also gives those tickets, once in review, to the person who asked.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string yes Id of the work item.
ticket string no Without pr: the key of the ticket the caller created. With it: the ticket the pull request links to, when any.
pr object no The pull request the caller opened.
pr.repo object yes
pr.repo.owner string yes Owner of the repository.
pr.repo.name string yes Name of the repository.
pr.repo.host string no Host of the code host.
pr.number integer yes Number of the pull request.
pr.url string no Its page on the code host.

Asks for the caller’s work items.

Sent by: agent. Answered by: work_list_result, error.

Field Type Required Description
workItemId string no Id of the work item.

The caller’s work items.

Sent by: office.

Field Type Required Description
items list of objects yes
items[].id string yes
items[].title string yes
items[].status string yes
items[].kind string no What the item is, for example assigned or review_feedback.
items[].ticketKey string no
items[].ticketTitle string no
items[].pr string no The office’s key of the pull request the item is about.
items[].prNumber integer no
items[].prTitle string no
items[].prUrl string no
items[].current boolean no True for the item the caller asked about.

Asks for the state of a list of work items, for example to find the ones whose worktree and scratch folder can go.

Sent by: agent. Answered by: work_status_result, error.

Field Type Required Description
workItemIds list of string yes The items to ask about.

The state of each item asked about, in the order asked. An item of someone else is not_yours and an item the office does not have is unknown; nothing else about either is given.

Sent by: office.

Field Type Required Description
items list of objects yes
items[].workItemId string yes Id of the work item.
items[].state queued or active or waiting or blocked or done or canceled or not_yours or unknown yes The item’s status. not_yours when it belongs to someone else, whatever its status; unknown when the office has no such item.

Changes the status of one of the caller’s work items.

Sent by: agent. Answered by: work_move_result, error.

Field Type Required Description
workItemId string yes Id of the work item.
status queued or blocked or canceled yes The new status.

The item after the move.

Sent by: office.

Field Type Required Description
item object yes
item.id string yes
item.title string yes
item.status string yes
item.kind string no What the item is, for example assigned or review_feedback.
item.ticketKey string no
item.ticketTitle string no
item.pr string no The office’s key of the pull request the item is about.
item.prNumber integer no
item.prTitle string no
item.prUrl string no
item.current boolean no True for the item the caller asked about.

Moves one of the caller’s queued items to a place in the queue.

Sent by: agent. Answered by: work_move_result, error.

Field Type Required Description
workItemId string yes Id of the work item.
position next or last or before or after yes Where among the queued items it goes.
relativeTo string no The queued item to go before or after; required for before and after.

Files the ticket a chat session created as work: the office creates a work item for it, in the thread the session answers in. Refused for an item that is not a chat session.

Sent by: agent. Answered by: work_link_result, error.

Field Type Required Description
workItemId string yes Id of the work item.
ticket string yes Key of the ticket the agent created.
request string yes Title of the request the ticket files.

Records the ticket a chat session created for someone else against the chat request: no work item is created, and the session’s own work is not tied to the ticket. The assignee is woken by the assignment, like any other. Refused like work_link.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string yes Id of the work item.
ticket string yes Key of the ticket the agent created.
request string yes Title of the request the ticket files.
assignee string yes Who the ticket was filed for, as the tracker names them.

Asks whether a chat session may file a request now, before it creates the ticket. Refused for an item that is not a chat session and for a request the message already filed, so a refused filing leaves nothing in the tracker.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string yes Id of the work item.
request string yes Title of the request about to be filed.

The work item created for the ticket, and whether it waits for its place.

Sent by: office.

Field Type Required Description
url string no Link to the ticket.
item object yes The work item that carries the filed work.
item.id string yes
item.title string yes
item.status string yes
item.kind string no What the item is, for example assigned or review_feedback.
item.ticketKey string no
item.ticketTitle string no
item.pr string no The office’s key of the pull request the item is about.
item.prNumber integer no
item.prTitle string no
item.prUrl string no
item.current boolean no True for the item the caller asked about.
waiting boolean yes True when the person is busy: the item waits at the end until the requester says where it goes. False when it starts now.
work list of objects yes The person’s other open items in the order they run, for the placement question.
work[].id string yes
work[].title string yes
work[].status string yes
work[].kind string no What the item is, for example assigned or review_feedback.
work[].ticketKey string no
work[].ticketTitle string no
work[].pr string no The office’s key of the pull request the item is about.
work[].prNumber integer no
work[].prTitle string no
work[].prUrl string no
work[].current boolean no True for the item the caller asked about.

Files work from a chat session when there is no tracker: the office creates a work item for it, in the thread the session answers in. Refused for an item that is not a chat session.

Sent by: agent. Answered by: work_queue_result, error.

Field Type Required Description
workItemId string yes Id of the work item.
title string yes Short title of the work.
body string no What is asked and why.

The work item created for the request, and whether it waits for its place.

Sent by: office.

Field Type Required Description
url string no Link to the ticket.
item object yes The work item that carries the filed work.
item.id string yes
item.title string yes
item.status string yes
item.kind string no What the item is, for example assigned or review_feedback.
item.ticketKey string no
item.ticketTitle string no
item.pr string no The office’s key of the pull request the item is about.
item.prNumber integer no
item.prTitle string no
item.prUrl string no
item.current boolean no True for the item the caller asked about.
waiting boolean yes True when the person is busy: the item waits at the end until the requester says where it goes. False when it starts now.
work list of objects yes The person’s other open items in the order they run, for the placement question.
work[].id string yes
work[].title string yes
work[].status string yes
work[].kind string no What the item is, for example assigned or review_feedback.
work[].ticketKey string no
work[].ticketTitle string no
work[].pr string no The office’s key of the pull request the item is about.
work[].prNumber integer no
work[].prTitle string no
work[].prUrl string no
work[].current boolean no True for the item the caller asked about.

Makes a chat session’s request part of existing work of the caller (a ticket or a pull request) instead of new work: the request becomes a round on it, carrying the human’s message as feedback, and the thread belongs to that item. Refused for work that is not the caller’s, for merged or done work, and for a pull request in review unless the requester confirmed.

Sent by: agent. Answered by: work_attach_result, error.

Field Type Required Description
workItemId string yes Id of the work item.
target string yes A ticket key, or a pull request: its number, #number, owner/repo#number or link.
confirmed boolean no True when the requester said in the thread that the request belongs to a pull request that is in review.
request string no What to add, when the session’s message is only the requester’s answer and the request came earlier in the thread. Default: the session’s message.

The existing work the request is part of now.

Sent by: office.

Field Type Required Description
url string no Link to the ticket.
item object yes The work item that carries the filed work.
item.id string yes
item.title string yes
item.status string yes
item.kind string no What the item is, for example assigned or review_feedback.
item.ticketKey string no
item.ticketTitle string no
item.pr string no The office’s key of the pull request the item is about.
item.prNumber integer no
item.prTitle string no
item.prUrl string no
item.current boolean no True for the item the caller asked about.
waiting boolean yes True when the person is busy: the item waits at the end until the requester says where it goes. False when it starts now.
work list of objects yes The person’s other open items in the order they run, for the placement question.
work[].id string yes
work[].title string yes
work[].status string yes
work[].kind string no What the item is, for example assigned or review_feedback.
work[].ticketKey string no
work[].ticketTitle string no
work[].pr string no The office’s key of the pull request the item is about.
work[].prNumber integer no
work[].prTitle string no
work[].prUrl string no
work[].current boolean no True for the item the caller asked about.
attached object yes The existing work the request is part of now.
attached.ticket object no The ticket the request was added to.
attached.ticket.type string yes Kind of subject, for example a ticket or a pull request.
attached.ticket.ref string yes Reference of the subject in its system.
attached.ticket.title string no Human-readable title.
attached.ticket.url string no Link to the subject.
attached.ticket.headRef string no For a pull request: the branch it is opened from.
attached.ticket.baseRef string no For a pull request: the branch it targets.
attached.ticket.state open or closed or merged no For a pull request: whether it is open, closed or merged.
attached.ticket.draft boolean no For a pull request: whether it is a draft.
attached.ticket.own boolean no For a pull request: true when the person the item is offered to opened it.
attached.pr object no The pull request the request was added to.
attached.pr.type string yes Kind of subject, for example a ticket or a pull request.
attached.pr.ref string yes Reference of the subject in its system.
attached.pr.title string no Human-readable title.
attached.pr.url string no Link to the subject.
attached.pr.headRef string no For a pull request: the branch it is opened from.
attached.pr.baseRef string no For a pull request: the branch it targets.
attached.pr.state open or closed or merged no For a pull request: whether it is open, closed or merged.
attached.pr.draft boolean no For a pull request: whether it is a draft.
attached.pr.own boolean no For a pull request: true when the person the item is offered to opened it.

A message from a trusted human in chat. The office takes it in as a chat.message event, which its pipeline decides on (by default it wakes the person in a chat session). Delivered at least once; the office recognizes a message it took in already.

Sent by: agent. Answered by: chat_message_result, error.

Field Type Required Description
messageId string yes Id of the message in the chat workspace.
channel string yes
thread string no Thread of the message; absent for a top-level message.
text string yes What the author wrote; empty for a message that only shares files.
author object yes
author.id string yes
author.name string no
direct boolean yes The message is in a direct message with the author.
participant boolean yes The author started the thread or replied in it.
files list of objects no Files shared in the message: metadata only, no bytes. Data from the author.
files[].id string yes Id of the file in the chat workspace.
files[].name string yes File name, as the sender named it. Data from them.
files[].mimetype string yes
files[].size integer yes Size in bytes.
files[].url string yes Where the chat adapter fetches the bytes from. Only the agent’s chat adapter uses it; the office stores it as it is and never fetches it.

The office took the message in; the agent answers nothing until the work it starts does.

Sent by: office.

Field Type Required Description
repeated boolean yes True when the office already took this message in.

Asks to tell the requester how an item ended: a chat item’s result or blocked report in its thread, and for a blocked item the blocked report to the requester’s direct message. The office grants it once per ending, so a retried hand-back does not post twice, and never posts anything itself.

Sent by: agent. Answered by: chat_report_result, error.

Field Type Required Description
workItemId string yes Id of the work item.
kind ack or result or blocked or failed yes What the agent is about to tell the requester.

Whether to post, whom to mention and which links to include.

Sent by: office.

Field Type Required Description
post boolean yes False when nothing should be posted: no chat origin and no blocked report to the requester, or already reported.
requester string no Id of the requester to mention.
links list of objects yes The ticket and pull requests of the item.
links[].url string yes Absolute URL.
links[].title string no Label for the link.
threads list of objects no Every thread linked to the item now, to post the report in: the one it came from and the ones attached later. Absent when the report goes to a direct message instead.
threads[].channel string yes Chat channel of the request.
threads[].thread string yes Thread the agent answers in.
threads[].requester object yes
threads[].requester.id string yes Id of the requester in the chat workspace.
threads[].requester.name string no
threads[].direct boolean yes The conversation is a direct message with the requester.
threads[].participant boolean yes The requester started the thread or replied in it, so the chat already notifies them.
direct string no For a blocked report on an item without a chat thread: the requester’s chat user id. Open a direct message with them and post the report there.

Reports to requesters for the agent to post as itself, sent while it is connected (the same list the welcome carries on connecting). Sent again until the agent confirms each with report_posted.

Sent by: office.

Field Type Required Description
reports list of objects yes Reports to requesters the agent has not confirmed posting yet.
reports[].id string yes Id of this report. The office sends it again until the agent confirms with report_posted, so the agent skips an id it posted already.
reports[].workItemId string yes Id of the work item.
reports[].kind result or blocked yes How the item ended.
reports[].text string yes What the agent handed back: the summary to report.
reports[].requester string no Id of the requester to mention.
reports[].links list of objects yes The ticket and pull requests of the item.
reports[].links[].url string yes Absolute URL.
reports[].links[].title string no Label for the link.
reports[].threads list of objects no Every thread linked to the item now, to post the report in: the one it came from and the ones attached later. Absent when the report goes to a direct message instead.
reports[].threads[].channel string yes Chat channel of the request.
reports[].threads[].thread string yes Thread the agent answers in.
reports[].threads[].requester object yes
reports[].threads[].requester.id string yes Id of the requester in the chat workspace.
reports[].threads[].requester.name string no
reports[].threads[].direct boolean yes The conversation is a direct message with the requester.
reports[].threads[].participant boolean yes The requester started the thread or replied in it, so the chat already notifies them.
reports[].direct string no For a blocked report on an item without a chat thread: the requester’s chat user id. Open a direct message with them and post the report there.

Confirms the agent posted a queued report. Only then does the office stop sending it, so a crash while posting sends it again.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string yes Id of the work item.
id string yes The id of the report the agent posted.

Tracker or knowledge-base changes the event pipeline decided for the agent (an act decision): moves, assignments, comments, parents, pull request and document links, and the ticket’s usage fields (set_field, which the office decides itself after a round, not the pipeline). The agent makes them with its own tracker and knowledge credentials, in order, without a model run, and answers with act_result. Sent while the agent is connected; the welcome carries the ones it has not answered.

Sent by: office.

Field Type Required Description
id string yes Id of the act. The office sends it again until the agent answers with act_result, so the agent makes an id’s changes once and only answers again.
ops list of any yes The changes, made in order.

What the agent’s changes for an act did. Only then does the office stop sending the act; it records the result on the event’s trace and reads the tickets changed again, so later decisions see the change.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
id string yes The id of the act.
ok boolean yes True when every change was made.
results list of string yes One line per change made, in order.
error string no The change that failed and why. The changes after it were not tried; the ones before it stay made.

Tells the office that the caller wrote a document for the ticket of a work item (or the ticket it names), so comments people leave on the document reach the caller as work, and the document is linked on the ticket in the tracker.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
workItemId string yes Id of the work item.
doc object yes
doc.id string yes Id of the document in the knowledge base.
doc.title string yes Title of the document.
doc.url string yes Absolute URL of the document.
ticket string no Key of the ticket the document is for; without it, the ticket of the work item.

Tells the office that the caller’s notes changed (ost note), were moved to the knowledge base, or have a version by someone it does not trust. The office logs it and, for notes kept in the knowledge base, records the page as the caller’s document, so comments on it reach the caller.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
change added or updated or removed or migrated or edit_ignored yes What happened: the caller added, changed or removed a note, wrote the notes it had on its volume to the knowledge base on first start, or found a version of its notes by someone it does not trust, which it does not use.
note string no The note added, changed (its new text) or removed.
count integer no For migrated: how many notes.
doc object no The page that shows the notes, when they are kept in the knowledge base; comments on it reach the caller.
doc.id string yes Id of the page in the knowledge base.
doc.title string yes Title of the page.
doc.url string yes Absolute URL of the page.
edit object no For edit_ignored: the version that is not used.
edit.author string yes Who wrote the version, as the knowledge base names them.
edit.at string yes When.
edit.version string yes The version that is not used.
workItemId string no The work item the caller was on, if any.

Reports the checks only the agent’s own container can make, run once at start: its declared tools installed, its granted services and devices answer, and its home volume has room. The office stores them with its own checks.

Sent by: agent. Answered by: ack, error.

Field Type Required Description
checks list of objects yes Every check the agent ran at start; replaces its earlier report.
checks[].name string yes What is checked, for example Tools install.
checks[].status ok or warn or fail yes
checks[].detail string yes What was found, naming the value that is wrong.
checks[].fix string no What to change, when the check is not ok.
checks[].key string no The secret key the check is about, when it is about one.
checks[].adapter string no The adapter that made the check, if one did.

Asks for the caller’s open tickets and pull requests, as context for a chat session.

Sent by: agent. Answered by: current_work_result, error.

No payload fields.

The caller’s current work as text.

Sent by: office.

Field Type Required Description
text string yes

Asks which ticket a pull request about to be opened would link to, its status and which pull requests that ticket already has, so ost pr open can keep to one open pull request per ticket and open none for a finished ticket.

Sent by: agent. Answered by: ticket_prs_result, error.

Field Type Required Description
headRef string yes Branch the pull request would be opened from.
title string yes Title it would have.
body string yes Description it would have.

The ticket the pull request would link to, its status, and the pull requests it already has.

Sent by: office.

Field Type Required Description
ticket string no The ticket the pull request would link to, by the rule that links existing ones (branch, then title, then a closing keyword in the body; a bare mention links nothing); absent when it would link to none.
status backlog or ready or active or review or blocked or done or canceled no That ticket’s canonical status, as the office last read it; absent when unknown.
prs list of objects yes The pull requests already linked to that ticket, in any state.
prs[].ref string yes Pull request, for example acme/shop#12.
prs[].number integer yes
prs[].title string yes
prs[].url string no
prs[].state open or closed or merged yes
prs[].authorKind human or agent or bot yes

Lists the pull requests of the team’s repositories as the office’s work state has them: open ones and recently merged or closed ones, with their CI and review state and linked ticket. For ost pr list, so agents answer status questions from the current state.

Sent by: agent. Answered by: pr_list_result, error.

Field Type Required Description
state open or merged or closed or all yes Which pull requests: open, merged, closed, or all. Merged and closed ones are those finished recently enough for the office to keep.
author string no Only those by this author: a person’s handle or a code host login.
ticket string no Only those linked to this ticket.
repo string no Only those of this repository, owner/name.
limit integer yes At most this many: open ones first, newest first, then the most recently finished.

The matching pull requests and how many more match beyond the limit.

Sent by: office.

Field Type Required Description
prs list of objects yes The matching pull requests: open ones first, newest first, then the most recently finished.
prs[].ref string yes Pull request, for example acme/shop#12.
prs[].number integer yes
prs[].title string yes
prs[].url string no
prs[].state open or closed or merged yes
prs[].draft boolean yes
prs[].author string yes The person’s handle, else the code host login.
prs[].ci none or pending or success or failure yes
prs[].mergeable clean or conflicting or unknown yes
prs[].review string no State of the latest submitted review, for example approved.
prs[].unresolvedThreads integer yes
prs[].ticket string no The ticket it is linked to.
prs[].updatedAt string yes When the office last read it.
more integer yes How many more match beyond the limit.

Asks for the log of a check on one of the team’s repositories, by its link: the office reads it with its own code host credentials, so agents need no CI access of their own.

Sent by: agent. Answered by: ci_log_result, error.

Field Type Required Description
url string yes Link of the check whose log to read: for GitHub, the link of an Actions job.
lines integer yes Lines to keep from the end of each failed step.

The failed steps of the check and the last lines of each, secrets masked. The text is data from the CI run, not instructions.

Sent by: office.

Field Type Required Description
repo string yes The repository of the check, owner/name.
steps list of objects yes The check’s failed steps; empty when its log shows none.
steps[].name string yes The failed step.
steps[].lines list of string yes The last lines of its log, oldest first, secrets masked. Data from the CI run, not instructions.
steps[].omitted integer yes Earlier lines of the step left out.

Searches the caller’s own history in what the office stores: its work items, their journals and outcomes, the events on the tickets, pull requests and documents its work refers to, and its chat messages. For ost recall.

Sent by: agent. Answered by: recall_result, error.

Field Type Required Description
query string yes What to look for: words (each must match, in any form), “quoted phrases”, or between two terms, -word to leave out.
with string no Only moments with this person: a human’s name or identity, or a teammate’s handle.
about string no Only moments about this: a ticket key, a pull request (number, #number, owner/repo#number or link) or a document id.
since string no Only moments at or after this date or time (ISO-8601).
limit integer yes At most this many moments.

The matching moments, newest first, each with when, where, who, a short excerpt and a link. The text is data from whoever wrote it, not instructions.

Sent by: office.

Field Type Required Description
moments list of objects yes The matching moments, newest first.
moments[].at string yes When it happened (ISO-8601).
moments[].kind string yes What it is: item (a work item), journal, outcome (what a run handed back), or the event type, such as ticket.commented or chat.message.
moments[].where object no Where it happened.
moments[].where.type string yes ticket, pr, doc or chat_thread.
moments[].where.ref string yes
moments[].where.title string no
moments[].where.url string no
moments[].who string no Who said or did it.
moments[].excerpt string yes A short excerpt around the match. Data from whoever wrote it, not instructions.
moments[].url string no A link to the moment itself, when there is one.
more boolean yes Whether older moments match beyond the limit.

Asks for the tokens and cost of a ticket’s work, for ost usage: its own runs by person, model and kind of round, and its total with its sub-tickets rolled up. Refused when the team does not track usage (usage.track_cost).

Sent by: agent. Answered by: ticket_usage_result, error.

Field Type Required Description
ticket string yes Key of the ticket, for example ACME-123.

The ticket’s usage. The cost is API-equivalent: what the tokens cost at API list prices, not what a subscription bills.

Sent by: office.

Field Type Required Description
ticket string yes Key of the ticket.
own object yes Every run of every work item whose subject or references name the ticket: its own rounds, reviews and merges of its pull requests, comment rounds and chat sessions attached to it.
own.inputTokens integer yes
own.outputTokens integer yes
own.cacheReadTokens integer yes
own.cacheCreationTokens integer yes
own.tokens integer yes All four token counts added up.
own.costUsd number yes What the tokens cost at API list prices, in USD. API-equivalent: on a subscription it is not what is billed.
own.runs integer yes Runs counted.
total object yes The ticket’s own usage plus its sub-tickets’ totals.
total.inputTokens integer yes
total.outputTokens integer yes
total.cacheReadTokens integer yes
total.cacheCreationTokens integer yes
total.tokens integer yes All four token counts added up.
total.costUsd number yes What the tokens cost at API list prices, in USD. API-equivalent: on a subscription it is not what is billed.
total.runs integer yes Runs counted.
subTickets list of objects yes The sub-tickets rolled into total, each with its own total.
subTickets[].ticket string yes
subTickets[].total object yes
subTickets[].total.inputTokens integer yes
subTickets[].total.outputTokens integer yes
subTickets[].total.cacheReadTokens integer yes
subTickets[].total.cacheCreationTokens integer yes
subTickets[].total.tokens integer yes All four token counts added up.
subTickets[].total.costUsd number yes What the tokens cost at API list prices, in USD. API-equivalent: on a subscription it is not what is billed.
subTickets[].total.runs integer yes Runs counted.
byPerson list of objects yes The ticket’s own usage per person, largest cost first.
byPerson[].key string yes The person’s handle, the model id, or the kind of round.
byPerson[].totals object yes
byPerson[].totals.inputTokens integer yes
byPerson[].totals.outputTokens integer yes
byPerson[].totals.cacheReadTokens integer yes
byPerson[].totals.cacheCreationTokens integer yes
byPerson[].totals.tokens integer yes All four token counts added up.
byPerson[].totals.costUsd number yes What the tokens cost at API list prices, in USD. API-equivalent: on a subscription it is not what is billed.
byPerson[].totals.runs integer yes Runs counted.
byModel list of objects yes The ticket’s own usage per model id, largest cost first.
byModel[].key string yes The person’s handle, the model id, or the kind of round.
byModel[].totals object yes
byModel[].totals.inputTokens integer yes
byModel[].totals.outputTokens integer yes
byModel[].totals.cacheReadTokens integer yes
byModel[].totals.cacheCreationTokens integer yes
byModel[].totals.tokens integer yes All four token counts added up.
byModel[].totals.costUsd number yes What the tokens cost at API list prices, in USD. API-equivalent: on a subscription it is not what is billed.
byModel[].totals.runs integer yes Runs counted.
byKind list of objects yes The ticket’s own usage per kind of round (the work item’s kind, for example assigned or review_feedback), largest cost first.
byKind[].key string yes The person’s handle, the model id, or the kind of round.
byKind[].totals object yes
byKind[].totals.inputTokens integer yes
byKind[].totals.outputTokens integer yes
byKind[].totals.cacheReadTokens integer yes
byKind[].totals.cacheCreationTokens integer yes
byKind[].totals.tokens integer yes All four token counts added up.
byKind[].totals.costUsd number yes What the tokens cost at API list prices, in USD. API-equivalent: on a subscription it is not what is billed.
byKind[].totals.runs integer yes Runs counted.

The request succeeded and has nothing to return.

Sent by: office.

No payload fields.

A request failed, or a message was malformed or not understood. Never closes the connection by itself, except for authentication and version errors.

Sent by: either side.

Field Type Required Description
code malformed or unknown_type or invalid_message or unauthenticated or auth_failed or version_mismatch or replaced or unknown_item or not_found or invalid or unsupported or failed yes
message string yes

Liveness check.

Sent by: either side. Answered by: pong.

No payload fields.

Answers a ping.

Sent by: either side.

No payload fields.