Skip to content

Ask questions

A good motion decides the clear cases on its own and asks about the rest. This page is about writing those questions well. For what happens to them in a batch, see Questions and queues.

ctx.ask stops the company until someone answers, then runs the step again and returns the chosen option’s id:

const candidates = match.candidates.slice(0, 3);
const pick = await ctx.ask({
type: "identity",
prompt: `${candidates.length} registrations match ${company.core.name}. Which one is it?`,
options: [
...candidates.map((c) => ({ id: c.cnpj_root, text: `${c.razao_social} (${c.cnpj_root})` })),
{ id: "none", text: "None of these: hold it", effect: "hold" },
],
evidence: [{ source: "cnpj.match", shows: match.reason }],
});
const chosen = candidates.find((c) => c.cnpj_root === pick)!;

Write the step as if the answer were already there. On the first run ctx.ask stops the step; on the run after the answer it returns at once, and the step carries on from the same place.

Field
type The kind of question, lowercase with underscores. It names the queue the question goes to, and a company gets at most one question of each type per step.
prompt The question, in full. The person may not know the motion; say what you found and what you need.
options Two to four, each with an id, the text on the button, and an effect: continue (the default), hold or drop.
recommended The option you’d pick. It’s highlighted, and a queue whose default is recommended picks it at the deadline.
evidence What you found, as { source, shows, ref? }: which source, what it showed, and a link or id.
risk low (the default) or high, shown to the person answering.
suggest Your own answer; see Suggest an answer.

Return questions instead of asking them, and the company carries on while the question waits on the side. Use this for things a person should know about but that shouldn’t stop the batch:

return {
facts: { owner: owner.name },
questions: [
{
type: "owner_mismatch",
prompt: `${company.core.name} belongs to ${owner.name} in HubSpot, but the open deal is ${dealOwner.name}'s.`,
options: [
{ id: "ok", text: "Fine as it is" },
{ id: "hold", text: "Hold it until they sort it out", effect: "hold" },
],
recommended: "ok",
},
],
};

Add blocking: true to a returned question to make the company wait for it, as ctx.ask does. When it’s answered, the step runs again and ctx.answer("owner_mismatch") returns the answer.

In motion.yaml, give every question type a queue with an owner, a deadline, and a default:

queues:
identity: { title: Which registration is it?, owner: ari, deadline: 4h, default: hold }
owner_mismatch: { owner: ari, deadline: manager_answers, default: recommended }
  • owner: the handle who answers. The motion’s approvers can always answer too.
  • deadline: a duration from when it was asked (30m, 4h, 2d) or a key in the motion’s calendar, such as manager_answers for “Monday 18:00”.
  • default: what happens at the deadline: hold, drop, continue, or recommended. Without a deadline, the question waits until someone answers.

A type with no queue goes to the first approver and defaults to hold, without a deadline.

When the step has a good guess, suggest it with a risk:

const pick = await ctx.ask({
type: "identity",
prompt: `...`,
options,
suggest: { answer: best.cnpj_root, risk: best.score > 0.95 ? "low" : "high", note: `matched on name and city, score ${best.score}` },
});
  • risk: "low": the question is answered by the step on the spot, recorded as such, and ctx.ask returns the suggestion without waiting. A person can still change it later, until the company is sealed in a changeset.
  • risk: "high": the question waits, with your suggestion shown. One click accepts it, and approvers can accept every pending suggestion in a batch at once.

answer can be one of the options, or $hold, $drop or $continue to suggest an effect without a specific option.

A batch step returns results per company, and each can carry questions. Read answers with the company’s key: ctx.answer("duplicate", row.key). See Batch steps.

  • Say what you found, then what you need. “aurora.com.br is registered to GRUPO TRANSVIA LTDA, not Metalúrgica Aurora. Is it the same company?” beats “Domain mismatch?”.
  • Make the options complete sentences, with the consequence: “Someone else’s domain: drop it from this batch”.
  • Show the evidence, with links when you have them. The person shouldn’t have to search for what your step already found.
  • Write in your team’s language. Prompts and options are plain strings; V360’s are in Portuguese.
  • Ask once. If two steps would ask the same thing, ask in the first and pass the answer on as a fact.

Motions is built by Pruma. These docs describe what the platform does today; Limitations lists what it doesn't do yet. Open the app