Request schema
Generated by handup schema request (make docs) intodocs/public/schema/request.schema.json. Raw file: /schema/request.schema.json.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
callback_url | string | null | Terminal-event destination; requires the daemon callbacks.allowlist. | |
content_hash | string | ||
created_at | integer | ||
decision | Decision | null | ||
dedupe_key | string | null | ||
expires_at | integer | null | ||
id | string | ||
input | RequestInput | null | ||
kind | Kind | ||
on_timeout | OnTimeout | ||
options | Option[] | ||
previews | Preview[] | ||
risk | Risk | ||
run | RunClaim | null | Present while the desktop app runs the command (daemon-managed). | |
source | Source | ||
status | Status | ||
summary | string | null | ||
timeout | string | null | Optional positive duration, at most one year. Absent uses config; null/`none` disables expiry. | |
title | string | yes | |
tool | string | null |
Definitions
Answer
The human's answer to one question.
| Field | Type | Required |
|---|---|---|
selected | string[] | |
text | string | null |
Command
| Field | Type | Required |
|---|---|---|
argv | string[] | null | |
cwd | string | null | |
env_keys | string[] | |
shell | string | null |
Decision
| Field | Type | Required |
|---|---|---|
content_hash | string | yes |
decided_at | integer | null | |
decided_by | string | null | |
feedback | string | null | |
fields | DecisionFields | null | |
option | string | yes |
outcome | Outcome | null | |
rule_id | string | null | |
run_result | RunResult | null | |
scope | string | 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 |
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 |
|---|---|---|
attachments | EmailAttachment[] | |
bcc | string[] | |
body | string | |
body_html | string | null | |
cc | string[] | |
date | string | null | |
from | string | null | |
in_reply_to | EmailQuote | null | |
reply_to | string | null | |
subject | string | |
to | string[] |
EmailAttachment
| Field | Type | Required |
|---|---|---|
blob | string | null | |
mime | string | null | |
name | string | yes |
size | integer | null |
EmailQuote
| Field | Type | Required |
|---|---|---|
body | string | |
date | string | null | |
from | string | null |
Kind
"command" | "edit" | "review" | "question" | "custom"
OnTimeout
"deny" | "approve" | "expire"
Option
| Field | Type | Required |
|---|---|---|
id | string | yes |
label | string | yes |
outcome | Outcome | yes |
style | string | null |
Outcome
"approve" | "deny"
Preview
| Field | Type | Required |
|---|---|---|
after_blob | string | null | |
before_blob | string | null | |
blob | string | null | |
command | Command | null | |
email | Email | null | |
entry | string | null | |
files | PreviewFile[] | null | |
inline | string | null | |
lang | string | null | |
mime | string | null | |
name | string | null | |
size | integer | null | |
title | string | null | |
type | PreviewType | yes |
PreviewFile
| Field | Type | Required |
|---|---|---|
blob | string | yes |
lang | string | null | |
mime | string | yes |
path | string | yes |
size | integer | yes |
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]`.
| Field | Type | Required |
|---|---|---|
allow_free_text | boolean | |
header | string | null | |
id | string | yes |
multi | boolean | |
options | QuestionOption[] | |
question | string | yes |
recommended | integer | null |
QuestionOption
One selectable answer to a [`Question`].
| Field | Type | Required |
|---|---|---|
description | string | null | |
label | string | yes |
preview | string | null |
RequestInput
Request `input`. Only `kind: question` requests interpret `questions`; other keys (for example raw agent tool input) pass through unchanged.
| Field | Type | Required |
|---|---|---|
feedback | string | null | |
fields | any[] | null | |
questions | Question[] | 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.
| Field | Type | Required |
|---|---|---|
elevated | boolean | |
lease_until | integer | yes |
started_at | integer | yes |
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 |
|---|---|---|
duration_ms | integer | |
elevated | boolean | |
error | string | null | |
exit_code | integer | null | |
stderr_tail | string | |
stdout_tail | string | |
truncated | boolean |
Source
| Field | Type | Required |
|---|---|---|
agent | string | null | |
branch | string | null | |
cwd | string | null | |
host | string | null | |
integration | string | null | |
repo | string | null | |
session | string | null | |
session_title | string | null |
Status
"pending" | "approved" | "denied" | "answered" | "expired" | "cancelled"
JSON Schema
{ "$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" ] } }}