stackbone hitl

Every verb targets one installation: the local-dev install by default, any install with --agent <id>. list is cursor-paginated. approve and reject are destructive and require --yes.

Human-in-the-loop approvals for the targeted installation. This inbox is the return path for a parked durable run: when a workflow step calls requestApproval() (from @stackbone/sdk/workflow, see Workflows → human-in-the-loop), the run pauses and the pending approval surfaces here. The same inbox carries defineHook pauses and any tool call an agent parked for a human decision. Deciding an approval (approve or reject) resumes the parked run with your decision. An approval's runId field links back to the run you can follow with stackbone runs get.

Editing an approval payload is a Studio-only action. The CLI sends only the decision and an optional comment.

Command Purpose
stackbone hitl list List approvals. Filters: --status <pending|approved|rejected|timed_out|cancelled>, --limit/--cursor.
stackbone hitl get <id> Inspect one approval (topic, run, timeout, and its audit trail of past decisions).
stackbone hitl approve <id> Approve a pending approval (--reason), resuming the parked run. Requires --yes.
stackbone hitl reject <id> Reject a pending approval (--reason), resuming the parked run. Requires --yes.

The runtime mints an approval id (a UUID) when it creates the pause.

stackbone hitl list

The human-in-the-loop approvals inbox: the return path for requestApproval() (and defineHook) calls made from your workflows, plus any tool call an agent paused for a human decision. Each pending entry is a step waiting on a human decision.

Flag Type Description
--agent string Installation id to target. Defaults to the local-dev install.
--status string Filter by status: pending, approved, rejected, timed_out, cancelled.
--cursor string Opaque page cursor (nextCursor / prevCursor).
--limit string Maximum number of approvals to return (1-100).

Human mode prints one line per approval (id, status, topic, created-at), and No approvals found. when the page is empty.

JSON payload

{
  "schema_version": 1,
  "items": [
    {
      "id": "3f6b0a1e-7c4d-4b21-9e88-2a5f1c0d9a44",
      "status": "pending",
      "topic": "refund",
      "createdAt": "2026-06-01T10:00:00Z",
    },
  ],
  "nextCursor": "eyJ..." /* or null */,
  "prevCursor": null,
}

stackbone hitl get

Read one approval, including its audit trail of past decisions.

Flag Type Description
--agent string Installation id to target. Defaults to the local-dev install.

Human mode prints the record as labelled lines: id, status, topic, run, created, timeout, decided, and a decisions count. Those labels are the human view; the JSON keys are the wire names below.

JSON payload

{
  "schema_version": 1,
  "approval": {
    "id": "3f6b0a1e-7c4d-4b21-9e88-2a5f1c0d9a44",
    "status": "pending",
    "topic": "refund",
    "runId": "0a9d2c17-5f83-4d0e-8f61-9c2b7e4a1d33" /* or null */,
    "createdAt": "2026-06-01T10:00:00Z",
    "timeoutAt": "2026-06-02T10:00:00Z" /* or null */,
    "decidedAt": null,
    "fallback": "reject" /* the expiry policy, or null */,
    "decisions": [],
  },
}

The record also carries agentId, workspaceId, requestedByStepId, payload, schema, callbackUrl and metadata.

stackbone hitl approve

Decide a pending approval, resuming the durable workflow or agent turn that is parked on it. Destructive: requires --yes. --reason attaches an optional comment, recorded on the decision.

stackbone hitl approve 3f6b0a1e-7c4d-4b21-9e88-2a5f1c0d9a44 --yes
stackbone hitl approve 3f6b0a1e-7c4d-4b21-9e88-2a5f1c0d9a44 --yes --reason "Verified with the customer"
Flag Type Description
--agent string Installation id to target. Defaults to the local-dev install.
--reason string Note recorded with the decision.

Human mode prints Approved approval <id>.

JSON payload

{
  "schema_version": 1,
  "approval": { "id": "3f6b...", "status": "approved", "decidedAt": "2026-06-01T11:00:00Z" },
  "decision": {
    "id": "b2c8...",
    "approvalId": "3f6b...",
    "decision": "approve",
    "comment": "Verified with the customer" /* or null */,
    "actorEmail": "you@example.com" /* or null */,
    "decidedAt": "2026-06-01T11:00:00Z",
  },
}

The approval object is the same record hitl get returns, minus the decisions trail.

stackbone hitl reject

The mirror of approve: aborts the parked run's approval with a reject decision. Destructive: requires --yes. Same flags, same JSON payload, with decision set to reject.

stackbone hitl reject 3f6b0a1e-7c4d-4b21-9e88-2a5f1c0d9a44 --yes --reason "Out of policy"

Human mode prints Rejected approval <id>.

Timeouts

The runtime's timeout sweep closes a pending approval as timed_out once its timeoutAt deadline passes with no decision. The sweep records the expiry policy the step declared as a system decision, then applies it to whatever the approval was blocking. The policy is reject unless the step said otherwise (fallback on a workflow's requestApproval(), onTimeout on stackbone.approval.request()).

An approval created with onTimeout: 'ignore' carries no policy. Its fallback is null and the sweep skips it. It stays pending until a person decides it, whatever its timeoutAt says.

Exit codes: 0 ok · 3 no target (no project and no --agent, or stackbone dev is not running) · 4 not found (unknown approval, or a targeted box with no registered deployment) · 5 permission (approve/reject without --yes) · 1 generic. Only a pending approval can be decided, so approve and reject also exit 1 on an approval somebody already decided, and on one the timeout sweep already closed. The full table is in Shared conventions.

BUILT WITH ❤️ FROM CANADA AND SPAIN