Skip to content

Request schema

Generated by handup schema request (make docs) intodocs/public/schema/request.schema.json. Raw file: /schema/request.schema.json.

Fields

FieldTypeRequiredDescription
callback_urlstring | nullTerminal-event destination; requires the daemon callbacks.allowlist.
content_hashstring
created_atinteger
decisionDecision | null
dedupe_keystring | null
expires_atinteger | null
idstring
inputRequestInput | null
kindKind
on_timeoutOnTimeout
optionsOption[]
previewsPreview[]
riskRisk
runRunClaim | nullPresent while the desktop app runs the command (daemon-managed).
sourceSource
statusStatus
summarystring | null
timeoutstring | nullOptional positive duration, at most one year. Absent uses config; null/`none` disables expiry.
titlestringyes
toolstring | null

Definitions

Answer

The human's answer to one question.

FieldTypeRequired
selectedstring[]
textstring | null

Command

FieldTypeRequired
argvstring[] | null
cwdstring | null
env_keysstring[]
shellstring | null

Decision

FieldTypeRequired
content_hashstringyes
decided_atinteger | null
decided_bystring | null
feedbackstring | null
fieldsDecisionFields | null
optionstringyes
outcomeOutcome | null
rule_idstring | null
run_resultRunResult | null
scopestring | null

DecisionFields

Decision `fields`. Question requests carry only `answers`, keyed by question id; other requests carry answers to `input.fields` or edited tool input.

FieldTypeRequired
answersobject | null

Email

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.

FieldTypeRequired
attachmentsEmailAttachment[]
bccstring[]
bodystring
body_htmlstring | null
ccstring[]
datestring | null
fromstring | null
in_reply_toEmailQuote | null
reply_tostring | null
subjectstring
tostring[]

EmailAttachment

FieldTypeRequired
blobstring | null
mimestring | null
namestringyes
sizeinteger | null

EmailQuote

FieldTypeRequired
bodystring
datestring | null
fromstring | null

Kind

"command" | "edit" | "review" | "question" | "custom"

OnTimeout

"deny" | "approve" | "expire"

Option

FieldTypeRequired
idstringyes
labelstringyes
outcomeOutcomeyes
stylestring | null

Outcome

"approve" | "deny"

Preview

FieldTypeRequired
after_blobstring | null
before_blobstring | null
blobstring | null
commandCommand | null
emailEmail | null
entrystring | null
filesPreviewFile[] | null
inlinestring | null
langstring | null
mimestring | null
namestring | null
sizeinteger | null
titlestring | null
typePreviewTypeyes

PreviewFile

FieldTypeRequired
blobstringyes
langstring | null
mimestringyes
pathstringyes
sizeintegeryes

PreviewType

"text" | "markdown" | "code" | "diff" | "files" | "command" | "json" | "html" | "image" | "video" | "audio" | "file" | "pdf" | "email"

Question

A question for the human; answered in `decision.fields.answers[id]`.

FieldTypeRequired
allow_free_textboolean
headerstring | null
idstringyes
multiboolean
optionsQuestionOption[]
questionstringyes
recommendedinteger | null

QuestionOption

One selectable answer to a [`Question`].

FieldTypeRequired
descriptionstring | null
labelstringyes
previewstring | null

RequestInput

Request `input`. Only `kind: question` requests interpret `questions`; other keys (for example raw agent tool input) pass through unchanged.

FieldTypeRequired
feedbackstring | null
fieldsany[] | null
questionsQuestion[] | null

Risk

"low" | "medium" | "high"

RunClaim

The handup desktop app on this computer is running the request's command right now. While the claim holds, the request stays pending but no other decision, expiry, or timeout applies; cancelling it stops the run. Set and cleared only by the daemon.

FieldTypeRequired
elevatedboolean
lease_untilintegeryes
started_atintegeryes

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.

FieldTypeRequired
duration_msinteger
elevatedboolean
errorstring | null
exit_codeinteger | null
stderr_tailstring
stdout_tailstring
truncatedboolean

Source

FieldTypeRequired
agentstring | null
branchstring | null
cwdstring | null
hoststring | null
integrationstring | null
repostring | null
sessionstring | null
session_titlestring | null

Status

"pending" | "approved" | "denied" | "answered" | "expired" | "cancelled"

JSON Schema

docs/public/schema/request.schema.json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Request",
"type": "object",
"properties": {
"callback_url": {
"description": "Terminal-event destination; requires the daemon callbacks.allowlist.",
"type": [
"string",
"null"
]
},
"content_hash": {
"type": "string",
"default": ""
},
"created_at": {
"type": "integer",
"format": "uint64",
"default": 0,
"minimum": 0
},
"decision": {
"anyOf": [
{
"$ref": "#/$defs/Decision"
},
{
"type": "null"
}
],
"default": null
},
"dedupe_key": {
"type": [
"string",
"null"
],
"default": null
},
"expires_at": {
"type": [
"integer",
"null"
],
"format": "uint64",
"default": null,
"minimum": 0
},
"id": {
"type": "string",
"default": ""
},
"input": {
"anyOf": [
{
"$ref": "#/$defs/RequestInput"
},
{
"type": "null"
}
],
"default": null
},
"kind": {
"$ref": "#/$defs/Kind",
"default": "custom"
},
"on_timeout": {
"$ref": "#/$defs/OnTimeout",
"default": "deny"
},
"options": {
"type": "array",
"default": [
{
"id": "approve",
"label": "Approve",
"outcome": "approve",
"style": "primary"
},
{
"id": "deny",
"label": "Deny",
"outcome": "deny",
"style": "danger"
}
],
"items": {
"$ref": "#/$defs/Option"
}
},
"previews": {
"type": "array",
"default": [],
"items": {
"$ref": "#/$defs/Preview"
}
},
"risk": {
"$ref": "#/$defs/Risk",
"default": "low"
},
"run": {
"description": "Present while the desktop app runs the command (daemon-managed).",
"anyOf": [
{
"$ref": "#/$defs/RunClaim"
},
{
"type": "null"
}
]
},
"source": {
"$ref": "#/$defs/Source",
"default": {
"agent": null,
"branch": null,
"cwd": null,
"host": null,
"integration": null,
"repo": null,
"session": null
}
},
"status": {
"$ref": "#/$defs/Status",
"default": "pending"
},
"summary": {
"type": [
"string",
"null"
],
"default": null
},
"timeout": {
"description": "Optional positive duration, at most one year. Absent uses config; null/`none` disables expiry.",
"type": [
"string",
"null"
]
},
"title": {
"type": "string"
},
"tool": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": false,
"required": [
"title"
],
"$defs": {
"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",
"default": [],
"items": {
"type": "string"
}
},
"text": {
"description": "Typed answer; only when the question allows free text.",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
},
"Command": {
"type": "object",
"properties": {
"argv": {
"type": [
"array",
"null"
],
"default": null,
"items": {
"type": "string"
}
},
"cwd": {
"type": [
"string",
"null"
],
"default": null
},
"env_keys": {
"type": "array",
"default": [],
"items": {
"type": "string"
}
},
"shell": {
"type": [
"string",
"null"
],
"default": null
}
},
"additionalProperties": false
},
"Decision": {
"type": "object",
"properties": {
"content_hash": {
"type": "string"
},
"decided_at": {
"type": [
"integer",
"null"
],
"format": "uint64",
"default": null,
"minimum": 0
},
"decided_by": {
"type": [
"string",
"null"
],
"default": null
},
"feedback": {
"type": [
"string",
"null"
],
"default": null
},
"fields": {
"anyOf": [
{
"$ref": "#/$defs/DecisionFields"
},
{
"type": "null"
}
],
"default": null
},
"option": {
"type": "string"
},
"outcome": {
"anyOf": [
{
"$ref": "#/$defs/Outcome"
},
{
"type": "null"
}
],
"default": null
},
"rule_id": {
"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"
}
]
},
"scope": {
"type": [
"string",
"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"
}
}
}
},
"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": {
"attachments": {
"type": "array",
"items": {
"$ref": "#/$defs/EmailAttachment"
}
},
"bcc": {
"type": "array",
"items": {
"type": "string"
}
},
"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"
]
},
"cc": {
"type": "array",
"items": {
"type": "string"
}
},
"date": {
"description": "Date shown in the header, as the agent formats it (e.g. RFC 2822).",
"type": [
"string",
"null"
]
},
"from": {
"type": [
"string",
"null"
]
},
"in_reply_to": {
"description": "The message this draft replies to, shown collapsed under the body.",
"anyOf": [
{
"$ref": "#/$defs/EmailQuote"
},
{
"type": "null"
}
]
},
"reply_to": {
"type": [
"string",
"null"
]
},
"subject": {
"type": "string",
"default": ""
},
"to": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"EmailAttachment": {
"type": "object",
"properties": {
"blob": {
"description": "Uploaded blob hash (`POST /v1/blobs`) so the reviewer can open the file.",
"type": [
"string",
"null"
]
},
"mime": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0
}
},
"additionalProperties": false,
"required": [
"name"
]
},
"EmailQuote": {
"type": "object",
"properties": {
"body": {
"description": "Plain text of the earlier message (or a snippet of it).",
"type": "string",
"default": ""
},
"date": {
"type": [
"string",
"null"
]
},
"from": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
},
"Kind": {
"type": "string",
"enum": [
"command",
"edit",
"review",
"question",
"custom"
]
},
"OnTimeout": {
"type": "string",
"enum": [
"deny",
"approve",
"expire"
]
},
"Option": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"label": {
"type": "string"
},
"outcome": {
"$ref": "#/$defs/Outcome"
},
"style": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": false,
"required": [
"id",
"label",
"outcome"
]
},
"Outcome": {
"type": "string",
"enum": [
"approve",
"deny"
]
},
"Preview": {
"type": "object",
"properties": {
"after_blob": {
"type": [
"string",
"null"
]
},
"before_blob": {
"type": [
"string",
"null"
]
},
"blob": {
"type": [
"string",
"null"
]
},
"command": {
"anyOf": [
{
"$ref": "#/$defs/Command"
},
{
"type": "null"
}
]
},
"email": {
"anyOf": [
{
"$ref": "#/$defs/Email"
},
{
"type": "null"
}
]
},
"entry": {
"type": [
"string",
"null"
]
},
"files": {
"type": [
"array",
"null"
],
"items": {
"$ref": "#/$defs/PreviewFile"
}
},
"inline": {
"type": [
"string",
"null"
]
},
"lang": {
"type": [
"string",
"null"
]
},
"mime": {
"type": [
"string",
"null"
]
},
"name": {
"type": [
"string",
"null"
]
},
"size": {
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"$ref": "#/$defs/PreviewType"
}
},
"additionalProperties": false,
"required": [
"type"
]
},
"PreviewFile": {
"type": "object",
"properties": {
"blob": {
"type": "string"
},
"lang": {
"type": [
"string",
"null"
],
"default": null
},
"mime": {
"type": "string"
},
"path": {
"type": "string"
},
"size": {
"type": "integer",
"format": "uint64",
"minimum": 0
}
},
"additionalProperties": false,
"required": [
"path",
"blob",
"mime",
"size"
]
},
"PreviewType": {
"type": "string",
"enum": [
"text",
"markdown",
"code",
"diff",
"files",
"command",
"json",
"html",
"image",
"video",
"audio",
"file",
"pdf",
"email"
]
},
"Question": {
"description": "A question for the human; answered in `decision.fields.answers[id]`.",
"type": "object",
"properties": {
"allow_free_text": {
"description": "Allow a typed answer besides (or instead of) the options.",
"type": "boolean",
"default": false
},
"header": {
"description": "Short topic chip, e.g. \"Database\".",
"type": [
"string",
"null"
]
},
"id": {
"description": "Stable id, unique within the request.",
"type": "string"
},
"multi": {
"description": "Allow selecting several options.",
"type": "boolean",
"default": false
},
"options": {
"type": "array",
"default": [],
"items": {
"$ref": "#/$defs/QuestionOption"
}
},
"question": {
"description": "The question itself (markdown).",
"type": "string"
},
"recommended": {
"description": "Index of the suggested option.",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0
}
},
"additionalProperties": false,
"required": [
"id",
"question"
]
},
"QuestionOption": {
"description": "One selectable answer to a [`Question`].",
"type": "object",
"properties": {
"description": {
"description": "One-line explanation shown under the label.",
"type": [
"string",
"null"
]
},
"label": {
"description": "Answer text; unique within its question and returned in `selected`.",
"type": "string"
},
"preview": {
"description": "Markdown shown while the option is focused (code blocks allowed).",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false,
"required": [
"label"
]
},
"RequestInput": {
"description": "Request `input`. Only `kind: question` requests interpret `questions`;\nother keys (for example raw agent tool input) pass through unchanged.",
"type": "object",
"properties": {
"feedback": {
"description": "`optional` (default) or `required_on_deny`.",
"type": [
"string",
"null"
]
},
"fields": {
"description": "Generic form fields (`text`, `textarea`, `select`, `boolean`) for non-question requests.",
"type": [
"array",
"null"
],
"items": true
},
"questions": {
"description": "Structured questions (1..=10) for `kind: question`; answers arrive in `decision.fields.answers`.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/$defs/Question"
}
}
}
},
"Risk": {
"type": "string",
"enum": [
"low",
"medium",
"high"
]
},
"RunClaim": {
"description": "The handup desktop app on this computer is running the request's command\nright now. While the claim holds, the request stays pending but no other\ndecision, expiry, or timeout applies; cancelling it stops the run. Set and\ncleared only by the daemon.",
"type": "object",
"properties": {
"elevated": {
"description": "Running with administrator rights.",
"type": "boolean",
"default": false
},
"lease_until": {
"description": "Unix milliseconds after which an unreported run no longer holds the\nrequest (the app crashed or lost the daemon).",
"type": "integer",
"format": "uint64",
"minimum": 0
},
"started_at": {
"description": "Unix milliseconds when the run was claimed.",
"type": "integer",
"format": "uint64",
"minimum": 0
}
},
"additionalProperties": false,
"required": [
"started_at",
"lease_until"
]
},
"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": {
"duration_ms": {
"description": "Wall time from start to exit, in milliseconds.",
"type": "integer",
"format": "uint64",
"default": 0,
"minimum": 0
},
"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"
]
},
"exit_code": {
"description": "Process exit status; absent when it never started or a signal ended it.",
"type": [
"integer",
"null"
],
"format": "int32"
},
"stderr_tail": {
"description": "Last bytes of standard error (at most 64 KiB), credentials redacted.",
"type": "string",
"default": ""
},
"stdout_tail": {
"description": "Last bytes of standard output (at most 64 KiB), credentials redacted.",
"type": "string",
"default": ""
},
"truncated": {
"description": "Earlier output was dropped from either tail.",
"type": "boolean",
"default": false
}
},
"additionalProperties": false
},
"Source": {
"type": "object",
"properties": {
"agent": {
"type": [
"string",
"null"
],
"default": null
},
"branch": {
"type": [
"string",
"null"
],
"default": null
},
"cwd": {
"type": [
"string",
"null"
],
"default": null
},
"host": {
"type": [
"string",
"null"
],
"default": null
},
"integration": {
"description": "Server-verified integration token name; caller values are overwritten.",
"type": [
"string",
"null"
],
"default": null
},
"repo": {
"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"
]
}
},
"additionalProperties": false
},
"Status": {
"type": "string",
"enum": [
"pending",
"approved",
"denied",
"answered",
"expired",
"cancelled"
]
}
}
}