Wait for time and events
A weekly routine has a rhythm: the manager answers by Monday evening, contacts go to the BDRs on Wednesday. Motions models time in four ways.
The calendar
Section titled “The calendar”A motion’s calendar names the moments of its week. Each entry resolves to an instant when the batch opens, in the motion’s time zone:
calendar: manager_answers: { weekday: mon, at: "18:00" } # the next Monday 18:00 after the batch opens review: { in: 2d } # two days after it opens launch: { at: "2026-12-01T09:00:00-03:00" } # a fixed instantUse the keys as question deadlines and checkpoint times. Steps read them as ctx.calendar.manager_answers, in milliseconds since 1970.
Deadlines on questions
Section titled “Deadlines on questions”A queue’s deadline is a duration from when a question was asked, or a calendar key:
queues: owner_mismatch: { owner: ari, deadline: manager_answers, default: recommended }At the deadline, every unanswered question in the queue takes the queue’s default, and the batch moves on. See Ask questions.
Waiting inside a step
Section titled “Waiting inside a step”Some work finishes later: an enrichment provider that answers in a few minutes, a record someone is about to fill in. ctx.wait stops the step and runs it again after a while:
const job = await ctx.sources.fullenrich.enrich_bulk({ name: company.key, contacts });const result = await ctx.sources.fullenrich.enrich_bulk_get({ enrichment_id: job.enrichment_id });if (result.status === "pending") ctx.wait("10m", "waiting for FullEnrich");- The cell shows parked with the time it wakes, and the company sits in the parked lane until then.
- When it wakes, the step runs again from the top, and its CRM reads are fresh.
- A source call that answered before answers from the cache. A polling operation must not cache its “not yet” answers: FullEnrich’s poll doesn’t, and a custom source returns
cache: falsefor them. everyis a duration:30s,10m,4h,1d.
Checkpoints
Section titled “Checkpoints”A checkpoint step runs no code. It holds every company that reaches it until a condition is met, then lets them all through together:
- id: before_distribution kind: checkpoint title: Wait for Wednesday until: { at: distribution }until |
Releases when |
|---|---|
| nothing | every company still moving has reached it; parked companies don’t hold it up |
at: <key or duration> |
that time has passed, and no company is still on its way |
event: <name> |
that event has happened, and no company is still on its way |
manual: true |
an approver chooses Release in the batch’s More actions menu |
at and event can be combined; both must hold.
An approver can always choose Release early.
Events
Section titled “Events”An event is a named signal in a batch. A step emits one by returning it:
return { facts, events: [{ type: "gate_passed", data: { score } }] };Someone with the approver role can also send one from outside, through the API: POST /api/batches/<batch id>/events with { "name": "gate_passed" } and an API token. A checkpoint with until: { event: gate_passed } releases once it has happened.
Testing time
Section titled “Testing time”In tests, pass now and calendar to runStep to fix the clock. See Test a motion.
A batch can also run on a simulated clock that only moves when an approver advances it, so a week of deadlines plays out in minutes. It’s only for tenants in fixture mode on the test CRM, and can only be started through the API (clock: { start } when opening the batch). Once started, the batch screen has Advance the simulated clock.
Motions is built by Pruma. These docs describe what the platform does today; Limitations lists what it doesn't do yet. Open the app