Hold a task, and clear a hold
Put a blocking or advisory hold on a task, and clear it — including who can clear a blocking hold, and how a worker can still get past one.
Sometimes a task should stop and wait for a person before it is worked any further — a decision to make, a fact to check, a mess to sort out. A hold is how you say so. This guide puts a hold on a task and later clears it, and explains the rule that will surprise you: the clear tools refuse a worker on a stopping hold, but a worker can still get past one by changing its kind.
You work with holds over the Model Context Protocol endpoint. If a hold's effect on what runs on its own is what you are after, read What moves a task without a person first; for the exhaustive surface, see the Holds reference.
Before you start
Setting and clearing a hold needs member on the space. See
Authentication. One optional step in
section 3, finding and removing a waiting inbound event and
checking whether one was closed, needs admin. You also need a task to hold — this
guide uses the example key OPS-42.
A worker running under a lease can set a hold too, on any task its lease reaches: by default the task it was leased for, and that task's parent, children and siblings (see Leases § What a lease can reach). That includes changing the kind of a hold already on the task. Everything below is written for you, an operator, over MCP.
1. Choose the kind of hold
A hold is one of two kinds, and the kind decides what it stops.
- A blocking hold stops the task. It suppresses dispatch and lease claims, and it discards any queued work for the task, so no pool picks the task up while the hold stands. A lease already running is left alone to finish. This is the default.
- An advisory hold stops nothing. It flags that a person is needed while the
pipeline keeps moving — it does not suppress dispatch, and it does not cancel
queued work. It retires on its own when the task moves to another stage on its
workflow. A move to another workflow with
tasks_transferkeeps it.
Use a blocking hold when the task must not be worked until you have dealt with it. Use an advisory hold when you want to mark "a human should look at this" without halting anything.
2. Set the hold
Set a hold with tasks_set_hold. Pass the task key and a reason — the reason
is required and cannot be empty. To choose the kind, pass kind; leave it out and
the hold is blocking.
// tasks_set_hold
{ "key": "OPS-42", "reason": "Waiting on the customer to confirm the address change.", "kind": "blocking" }Setting the same reason and kind on a task that already carries them does nothing — it is a no-op, and no timeline entry is written. Changing the reason or the kind overwrites the hold and records the change.
3. Clear the hold
Clear a hold with tasks_clear_hold. Pass the task key.
// tasks_clear_hold
{ "key": "OPS-42" }Clearing a task that is not held does nothing. When the clear does take, Cadence dispatches the task again at its current stage. That starts a pool only when all of these are true:
- an assignment rule at the task's current stage names the pool and applies to the task
- the pool is not archived
- the task has no unresolved dependency that blocks at its current stage and no unpassed required check at its stage
- no lease of that pool is still active on the task the rule leases (a rule with
target: parentleases the parent)
A pool whose work came from somewhere else is not restarted by a clear:
-
A pool you assigned the task to: assign the task to it again, with
tasks_assignandassignee: "pool:<id>"or the Assignee field. See Tasks § Assign a task. -
A scheduled rule's pool: it runs again at the rule's next due time. See Scheduled rules.
-
An inbound rule's pool: it runs again when a new matching event arrives, or when an event that was already waiting in the dispatch queue reaches its turn. A waiting event starts the pool with no new event and no person, but only if, when its turn comes, the task has no blocking hold, no unresolved dependency that blocks at its current stage and no unpassed required check. If one of those stops it, the event is closed without starting anything and is not tried again. An event whose turn came while the hold was still on has already been closed this way, so it does not run after the clear.
Cadence takes the waiting events for a task and pool one at a time: on each pass it closes or starts only the oldest. So while the hold is on, it closes them one by one, and if you clear the hold before it has closed them all, the next one starts the pool after the clear.
To stop the waiting events from running, remove each of them with
inbound_queue_removebefore you clear the hold. Listing and removing waiting events both need admin; if you are a member, ask a space admin to do it before you clear the hold. Find each event'sidwithinbound_queue_list space_key=OPS: they are thewaitingrows whosesubjectis the task and whosepool_idis the pool.If no event for the task and pool is still waiting, Cadence will not start that pool on the task again until a new matching event arrives. To run it sooner, assign the task to the pool yourself, with
tasks_assignandassignee: "pool:<id>"or the Assignee field. Assigning does not use up an event that is still waiting: the event waits while the lease you started is active, and once that lease ends it starts the pool again, with no person, if the task passes the same conditions. If you do not want that second run, remove the waiting event first. The lease you start waits,pending, while the pool is paused, the space is archived, or the pool, the space or the instance has no room, and starts once all of them allow it.To check whether an event was closed, an admin can run
inbound_queue_list space_key=OPS state=done; the event's delivery ininbound_deliveries_listis markedfailedwith the gate's reason. See Inbound § The dispatch queue and Inbound § When a dispatch mints nothing.
Clearing the hold lets the task move again, but it does not by itself transition the task to another stage; that stays a separate action. See Web interface § Holds on a task's page.
You can also clear a hold in the web interface: open the task in its workflow's board
view, and the task drawer shows the hold with a Clear hold button. A task's own page,
where a task link from MCP or the search window takes you, has no Clear hold
button. From there, click View on board and use the drawer. See
Web interface § Holds on a task's page. There is no /api/v1 route for holds — setting one is
over MCP, and clearing one is over MCP or the browser.
The rule that will surprise you: who can get past a blocking hold
tasks_clear_hold clears a blocking hold only for a human operator. A worker
or any other non-human principal that tries to clear one is refused:
only a human operator may clear a blocking holdThe refusal's code is clear_hold_requires_human. tasks_nudge and
tasks_dispatch_pool, which also clear a hold, refuse a worker on a blocking hold
too, each with its own code and message:
tasks_nudge:nudge_requires_human,only a human operator may nudge a task on a holdtasks_dispatch_pool:dispatch_pool_requires_human,only a human operator may dispatch a pool on a held task
Cadence itself never clears a blocking hold.
Do not nudge a task whose hold reason ends in (3 attempts). That hold means a
pool's leases were lost three times, and Cadence now treats the pool as blocked.
A nudge clears the hold and resets the count, but it does not reset the pool's
blocked state, so afterwards the third lost lease on that pool places no
hold and the task can sit idle with nothing pointing you to it. The pool stays
blocked even if another hold, such as a stage-loop hold, has since replaced the
(3 attempts) hold, so the hold a task carries now does not tell you. Clear the
hold with tasks_clear_hold or Clear hold instead. If you are not sure
whether a pool is blocked, or you have already nudged, call
tasks_dispatch_unblock with the task's key and no pool_id straight after
the nudge. It resets every pool that is still blocked and lists them in
cleared; an empty cleared means none was. A worker may nudge a task with an
advisory hold or no hold, so tell workers in their agent skills to do the same,
or check for idle tasks from time to time. See
Tasks § A nudge turns off the lost-lease hold,
which also says how to find and restart a task already left idle.
This does not make a blocking hold a guarantee that the task waits for you. A
worker whose lease reaches the task can call tasks_set_hold with
kind: "advisory". That replaces the blocking hold with an advisory one, which
the worker can then clear. Any worker whose lease reaches the task can also move
the task while it is held, including one started after the hold was placed. Nothing turns these tools off for a worker; whether it
uses them depends on what its worker version and agent skills tell it to do. For
what does make a task wait for a person, see
Web interface § Making a task wait for a person.
Every change shows on the task's timeline. Read it with activities_list. A
hold_set entry records each hold set or changed, with its kind and who did it
in by. A hold_cleared entry records a clear made with tasks_clear_hold or
tasks_dispatch_pool. A clear made with tasks_nudge is recorded instead as a
single nudged entry, which carries the cleared hold's reason in
cleared_reason. A transition entry records a move between stages, and a
transferred entry a move to another workflow. A blocking hold changed to advisory by a worker shows as a hold_set entry
with "kind": "advisory" and that worker's pool in by, as pool:<id>. A
change a person made shows their account as user:<id>.
An advisory hold carries no such rule. Because it stops nothing, any principal may clear it, including the worker that set it dropping the "needs a human" flag once it no longer applies.
Docs, and how a written record sits alongside the work
What a doc is in Cadence — a written record kept in a space next to its workflows and tasks — and how a doc is versioned, addressed, and searched.
Staff a stage with a pool
Create a worker version, pin a pool to it, and route a stage's work to the pool.