Skip to content

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

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.
{
"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"]
}