Gates & approvals
A gate is a checkpoint step (kind: gate) inside a workflow phase. When the pipeline reaches one, the gate's subtask goes blocked and nothing downstream of it runs until the gate resolves. Gates are how a multi-hour autonomous pipeline stays reviewable: approve the storyboard before the scenes render, approve the deploy before it ships.
Gate kinds
The spec supports four gate_kind values; human gates are the fully shipped surface (portal buttons, Discord ping, REST endpoint):
| Kind | Resolves when |
|---|---|
human |
A person approves or rejects (portal or REST). |
webhook |
An external system calls back (resolved via the runtime's webhook-gate tooling). |
schedule |
A scheduled time arrives. |
pipeline_dep |
Another pipeline reaches a required state. |
The approval flow
- The runner reaches the gate; the subtask flips to
blockedand the project stops advancing along that path. - The project detail page raises an amber awaiting-approval banner naming the gate and its phase, with a Review & decide link to the gate's subtask page.
- If Discord notifications are configured, a ping goes out carrying a deep link to that portal page — the review itself happens in the portal, not in Discord.
- On the subtask page you get Approve and Reject buttons, each with an optional comment. If the gate reviews a producer step, the page shows that step's output right there (a gate with no explicit
reviewsfalls back to showing its first consumed sibling — that's how an edit-session's plan gate shows you the plan). - Once resolved, the project wakes and autodrive finishes the rest — no manual nudge needed.
Decision semantics
Only two decisions exist: approved and rejected. What a rejection does depends on the gate's position:
- Approve — the gate succeeds (recording a
human_decision.v1output) and the pipeline continues. - Reject a reviewing gate (the gate
reviewsa producer step) — the verdict was successfully collected, so the gate succeeds carrying the rejection; the review chain converts it into one producer rework (attempt_reason: review_failure) with your comment threaded into the retry brief, and the chain — including the gate — resets to pending so you re-decide on the rework. - Reject a standalone gate (no
reviews) — the gate fails with the decision recorded, the task fails, and the project pauses for a human. Rejection never abandons a project.
Resolving via REST
POST /v1/projects/{project_id}/subtasks/{subtask_id}/resolve-gate
{ "decision": "approved", "comment": "Storyboard looks right." }
decided_by is always derived from your verified session (the portal path sends portal:<huudis-user-id>); it cannot be spoofed from the body. Response:
{
"subtask_id": "…",
"step_slug": "approve_storyboard",
"decision": "approved",
"decided_by": "portal:usr_…",
"new_status": "succeeded",
"reviewed_producer": "storyboard",
"review_chain_resolved": true
}
Errors: 400 invalid decision (anything other than approved/rejected), 404 subtask not in the project, 409 when the subtask isn't a blocked human gate — not a gate, wrong gate kind, not blocked, or you lost a resolution race.
Not exposed in the SDKs yet — call the REST endpoint directly.
Edit-session plan gates
Edit sessions use a dedicated approve_plan gate with a wider decision set (approved, rejected, request_changes, edit_plan + a revised plan) and its own endpoint (POST …/edit-sessions/{task_id}/approve).
Next
- Portal → Projects — where the banner and buttons live.
- Artifact versioning & backtrack — what happens after an approval you regret.
- Autodrive — why the pipeline resumes on its own after you decide.