{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "EventEnvelope",
  "type": "object",
  "properties": {
    "v": {
      "description": "Envelope version, currently 1.",
      "type": "integer",
      "format": "uint8",
      "minimum": 0,
      "maximum": 255
    },
    "type": {
      "$ref": "#/$defs/EventType"
    },
    "id": {
      "description": "Event identifier (ULID), distinct from the request identifier.",
      "type": "string"
    },
    "time": {
      "description": "Event time in RFC3339 UTC.",
      "type": "string"
    },
    "data": {
      "$ref": "#/$defs/EventData"
    }
  },
  "additionalProperties": false,
  "required": [
    "v",
    "type",
    "id",
    "time",
    "data"
  ],
  "$defs": {
    "EventType": {
      "type": "string",
      "enum": [
        "request.created",
        "request.decided",
        "request.expired",
        "request.cancelled",
        "request.reminder",
        "request.expiring"
      ]
    },
    "EventData": {
      "type": "object",
      "properties": {
        "request": {
          "$ref": "#/$defs/EventRequest"
        },
        "decision": {
          "anyOf": [
            {
              "$ref": "#/$defs/Decision"
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "additionalProperties": false,
      "required": [
        "request"
      ]
    },
    "EventRequest": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "title": {
          "type": "string"
        },
        "risk": {
          "$ref": "#/$defs/Risk"
        },
        "agent": {
          "type": [
            "string",
            "null"
          ]
        },
        "source": {
          "$ref": "#/$defs/Source"
        },
        "status": {
          "$ref": "#/$defs/Status"
        },
        "url": {
          "type": "string"
        },
        "deep_link": {
          "type": "string"
        },
        "content": {
          "anyOf": [
            {
              "$ref": "#/$defs/EventContent"
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "additionalProperties": false,
      "required": [
        "id",
        "title",
        "risk",
        "source",
        "status",
        "url",
        "deep_link"
      ]
    },
    "Risk": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ]
    },
    "Source": {
      "type": "object",
      "properties": {
        "integration": {
          "description": "Server-verified integration token name; caller values are overwritten.",
          "type": [
            "string",
            "null"
          ],
          "default": null
        },
        "agent": {
          "type": [
            "string",
            "null"
          ],
          "default": null
        },
        "session": {
          "type": [
            "string",
            "null"
          ],
          "default": null
        },
        "session_title": {
          "description": "Display-only session name; scoped rules always use the session ID.",
          "type": [
            "string",
            "null"
          ]
        },
        "cwd": {
          "type": [
            "string",
            "null"
          ],
          "default": null
        },
        "repo": {
          "type": [
            "string",
            "null"
          ],
          "default": null
        },
        "branch": {
          "type": [
            "string",
            "null"
          ],
          "default": null
        },
        "host": {
          "type": [
            "string",
            "null"
          ],
          "default": null
        }
      },
      "additionalProperties": false
    },
    "Status": {
      "type": "string",
      "enum": [
        "pending",
        "approved",
        "denied",
        "answered",
        "dismissed",
        "expired",
        "cancelled"
      ]
    },
    "EventContent": {
      "type": "object",
      "properties": {
        "summary": {
          "type": [
            "string",
            "null"
          ]
        },
        "previews": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Preview"
          }
        }
      },
      "additionalProperties": false,
      "required": [
        "previews"
      ]
    },
    "Preview": {
      "type": "object",
      "properties": {
        "type": {
          "$ref": "#/$defs/PreviewType"
        },
        "title": {
          "type": [
            "string",
            "null"
          ]
        },
        "lang": {
          "type": [
            "string",
            "null"
          ]
        },
        "inline": {
          "type": [
            "string",
            "null"
          ]
        },
        "blob": {
          "type": [
            "string",
            "null"
          ]
        },
        "mime": {
          "type": [
            "string",
            "null"
          ]
        },
        "name": {
          "type": [
            "string",
            "null"
          ]
        },
        "size": {
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0
        },
        "files": {
          "type": [
            "array",
            "null"
          ],
          "items": {
            "$ref": "#/$defs/PreviewFile"
          }
        },
        "entry": {
          "type": [
            "string",
            "null"
          ]
        },
        "command": {
          "anyOf": [
            {
              "$ref": "#/$defs/Command"
            },
            {
              "type": "null"
            }
          ]
        },
        "email": {
          "anyOf": [
            {
              "$ref": "#/$defs/Email"
            },
            {
              "type": "null"
            }
          ]
        },
        "before_blob": {
          "type": [
            "string",
            "null"
          ]
        },
        "after_blob": {
          "type": [
            "string",
            "null"
          ]
        }
      },
      "additionalProperties": false,
      "required": [
        "type"
      ]
    },
    "PreviewType": {
      "type": "string",
      "enum": [
        "text",
        "markdown",
        "code",
        "diff",
        "files",
        "command",
        "json",
        "html",
        "image",
        "video",
        "audio",
        "file",
        "pdf",
        "email"
      ]
    },
    "PreviewFile": {
      "type": "object",
      "properties": {
        "path": {
          "type": "string"
        },
        "blob": {
          "type": "string"
        },
        "mime": {
          "type": "string"
        },
        "size": {
          "type": "integer",
          "format": "uint64",
          "minimum": 0
        },
        "lang": {
          "type": [
            "string",
            "null"
          ],
          "default": null
        }
      },
      "additionalProperties": false,
      "required": [
        "path",
        "blob",
        "mime",
        "size"
      ]
    },
    "Command": {
      "type": "object",
      "properties": {
        "shell": {
          "type": [
            "string",
            "null"
          ],
          "default": null
        },
        "argv": {
          "type": [
            "array",
            "null"
          ],
          "items": {
            "type": "string"
          },
          "default": null
        },
        "cwd": {
          "type": [
            "string",
            "null"
          ],
          "default": null
        },
        "env_keys": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": []
        }
      },
      "additionalProperties": false
    },
    "Email": {
      "description": "An email draft for review. handup never sends it: on approval the agent\nsends the draft (or the edited `decision.fields`) with its own mail tool.",
      "type": "object",
      "properties": {
        "from": {
          "type": [
            "string",
            "null"
          ]
        },
        "to": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "cc": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "bcc": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "reply_to": {
          "type": [
            "string",
            "null"
          ]
        },
        "subject": {
          "type": "string",
          "default": ""
        },
        "date": {
          "description": "Date shown in the header, as the agent formats it (e.g. RFC 2822).",
          "type": [
            "string",
            "null"
          ]
        },
        "body": {
          "description": "Message body as Markdown (plain text renders as-is).",
          "type": "string",
          "default": ""
        },
        "body_html": {
          "description": "Optional HTML alternative; rendered only in the sandboxed HTML preview frame.",
          "type": [
            "string",
            "null"
          ]
        },
        "attachments": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/EmailAttachment"
          }
        },
        "in_reply_to": {
          "description": "The message this draft replies to, shown collapsed under the body.",
          "anyOf": [
            {
              "$ref": "#/$defs/EmailQuote"
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "additionalProperties": false
    },
    "EmailAttachment": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "mime": {
          "type": [
            "string",
            "null"
          ]
        },
        "size": {
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0
        },
        "blob": {
          "description": "Uploaded blob hash (`POST /v1/blobs`) so the reviewer can open the file.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "additionalProperties": false,
      "required": [
        "name"
      ]
    },
    "EmailQuote": {
      "type": "object",
      "properties": {
        "from": {
          "type": [
            "string",
            "null"
          ]
        },
        "date": {
          "type": [
            "string",
            "null"
          ]
        },
        "body": {
          "description": "Plain text of the earlier message (or a snippet of it).",
          "type": "string",
          "default": ""
        }
      },
      "additionalProperties": false
    },
    "Decision": {
      "type": "object",
      "properties": {
        "option": {
          "type": "string"
        },
        "feedback": {
          "type": [
            "string",
            "null"
          ],
          "default": null
        },
        "fields": {
          "anyOf": [
            {
              "$ref": "#/$defs/DecisionFields"
            },
            {
              "type": "null"
            }
          ],
          "default": null
        },
        "content_hash": {
          "type": "string"
        },
        "decided_by": {
          "type": [
            "string",
            "null"
          ],
          "default": null
        },
        "decided_at": {
          "type": [
            "integer",
            "null"
          ],
          "format": "uint64",
          "minimum": 0,
          "default": null
        },
        "outcome": {
          "anyOf": [
            {
              "$ref": "#/$defs/Outcome"
            },
            {
              "type": "null"
            }
          ],
          "default": null
        },
        "rule_id": {
          "type": [
            "string",
            "null"
          ]
        },
        "scope": {
          "type": [
            "string",
            "null"
          ]
        },
        "run_result": {
          "description": "The desktop app ran the request's command for the human: this is how\nit ended. Present only on approved command requests decided by Run.",
          "anyOf": [
            {
              "$ref": "#/$defs/RunResult"
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "additionalProperties": false,
      "required": [
        "option",
        "content_hash"
      ]
    },
    "DecisionFields": {
      "description": "Decision `fields`. Question requests carry only `answers`, keyed by question\nid; other requests carry answers to `input.fields` or edited tool input.",
      "type": "object",
      "properties": {
        "answers": {
          "type": [
            "object",
            "null"
          ],
          "additionalProperties": {
            "$ref": "#/$defs/Answer"
          }
        }
      }
    },
    "Answer": {
      "description": "The human's answer to one question.",
      "type": "object",
      "properties": {
        "selected": {
          "description": "Chosen option labels; at most one unless the question is `multi`.",
          "type": "array",
          "items": {
            "type": "string"
          },
          "default": []
        },
        "text": {
          "description": "Typed answer; only when the question allows free text.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "additionalProperties": false
    },
    "Outcome": {
      "type": "string",
      "enum": [
        "approve",
        "deny"
      ]
    },
    "RunResult": {
      "description": "Outcome of running a command request in the handup desktop app. The\ncommand already ran: an agent must not run it again. Output is the\nredacted tail of each stream.",
      "type": "object",
      "properties": {
        "exit_code": {
          "description": "Process exit status; absent when it never started or a signal ended it.",
          "type": [
            "integer",
            "null"
          ],
          "format": "int32"
        },
        "stdout_tail": {
          "description": "Last bytes of standard output (at most 64 KiB), credentials redacted.",
          "type": "string",
          "default": ""
        },
        "stderr_tail": {
          "description": "Last bytes of standard error (at most 64 KiB), credentials redacted.",
          "type": "string",
          "default": ""
        },
        "duration_ms": {
          "description": "Wall time from start to exit, in milliseconds.",
          "type": "integer",
          "format": "uint64",
          "minimum": 0,
          "default": 0
        },
        "truncated": {
          "description": "Earlier output was dropped from either tail.",
          "type": "boolean",
          "default": false
        },
        "elevated": {
          "description": "Ran with administrator rights (pkexec on Linux, osascript on macOS).",
          "type": "boolean",
          "default": false
        },
        "error": {
          "description": "Why it did not finish normally: timeout, cancellation, signal, or a\nstart failure (for example pkexec missing or authentication refused).",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "additionalProperties": false
    }
  }
}
