Skip to content

Work with Claude Code

You don’t need to be a platform engineer to write motions. If you can describe the routine, read a diff, and run three commands, Claude Code, or any coding assistant, can do most of the typing. Motions is well suited to it: a motion is small, its rules are strict, and check and test tell the assistant quickly when it’s wrong.

Add a CLAUDE.md at the root of the tenant repository. Claude Code reads it at the start of every session. This one tells it the layout, the rules that aren’t obvious from the code, and what “done” means:

CLAUDE.md
# Órbita's motions
This repository is a Motions tenant. Motions runs these motions over batches of companies from our CRM; people answer the questions they ask and approve the CRM changes they propose. Docs: https://docs.pruma.tech/docs/
## Layout
- `tenant.yaml`, `crm.yaml`: the tenant and its CRM field map. Don't change `system` or `mode` in `crm.yaml` without asking.
- `motions/<id>/motion.yaml`: the steps and who decides. Reference: https://docs.pruma.tech/docs/reference/motion-yaml/
- `motions/<id>/steps/*.ts`: one file per step, `export default defineStep({ async run(company, ctx) { … } })` from `@motionskit/sdk`.
- `motions/<id>/rules.yaml`: values the steps read as `ctx.rules`. Put thresholds and lists here, not in code.
- `motions/<id>/tests/*.test.ts`: Vitest tests using `runStep` from `@motionskit/sdk/testing`.
- `fixtures/sources/*.json`: recorded source answers for tests and fixture mode.
- `sources/<id>/index.ts`: custom sources, `defineSource` from `@motionskit/sdk`.
## Rules for steps
- No `fetch`, no Node built-ins. Data from outside the CRM comes only through `ctx.sources`, and every operation a step calls must be listed under its `sources` in `motion.yaml`.
- CRM reads need the object in the step's `crm.read`; writes are proposals (`ctx.crm.*.create/update`, `associate`, `notes.*`) that need the action in `crm.propose` and a `changeset` step after them.
- A step returns `{ facts }`, `drop(reason)`, `hold(reason)`, or nothing. Reasons must be in the motion's `reasons`.
- When a case is unclear, ask with `ctx.ask({ type, prompt, options })` instead of guessing: 2 to 4 options, each a full sentence; options that end the company's run have `effect: "hold"` or `"drop"`. Every question type needs a queue in `motion.yaml`.
- Steps re-run from the top after an answer, a retry or a wait. Keep them deterministic: use `ctx.now()`, never the wall clock.
- Write prompts and options in the language of the people who answer them.
## Before saying something is done
1. `npx motions check` passes.
2. `npm run typecheck` passes.
3. `npx motions test` passes, with a test for each new path: each drop, each question, and the answered case.
4. New source calls have fixtures in `fixtures/sources/` for the tests.
Never push, never run `motions push`, and never put tokens or keys in any file. Open a pull request; a person reviews and merges it.

Adjust the language rule and anything specific to your client. Keep it short: it’s read every time.

The best requests read like a brief to a colleague. Say what the step decides, from what, and what a person should be asked:

Add a step after identity called fit. Using the CNPJ facts and the company’s segment field, drop companies with fewer than min_employees employees (put the number in rules.yaml, start at 50) with reason too_small. If the segment is empty, ask the account owner which segment it is, with the four segments in rules.yaml as options. Add tests for each case, with fixtures.

  1. Start from the motion. Ask it to read motion.yaml and the steps it’ll touch, and to say what it plans before writing.
  2. One step at a time. A step and its tests per request. Review, run, commit, then the next.
  3. Make it run the checks. npx motions check, npm run typecheck, npx motions test. Its CLAUDE.md says so, but ask for the output.
  4. Review the parts that matter. You don’t need to read every line. Read:
    • the motion.yaml diff: sources, crm.propose, caps, queues and owners;
    • each question’s prompt and options, as the person answering will see them;
    • the tests’ names, which should read like the cases you described.
  5. Try it on a draft. Push, open a batch on the draft with Try on a batch on a few companies, and look at the facts and questions in the drawer.

These pages are the reference. When the assistant is unsure about an API, give it the page:

  • “add it to the step’s sources”: it called an operation the step doesn’t list. The fix is in motion.yaml, not the step.
  • “no fixture matches”: a test called a source with a request no fixture covers. Ask it to add a fixture with the exact request from the message.
  • A test passes but the batch fails: compare the fixture’s data with what the provider really returns, using the operation’s type in the SDK. An assistant that invents fixtures can invent fields.
  • It wants to work around a rule: steps can’t fetch, can’t write to the CRM directly, and re-run from the top. Those are the platform’s guarantees; a design that fights them is the wrong design.

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