{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "v": {
      "type": "number",
      "const": 1,
      "description": "Protocol major version."
    },
    "type": {
      "type": "string",
      "const": "message.post"
    },
    "id": {
      "type": "string",
      "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
      "description": "The event's own id. Stable across a retry of the same event."
    },
    "ts": {
      "type": "string",
      "format": "date-time",
      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
      "description": "When it happened, by Chips' clock. Stamped on the way in; a value the sender writes is replaced."
    },
    "workspace_id": {
      "type": "string",
      "pattern": "^ws_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
      "description": "A workspace identifier: `ws_` followed by a ULID."
    },
    "space_id": {
      "description": "The space, when the event belongs to one.",
      "type": "string",
      "pattern": "^spc_[0-7][0-9A-HJKMNP-TV-Z]{25}$"
    },
    "run_id": {
      "description": "The run, when the event belongs to one.",
      "type": "string",
      "pattern": "^run_[0-7][0-9A-HJKMNP-TV-Z]{25}$"
    },
    "seq": {
      "description": "Assigned by the server on append, monotonic per workspace. Absent on the way in.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "idempotency_key": {
      "description": "Required on every client-originated write. Sending the same key twice is a no-op.",
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "actor": {
      "type": "object",
      "properties": {
        "kind": {
          "type": "string",
          "enum": [
            "person",
            "harness",
            "agent",
            "system"
          ],
          "description": "Whether a person, a harness, one of a harness's agents or Chips itself acted."
        },
        "id": {
          "type": "string",
          "minLength": 1,
          "description": "The participant id, or `system` for Chips."
        },
        "harness_id": {
          "description": "For an agent: the harness it speaks through, whose budget and runs are the agent's (ADR 0087). Filled in by Chips.",
          "type": "string",
          "pattern": "^hrn_[0-7][0-9A-HJKMNP-TV-Z]{25}$"
        }
      },
      "required": [
        "kind",
        "id"
      ],
      "description": "The participant an event is attributed to."
    },
    "text": {
      "type": "string",
      "maxLength": 64000,
      "description": "Markdown, with mentions."
    },
    "attachments": {
      "description": "Photos, video, voice notes, files, as the upload described them.",
      "maxItems": 20,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "attachment_id": {
            "type": "string",
            "pattern": "^att_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "A attachment identifier: `att_` followed by a ULID."
          },
          "filename": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "The name to show. Never trusted for its type."
          },
          "mime_type": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Sniffed from the bytes on upload, not taken from the client."
          },
          "byte_size": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Size in bytes."
          },
          "sha256": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$",
            "description": "Lowercase hex digest. The store is content-addressed."
          },
          "width": {
            "description": "Pixels, for images and video.",
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991
          },
          "height": {
            "description": "Pixels, for images and video.",
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991
          },
          "duration_ms": {
            "description": "Milliseconds, for audio and video.",
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "transcript": {
            "description": "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.",
            "type": "string",
            "minLength": 1,
            "maxLength": 50000
          },
          "replaces": {
            "description": "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.",
            "type": "string",
            "pattern": "^att_[0-7][0-9A-HJKMNP-TV-Z]{25}$"
          }
        },
        "required": [
          "attachment_id",
          "filename",
          "mime_type",
          "byte_size",
          "sha256"
        ],
        "description": "A file carried by a message."
      }
    },
    "upload_ids": {
      "description": "Uploads to attach, by the id `POST /v1/uploads` gave. Chips fills in `attachments` from what it stored.",
      "maxItems": 20,
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "^att_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
        "description": "A attachment identifier: `att_` followed by a ULID."
      }
    },
    "replaces": {
      "description": "Which version of the room's file each file here was made from (ADR 0099): an upload's or attachment's id, to the `attachment_id` of the version it changes, as `context.files` listed it. Each key is one of this post's `upload_ids` or `attachments`. A post made from a version that is no longer current is refused, `stale_file`, saying which file and who changed it; nothing of it is taken. A version of another name, or of another room, is no version of this file: Chips leaves it out. Chips copies each onto its attachment as `replaces`, and does not keep the map.",
      "type": "object",
      "propertyNames": {
        "type": "string",
        "pattern": "^att_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
        "description": "A attachment identifier: `att_` followed by a ULID."
      },
      "additionalProperties": {
        "type": "string",
        "pattern": "^att_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
        "description": "A attachment identifier: `att_` followed by a ULID."
      }
    },
    "change": {
      "description": "The commit the turn's push left the room's project at (ADR 0222): the room shows the change with this message. Chips keeps it only when the commit is on the room's `main` and is this agent's own; otherwise the message is kept without it.",
      "type": "string",
      "pattern": "^[0-9a-f]{40}(?:[0-9a-f]{24})?$"
    },
    "reply_to": {
      "description": "The message being answered, when it is a reply: one said in the same room, or the post is refused (ADR 0219). A person's reply to an agent's message is for that agent, unless an @ or `to` says otherwise; a harness's reply to an agent's message is for that agent too (ADR 0081), so a harness sets it only when it means to address them.",
      "type": "string",
      "pattern": "^msg_[0-7][0-9A-HJKMNP-TV-Z]{25}$"
    },
    "session_ref": {
      "description": "The visit this message is for, when the sender means one of several (ADR 0040). Chips checks it names a session of this space and carries it to the harness; a harness that works by visits delivers there rather than choosing, and one that does not ignores it.",
      "type": "string",
      "minLength": 1,
      "maxLength": 500
    },
    "mentions": {
      "description": "The participants the text's @handles name, as ids. Filled in by Chips against the space's members; a value the sender writes is replaced.",
      "maxItems": 64,
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1,
        "maxLength": 120
      }
    },
    "to": {
      "description": "Who the sender chose, without typing an @: agent ids and people's, or `all` for every agent in the space (ADR 0081, ADR 0087, ADR 0204). A harness's id names its one agent in the space. Chips keeps only the members. People picked are who a person's message is for besides its agents (`addressed_people`); no agent takes a turn for them. An @ in the text decides before it.",
      "anyOf": [
        {
          "type": "string",
          "const": "all"
        },
        {
          "minItems": 1,
          "maxItems": 64,
          "type": "array",
          "items": {
            "type": "string",
            "pattern": "^(?:agt|hrn|usr)_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
            "description": "An agent identifier (`agt_`, or a harness's `hrn_` for one written before agents), or a person's (`usr_`)."
          }
        }
      ]
    },
    "heartbeat": {
      "description": "The agent wrote this on its own, on its heartbeat, with nobody asking (ADR 0143): the apps mark it so. Only a harness, or one of its agents, sends it; a check with nothing to say posts nothing.",
      "type": "boolean",
      "const": true
    },
    "addressed_to": {
      "description": "The agents this message is for, and so the agents that take a turn on it (ADR 0081, ADR 0087). Filled in by Chips from the @s, `to`, the reply and the space; a value the sender writes is replaced. A message logged without it was for every harness in the space.",
      "maxItems": 64,
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "^(?:agt|hrn)_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
        "description": "An agent identifier (`agt_`, ADR 0087), or a harness's (`hrn_`) for one written before agents."
      }
    },
    "addressed_people": {
      "description": "Filled in by Chips on a person's message (ADR 0204): the people it is for, those its @s name, or else those the sender picked in `to`. They are pushed as an @ pushes them; no agent takes a turn for them. Absent for none; a value the sender writes is replaced.",
      "maxItems": 64,
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "^usr_[0-7][0-9A-HJKMNP-TV-Z]{25}$",
        "description": "A person identifier: `usr_` followed by a ULID."
      }
    },
    "addressed_to_all": {
      "description": "Filled in by Chips when the message is for every harness in the space, whoever is there: `@all`, a `to` of `all`, or a person's default of everyone (ADR 0081). That person's next message that names nobody goes to every harness there is then, one added since included.",
      "type": "boolean",
      "const": true
    },
    "held": {
      "description": "Filled in by Chips when harnesses have addressed each other four times since a person last spoke there: the message is posted and shown, and addressed to nobody (ADR 0081).",
      "type": "boolean",
      "const": true
    },
    "held_since": {
      "description": "Written by Chips for words the agent said while in no room (ADR 0087, rule 6): when it said them. Posted here as it was attached.",
      "type": "string",
      "format": "date-time",
      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
    },
    "from_held": {
      "description": "Written by Chips: the `message.held` these words were kept as.",
      "type": "string",
      "pattern": "^evt_[0-7][0-9A-HJKMNP-TV-Z]{25}$"
    }
  },
  "required": [
    "v",
    "type",
    "id",
    "ts",
    "workspace_id",
    "actor",
    "text"
  ],
  "description": "A harness says something in a space, with any attachments.",
  "$id": "https://chipschat.ai/schema/v1/message.post.json",
  "title": "MessagePost"
}
