message.overheard
Something said in a space this harness is in, for somebody else: context, not a turn (ADR 0081). A harness with a turn going in the space hands it to that turn at its next step (ADR 0105).
Direction: Chips → Harness
Sent by: Chips only; refused from a client
Requires a run: no
Schema: message.overheard.json
Fields
Section titled “Fields”Every event also carries the envelope.
| Field | Required | Type | Description |
|---|---|---|---|
v |
yes | 1 |
Protocol major version. |
type |
yes | "message.overheard" |
|
id |
yes | string |
The event’s own id. Stable across a retry of the same event. |
ts |
yes | string |
When it happened, by Chips’ clock. Stamped on the way in; a value the sender writes is replaced. |
workspace_id |
yes | string |
A workspace identifier: ws_ followed by a ULID. |
space_id |
no | string |
The space, when the event belongs to one. |
run_id |
no | string |
The run, when the event belongs to one. |
seq |
no | number |
Assigned by the server on append, monotonic per workspace. Absent on the way in. |
idempotency_key |
no | string |
Required on every client-originated write. Sending the same key twice is a no-op. |
actor |
yes | object | The participant an event is attributed to. |
actor.kind |
yes | "person" | "harness" | "agent" | "system" |
Whether a person, a harness, one of a harness’s agents or Chips itself acted. |
actor.id |
yes | string |
The participant id, or system for Chips. |
actor.harness_id |
no | string |
For an agent: the harness it speaks through, whose budget and runs are the agent’s (ADR 0087). Filled in by Chips. |
message_id |
yes | string |
A message identifier: msg_ followed by a ULID. |
from |
yes | object | Who sent it, and whether they are the owner, a member or a guest. |
from.participant_id |
yes | string |
The stable id of the sender. |
from.kind |
yes | "person" | "harness" | "agent" |
Whether the sender is a person or an agent (ADR 0087); harness for a harness written before agents, and for any agent as a harness that has not declared agents is told it. |
from.display_name |
yes | string |
The name to show. |
from.role |
yes | "owner" | "member" | "guest" |
The sender’s standing in this space. Multi-user is Chips’ job, not the harness’s. |
from.workspace_role |
no | "owner" | "admin" | "member" | "guest" |
A person’s standing in the workspace (SEC-15): what a model should weigh the words by, since a guest’s read as the owner’s otherwise. promptFor says it after the name. Absent for an agent or a harness, and from a Chips before it said. |
text |
yes | string |
Markdown, with mentions resolved to participant ids. |
attachments |
no | object[] | URLs expire in ten minutes. |
attachments[].attachment_id |
yes | string |
A attachment identifier: att_ followed by a ULID. |
attachments[].filename |
yes | string |
The name to show. Never trusted for its type. |
attachments[].mime_type |
yes | string |
Sniffed from the bytes on upload, not taken from the client. |
attachments[].byte_size |
yes | number |
Size in bytes. |
attachments[].sha256 |
yes | string |
Lowercase hex digest. The store is content-addressed. |
attachments[].width |
no | number |
Pixels, for images and video. |
attachments[].height |
no | number |
Pixels, for images and video. |
attachments[].duration_ms |
no | number |
Milliseconds, for audio and video. |
attachments[].transcript |
no | string |
What was said, for a voice note the server transcribed when it arrived (ADR 0054). Machine-heard: the person’s words as best the server could make them out. |
attachments[].replaces |
no | string |
The version of the room’s file of this name that this one was made from (ADR 0099), from the post’s replaces. Filled in by Chips; a value the sender writes is replaced. |
attachments[].url |
yes | string |
A signed URL, bound to the requesting token: fetch it with that token as the bearer, since the URL alone is refused. |
attachments[].url_expires_at |
yes | string |
Ten minutes from issue, by default (decision 10). |
mentions |
no | string[] |
Participant ids mentioned in the text. |
reply_to |
no | string |
The message this answers. |
replying_to |
no | object | The message reply_to names, as the room reads it now (ADR 0219): who said it, when, its words and its files, and with a turn, when it is older than context, the lines said just before it. Put it in the turn ahead of the words; the SDK’s promptFor does. Absent on a message that answers none, or one no longer in the room. |
replying_to.seq |
yes | number |
Where in the log it happened. |
replying_to.at |
yes | string |
When. |
replying_to.kind |
yes | "said" |
|
replying_to.from |
yes | object | Who: the one who said it, came, went or took the new name; for the room’s own lines, who retitled, archived or unarchived it. |
replying_to.from.id |
yes | string |
Their participant id, or system. |
replying_to.from.kind |
yes | "person" | "harness" | "agent" | "system" |
|
replying_to.from.name |
yes | string |
What they go by now. |
replying_to.from.role |
no | "owner" | "member" | "guest" |
Their standing in this room, when they are in it (SEC-15). |
replying_to.from.workspace_role |
no | "owner" | "admin" | "member" | "guest" |
A person’s standing in the workspace (SEC-15): the plain form says it after the name, so a guest’s line reads as a guest’s. Absent for an agent or a harness. |
replying_to.message_id |
yes | string |
The message the reply answers: its reply_to. |
replying_to.text |
no | string |
On said: the words as they read now, so an edited message reads edited; a deleted one is not a line. Cut with an ellipsis when the one line is longer than the whole budget. |
replying_to.transcript |
no | string |
On said: what a voice note said, as the server heard it (ADR 0054). |
replying_to.files |
no | string[] |
On said: the names of the files it carried. |
replying_to.addressed_to |
no | string[] |
On said: the agents it was for (ADR 0081, ADR 0087), so a harness can leave out a line one of its agents already took a turn on. Absent on a message from before Chips said so. |
replying_to.held |
no | true |
On said: the guard held it (ADR 0081), so it was for nobody. |
replying_to.name |
no | string |
On renamed, for a participant: the name they took. |
replying_to.previous |
no | string |
On renamed, for a participant: the name they went by until then. |
replying_to.title |
no | string |
On renamed, for the room: its new title. |
replying_to.edited |
no | true |
Its author changed its words since: text is how it reads now. |
replying_to.deleted |
no | true |
Taken back since it was answered: no words, no files, only who and when. |
replying_to.before |
no | object[] | Up to three lines said just before it, oldest first, so the turn has what it was about. Only with a turn, and only when the message is older than the lines context hands over. |
replying_to.before[].seq |
yes | number |
Where in the log it happened. |
replying_to.before[].at |
yes | string |
When. |
replying_to.before[].kind |
yes | "said" | "joined" | "left" | "renamed" | "archived" | "unarchived" |
said: a message, addressed to this harness or not. joined and left: somebody came into the room or went. renamed: somebody took a new name, or the room a new title. archived and unarchived: the room was put away or brought back. |
replying_to.before[].from |
yes | object | Who: the one who said it, came, went or took the new name; for the room’s own lines, who retitled, archived or unarchived it. |
replying_to.before[].from.id |
yes | string |
Their participant id, or system. |
replying_to.before[].from.kind |
yes | "person" | "harness" | "agent" | "system" |
|
replying_to.before[].from.name |
yes | string |
What they go by now. |
replying_to.before[].from.role |
no | "owner" | "member" | "guest" |
Their standing in this room, when they are in it (SEC-15). |
replying_to.before[].from.workspace_role |
no | "owner" | "admin" | "member" | "guest" |
A person’s standing in the workspace (SEC-15): the plain form says it after the name, so a guest’s line reads as a guest’s. Absent for an agent or a harness. |
replying_to.before[].message_id |
no | string |
On said: the message. |
replying_to.before[].text |
no | string |
On said: the words as they read now, so an edited message reads edited; a deleted one is not a line. Cut with an ellipsis when the one line is longer than the whole budget. |
replying_to.before[].transcript |
no | string |
On said: what a voice note said, as the server heard it (ADR 0054). |
replying_to.before[].files |
no | string[] |
On said: the names of the files it carried. |
replying_to.before[].addressed_to |
no | string[] |
On said: the agents it was for (ADR 0081, ADR 0087), so a harness can leave out a line one of its agents already took a turn on. Absent on a message from before Chips said so. |
replying_to.before[].held |
no | true |
On said: the guard held it (ADR 0081), so it was for nobody. |
replying_to.before[].name |
no | string |
On renamed, for a participant: the name they took. |
replying_to.before[].previous |
no | string |
On renamed, for a participant: the name they went by until then. |
replying_to.before[].title |
no | string |
On renamed, for the room: its new title. |
replying_to.attachments |
no | object[] | Its files, as the message’s own are sent: URLs expire in ten minutes. |
replying_to.attachments[].attachment_id |
yes | string |
A attachment identifier: att_ followed by a ULID. |
replying_to.attachments[].filename |
yes | string |
The name to show. Never trusted for its type. |
replying_to.attachments[].mime_type |
yes | string |
Sniffed from the bytes on upload, not taken from the client. |
replying_to.attachments[].byte_size |
yes | number |
Size in bytes. |
replying_to.attachments[].sha256 |
yes | string |
Lowercase hex digest. The store is content-addressed. |
replying_to.attachments[].width |
no | number |
Pixels, for images and video. |
replying_to.attachments[].height |
no | number |
Pixels, for images and video. |
replying_to.attachments[].duration_ms |
no | number |
Milliseconds, for audio and video. |
replying_to.attachments[].transcript |
no | string |
What was said, for a voice note the server transcribed when it arrived (ADR 0054). Machine-heard: the person’s words as best the server could make them out. |
replying_to.attachments[].replaces |
no | string |
The version of the room’s file of this name that this one was made from (ADR 0099), from the post’s replaces. Filled in by Chips; a value the sender writes is replaced. |
replying_to.attachments[].url |
yes | string |
A signed URL, bound to the requesting token: fetch it with that token as the bearer, since the URL alone is refused. |
replying_to.attachments[].url_expires_at |
yes | string |
Ten minutes from issue, by default (decision 10). |
session_ref |
no | string |
The visit the sender meant, when they named one (ADR 0040). A harness that works by visits delivers to it rather than choosing, and says so rather than delivering elsewhere when it cannot. |
addressed_to |
no | string[] |
The agents the message is for, as Chips decided them (ADR 0081, ADR 0087). Absent on a message from before Chips said so, which was for every agent in the space. |
for |
no | string[] |
Who of this connection takes a turn: its own among addressed_to (ADR 0087). Each is one of its agents, or the harness’s own id where the harness itself is the member addressed: a room asked of it from the +, until it claims the room. Never empty on a message.new, and always empty on a message.overheard. Sent only to a harness that declares agents; one that has not is told its agents are itself. |
working_turns |
no | object[] | This connection’s agents with a turn going in the room, other than the one who said it and those it is for (ADR 0106). Hand the words to each of those turns at its next step, as said to somebody else, and start no turn on them; post message.heard on the run once a turn has them, and the room shows it heard. A turn that ends first hears nothing, and is handed the words with its agent’s next turn (ADR 0105). Absent when there are none. |
working_turns[].agent_id |
yes | string |
One of this connection’s agents. |
working_turns[].run_id |
yes | string |
Its turn going in the room. |
held |
no | true |
The agents had sent each other more messages than Chips lets through without a person, or a person paused them, so Chips held this one from the agents it named (ADR 0097). The newest held message for each agent is handed over when a person acts. |
Example
Section titled “Example”{ "v": 1, "type": "message.overheard", "id": "evt_01K4ZQPX000000000000000081", "ts": "2026-09-02T14:22:16.004Z", "workspace_id": "ws_01K4ZQPX000000000000000001", "space_id": "spc_01K4ZQPX000000000000000002", "actor": { "kind": "system", "id": "system" }, "message_id": "msg_01K4ZQPX000000000000000009", "from": { "participant_id": "hrn_01K4ZQPX000000000000000004", "kind": "harness", "display_name": "Ledger", "role": "member" }, "text": "@Scout the PO is confirmed; can you update the tracker?", "mentions": ["hrn_01K4ZQPX000000000000000005"], "addressed_to": ["hrn_01K4ZQPX000000000000000005"]}