How do I pause and resume a playbook run?
TL;DR: Ballet can park a playbook run as Paused (suspended) and continue it later on the same run ID. Editors can pause between steps, or a Code step can call metaphor.waitForInput to wait for a human or external signal. Continue from Studio, or wake via the API with a server-issued requestId.
Who this is for
Builders who need human approval, long waits, or a mid-run pause without losing progress.
What are the two pause modes?
In both cases:
- The run keeps the same
runId(History shows one row; the badge flips Running → Pausing → Paused → Running). - The sandbox is freed while parked so other runs keep processing.
suspendedis not a final status — you can Continue or Stop.
How do I pause from Studio?
- Start a run from the Play tab.
- Click Pause while the run is running.
- Ballet finishes the current step, then parks before the next one (
reason: operator_pause). - Click Continue when you are ready. The run resumes from the next step — no reply payload is injected into that step.
Use Stop on a paused run to cancel it.
How do I wait for approval inside a step?
In a Code step, checkpoint expensive work first, then park:
const decision = await metaphor.waitForInput({
prompt: 'Approve this invoice before posting?',
details: extractedFields, // shown in Studio while waiting
schema: {
kind: 'choice',
options: [
{ id: 'approve', label: 'Approve' },
{ id: 'reject', label: 'Reject' },
],
multiSelect: false,
},
});
if (decision?.id === 'reject') {
const result = { ok: false, __next: 'abort' };
} else {
const result = { ok: true, decision };
}
Rules:
- Do not busy-wait or poll Slack/email inside the step — that holds a sandbox.
- Always pass
detailsso reviewers (and notifiers) can see what to approve. - On wake,
waitForInputreturns thereplypayload (for example{ id: 'approve', label: 'Approve' }).
How does external data arrive on Continue?
For HITL parks, the wake payload is the reply body — not a new set of step input mappings.
- Studio Continue / choice → that choice becomes the return value of
waitForInput. - An external system (Slack button, webhook worker) sends the same payload via
POST /api/runs/:runId/reply. - Optionally pass
inputon wake to override the run'sflow.inputfor the continued execution.
Discover wake parameters from History → run detail (or GET /api/runs/:id) while status is Paused:
Past plays also show an API resume (curl) snippet with runId and requestId filled in.
What if I need Slack or email approval?
Slack and email are notifiers for the same park — they are not a second pause API. A notifier posts Approve/Reject, then calls the wake API with the parked requestId. Studio Continue uses that same path.
For the full HTTP contract, curl examples, and notifier pattern, see How do I wake a suspended run with reply or resume?.
