Event schema
Generated by handup schema event (make docs) into docs/public/schema/event.schema.json. Raw file: /schema/event.schema.json.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
v | integer | yes | Envelope version, currently 1. |
type | EventType | yes | |
id | string | yes | Event identifier (ULID), distinct from the request identifier. |
time | string | yes | Event time in RFC3339 UTC. |
data | EventData | yes |
Definitions
EventType
"request.created" | "request.decided" | "request.expired" | "request.cancelled" | "request.reminder" | "request.expiring"
EventData
| Field | Type | Required |
|---|---|---|
request | EventRequest | yes |
decision | Decision | null |
EventRequest
| Field | Type | Required |
|---|---|---|
id | string | yes |
title | string | yes |
risk | Risk | yes |
agent | string | null | |
source | Source | yes |
status | Status | yes |
url | string | yes |
deep_link | string | yes |
content | EventContent | null |
Risk
"low" | "medium" | "high"
Source
| Field | Type | Required |
|---|---|---|
integration | string | null | |
agent | string | null | |
session | string | null | |
session_title | string | null | |
cwd | string | null | |
repo | string | null | |
branch | string | null | |
host | string | null |
Status
"pending" | "approved" | "denied" | "answered" | "dismissed" | "expired" | "cancelled"
EventContent
| Field | Type | Required |
|---|---|---|
summary | string | null | |
previews | Preview[] | yes |
Preview
| Field | Type | Required |
|---|---|---|
type | PreviewType | yes |
title | string | null | |
lang | string | null | |
inline | string | null | |
blob | string | null | |
mime | string | null | |
name | string | null | |
size | integer | null | |
files | PreviewFile[] | null | |
entry | string | null | |
command | Command | null | |
email | Email | null | |
before_blob | string | null | |
after_blob | string | null |
PreviewType
"text" | "markdown" | "code" | "diff" | "files" | "command" | "json" | "html" | "image" | "video" | "audio" | "file" | "pdf" | "email"
PreviewFile
| Field | Type | Required |
|---|---|---|
path | string | yes |
blob | string | yes |
mime | string | yes |
size | integer | yes |
lang | string | null |
Command
| Field | Type | Required |
|---|---|---|
shell | string | null | |
argv | string[] | null | |
cwd | string | null | |
env_keys | string[] |
An email draft for review. handup never sends it: on approval the agent sends the draft (or the edited `decision.fields`) with its own mail tool.
| Field | Type | Required |
|---|---|---|
from | string | null | |
to | string[] | |
cc | string[] | |
bcc | string[] | |
reply_to | string | null | |
subject | string | |
date | string | null | |
body | string | |
body_html | string | null | |
attachments | EmailAttachment[] | |
in_reply_to | EmailQuote | null |
EmailAttachment
| Field | Type | Required |
|---|---|---|
name | string | yes |
mime | string | null | |
size | integer | null | |
blob | string | null |
EmailQuote
| Field | Type | Required |
|---|---|---|
from | string | null | |
date | string | null | |
body | string |
Decision
| Field | Type | Required |
|---|---|---|
option | string | yes |
feedback | string | null | |
fields | DecisionFields | null | |
content_hash | string | yes |
decided_by | string | null | |
decided_at | integer | null | |
outcome | Outcome | null | |
rule_id | string | null | |
scope | string | null | |
run_result | RunResult | null |
DecisionFields
Decision `fields`. Question requests carry only `answers`, keyed by question id; other requests carry answers to `input.fields` or edited tool input.
| Field | Type | Required |
|---|---|---|
answers | object | null |
Answer
The human's answer to one question.
| Field | Type | Required |
|---|---|---|
selected | string[] | |
text | string | null |
Outcome
"approve" | "deny"
RunResult
Outcome of running a command request in the handup desktop app. The command already ran: an agent must not run it again. Output is the redacted tail of each stream.
| Field | Type | Required |
|---|---|---|
exit_code | integer | null | |
stdout_tail | string | |
stderr_tail | string | |
duration_ms | integer | |
truncated | boolean | |
elevated | boolean | |
error | string | null |
JSON Schema
{ "$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 } }}