write-rules
Write Mendix rules — a special kind of microflow returning a Boolean or enumeration, callable only from a decision. Use when writing CREATE RULE, or deciding whether logic belongs in a rule or a micro
Files1
View on GitHubSKILL.md.claude/skills/mendix/write-rules/SKILL.md
GitHub<!-- skill-index: generated by scripts/skill-index.py; make check-skill-index -->
<!-- /skill-index -->
Find it fast
sed -n '<from>,<to>p' SKILL.md one section rather than reading the file;
./mxcli syntax <topic> answers how do I write this for a fraction of either.
| lines | section |
|---|---|
| 29-38 | When to Use This Skill |
| 39-52 | When to Use a Rule vs a Microflow |
| 53-67 | Key Differences from Microflows |
| 68-111 | Syntax |
| 112-129 | Reading and managing rules |
| 130-144 | What a rule may not contain |
| 145-155 | Validation checklist |
| 156-158 | Rules (LIST/DESCRIBE/CREATE [OR MODIFY]/DROP/MOVE RULE) |
Mendix Rule Skill
Guidance for writing Mendix rules in MDL. Mendix's own reference calls a rule "a special kind of microflow": it returns a Boolean or an enumeration, and it can only be used from a decision.
When to Use This Skill
- Writing
CREATE RULEstatements - Deciding whether logic belongs in a rule or a microflow
- Understanding what
mxcli checkrefuses in a rule body and why
The mirrors are write-microflows and write-nanoflows — a rule is the third flavour and shares their body syntax exactly.
When to Use a Rule vs a Microflow
| Scenario | Use |
|---|---|
| One condition, evaluated from several decisions | Rule |
| A named business condition the model should show by name | Rule |
| Choosing one of several enumerated outcomes from input | Rule |
| Anything that changes data | Microflow |
| Anything the user sees (page, message, download) | Microflow |
| Anything that talks to another system | Microflow |
Rule of thumb: a rule answers a question. The moment it needs to do something, it is a microflow.
Key Differences from Microflows
| Aspect | Microflow | Rule |
|---|---|---|
| Return type | Anything, including void | Boolean or enumeration — mandatory |
| Called from | Anywhere | A decision, and nowhere else |
| Changes data | Yes | No |
| Talks to the client | Yes | No |
| Integration | Yes | No |
| Module-role security | grant execute on microflow … |
None — a rule has no security to grant |
That last row is not an mxcli omission. A rule document stores no
AllowedModuleRoles, because a rule is never called on its own; it is reached
through the microflow that evaluates it, and that microflow's security applies.
Syntax
mdl 1;
create or modify rule Sales.Rule_IsSolvent ($pCustomer: Sales.Customer)
returns Boolean
folder 'Rules'
begin
return $pCustomer/Balance >= 0;
end;
An enumeration rule lets one decision fan out to several branches:
mdl 1;
create or modify rule Sales.Rule_Outcome ($pCustomer: Sales.Customer)
returns enum Sales.Outcome
begin
if $pCustomer/Balance >= 0 then
return Sales.Outcome.Approved;
else
return Sales.Outcome.Rejected;
end if;
end;
Calling one — the only place a rule may be called:
mdl 1;
create or modify microflow Sales.MF_Screen ($pCustomer: Sales.Customer)
begin
if Sales.Rule_IsSolvent(pCustomer = $pCustomer) then
return;
else
return;
end if;
end;
The argument names are the rule's parameter names, so
Rule_IsSolvent(pCustomer = $pCustomer) reads the same way a microflow call does.
Reading and managing rules
mdl 1;
list rules; -- `list rules` is the same statement
list rules in Sales;
describe rule Sales.Rule_IsSolvent; -- round-trippable MDL
drop rule Sales.Rule_IsSolvent;
move rule Sales.Rule_IsSolvent to folder 'Rules/Customer';
list microflows lists microflows only — not nanoflows, not workflows, and not
rules. Each doctype has its own listing.
list callers of Sales.Rule_IsSolvent lists the microflows whose decisions
evaluate it, and a microflow called from inside a rule's body is a normal
reference: it will not be reported as dead code.
What a rule may not contain
mxcli check refuses these before the build, with the same function exec uses,
so the two cannot disagree. Each was measured against mxbuild 11.13.0:
| Written in a rule | mxbuild says |
|---|---|
create / change / delete / commit / rollback |
CE0009 "This action is not supported in rules." |
show page, close page, show message, validation feedback, download |
CE0009 |
call web service |
CE0009 |
| A void, String, Integer … return type | CE0103 and CE0139 — the return type must be Boolean or an enumeration |
A missing returns clause is refused too. For a microflow, void is a legitimate
choice; for a rule it means the decision calling it has nothing to branch on.
Validation checklist
Before presenting a rule:
-
returns Booleanorreturns enum Module.Enumis present - The body only reads — no create/change/delete/commit/rollback
- Nothing in the body touches the client or another system
- Every path returns a value of the declared type
- The caller is a decision:
if Module.Rule_Name(Param = $Value) then -
mxcli check script.mdl -p app.mpr --referencespasses
Rules (LIST/DESCRIBE/CREATE [OR MODIFY]/DROP/MOVE RULE)
Mendix's "special kind of microflow" — returns Boolean or an enumeration, callable only from a decision. Handled as a third flow flavour beside microflows and nanoflows: its own semantic type, its own listing (list microflows stays microflow-only), the shared microflowBody, flow builder and describer. The document is the ten properties a Studio Pro rule stores, pinned against two reference rules (ako/TestApp, 11.13.0) — no AllowedModuleRoles (a rule is not independently callable, so there is no grant execute on rule) and no ReturnType despite gen declaring one beside MicroflowReturnType. Two keys only a reference document catches, both invisible to mx check: ExportLevel (Studio Pro writes "Hidden" on every rule) and Flows (written as the bare marker even when empty — a MandatoryLists entry). Rules are catalog objects and their bodies are walked for references, which together stop a microflow called only from a rule reading as dead. The body restrictions are refused at check time by the same function exec calls, each measured: create/change/delete/commit/rollback and client or web-service activities are CE0009, a non-Boolean/enum return is CE0103 + CE0139. Authoring is modelsdk-only; legacy refuses.