Motions by Pruma
Run your go-to-market routine as code.
A motion takes a list of companies through the steps your team does by hand every week. It looks each one up, asks the right person when something is unclear, and proposes CRM updates that an approver signs off before anything is written.
| Company | Lane | ||||||
|---|---|---|---|---|---|---|---|
| Metalúrgica Aurora | Moving | ||||||
| Laticínios Serra Verde | Moving | ||||||
| Pátio Logística | Waiting | ||||||
| Café Bandeirante | Dropped | ||||||
| Nuvem Clara | Moving | ||||||
| Ateliê Ipê | Moving | ||||||
| Vale do Aço Usinagem | Parked | ||||||
| Rio Doce Têxtil | Moving |
- Done
- Running
- Retrying
- Asked
- Failed
- Approval
- Stopped
- Pending
Write the routine once
A motion is a folder in git: a motion.yaml that lists the steps, and a short TypeScript file for each one. You test it on your laptop against recorded answers, then push it.
People decide the unclear cases
When a step can't tell on its own, it asks a closed question, with evidence and a recommended answer, to whoever owns that kind of decision. A deadline and a default keep the batch moving.
Nothing reaches the CRM unapproved
Steps only propose CRM changes. Motions seals them into a changeset that shows the before and after of every record, and nothing is written until an approver signs it off.
A motion is a folder in git
Section titled “A motion is a folder in git”motion.yaml lists the steps and who answers each kind of question. Each step is a TypeScript function that gets one company and returns facts, a question, or a change it proposes to the CRM.
This one checks who registered each company’s domain, asks when the registrant looks like a different company, and drafts a CRM note for an approver to sign off. It’s the motion the Quickstart runs.
title: Domain checkapprovers: [ana]reasons: [no_domain, unregistered]input: { list: first-batch }
steps: - id: domain title: Look up the domain run: steps/domain.ts sources: [rdap.lookup] - id: note title: Draft a CRM note run: steps/note.ts crm: { propose: [notes.create] } - id: write kind: changeset title: Write the notes approval: required
queues: domain_owner: { title: Who owns this domain?, owner: ana, deadline: 1d, default: hold }import { defineStep, drop } from "@motionskit/sdk";import { sameCompany } from "../lib/names.ts";
export default defineStep({ async run(company, ctx) { const domain = company.core.domain?.replace(/^www\./, ""); if (!domain) return drop("no_domain");
const rdap = await ctx.sources.rdap.lookup({ domain }); if (!rdap) return drop("unregistered");
if (rdap.registrant && !sameCompany(company.core.name, rdap.registrant)) { await ctx.ask({ type: "domain_owner", prompt: `${domain} is registered to ${rdap.registrant}, not ${company.core.name}. Is it the same company?`, options: [ { id: "same", text: "Same company: keep going" }, { id: "other", text: "Someone else's domain: drop it from this batch", effect: "drop" }, ], recommended: "same", evidence: [{ source: "rdap.lookup", shows: `registrant: ${rdap.registrant}` }], }); }
const since = rdap.registeredAt ? Number(rdap.registeredAt.slice(0, 4)) : null; const years = since === null ? null : ctx.now().getUTCFullYear() - since; console.log(`${domain} is registered to ${rdap.registrant ?? "an undisclosed owner"} since ${since ?? "an unknown year"}`); return { facts: { domain, registrant: rdap.registrant, since, years } }; },});import { defineStep } from "@motionskit/sdk";
type Domain = { domain: string; registrant: string | null; since: number | null; years: number | null };
export default defineStep({ async run(company, ctx) { const found = company.facts.domain as Domain; const young = Number(ctx.rules.young_years); const age = found.years === null ? "of unknown age" : found.years < young ? `young (${found.years} years)` : `${found.years} years old`; const body = `Domain check: ${found.domain} is registered to ${found.registrant ?? "an undisclosed owner"} and is ${age}.`;
// Nothing is written yet: this lands in the "write" changeset, and an approver decides. await ctx.crm.notes.create({ on: company.core.crm.id, body }); return { facts: { body } }; },});Start here
Section titled “Start here”Motions is built by Pruma. These docs describe what the platform does today; Limitations lists what it doesn't do yet. Open the app