Presentations
asgeirtj/system_prompts_leaks
Help choose a presentation's audience, story, outline, or use of evidence and visuals.
Validate MDL with mxcli check before presenting or executing it, including reference resolution against a project.
$ npx skills add mendixlabs/mxcli --skill check-syntax -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install mendixlabs/mxcli check-syntax --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/mendixlabs/mxcli.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/mendix/check-syntax .claude/skills/check-syntax && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "check-syntax" agent skill from https://github.com/mendixlabs/mxcli/tree/main/.claude/skills/mendix/check-syntax into .claude/skills/check-syntax/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "check-syntax", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/mendixlabs/mxcli/tree/main/.claude/skills/mendix/check-syntaxType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add mendixlabs/mxcli --skill check-syntax -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install mendixlabs/mxcli check-syntax --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/mendixlabs/mxcli.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/mendix/check-syntax .agents/skills/check-syntax && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "check-syntax" agent skill from https://github.com/mendixlabs/mxcli/tree/main/.claude/skills/mendix/check-syntax into .agents/skills/check-syntax/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "check-syntax", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add mendixlabs/mxcli --skill check-syntax -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install mendixlabs/mxcli check-syntax --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/mendixlabs/mxcli.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/mendix/check-syntax .cursor/skills/check-syntax && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "check-syntax" agent skill from https://github.com/mendixlabs/mxcli/tree/main/.claude/skills/mendix/check-syntax into .cursor/skills/check-syntax/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "check-syntax", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/mendixlabs/mxcli.git --path .claude/skills/mendix/check-syntax--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add mendixlabs/mxcli --skill check-syntax -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install mendixlabs/mxcli check-syntax --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/mendixlabs/mxcli.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/mendix/check-syntax .gemini/skills/check-syntax && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "check-syntax" agent skill from https://github.com/mendixlabs/mxcli/tree/main/.claude/skills/mendix/check-syntax into .gemini/skills/check-syntax/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "check-syntax", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install mendixlabs/mxcli check-syntaxInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add mendixlabs/mxcli --skill check-syntax -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/mendixlabs/mxcli.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/mendix/check-syntax .github/skills/check-syntax && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "check-syntax" agent skill from https://github.com/mendixlabs/mxcli/tree/main/.claude/skills/mendix/check-syntax into .github/skills/check-syntax/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "check-syntax", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add mendixlabs/mxcli --skill check-syntax -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install mendixlabs/mxcli check-syntax --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/mendixlabs/mxcli.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/mendix/check-syntax .opencode/skills/check-syntax && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "check-syntax" agent skill from https://github.com/mendixlabs/mxcli/tree/main/.claude/skills/mendix/check-syntax into .opencode/skills/check-syntax/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "check-syntax", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
check-syntaxValidate MDL with mxcli check before presenting or executing it, including reference resolution against a project.
Check Syntax is an agent skill from mendixlabs/mxcli. Validate MDL with mxcli check before presenting or executing it, including reference resolution against a project. Use ALWAYS before showing MDL to a user, running mxcli exec, or committing a .mdl file — exec refuses exactly what check rejects.
Its SKILL.md is about 8.4k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
The repository describes itself as: Mendix cli tool, a headless way to work with Mendix projects. Enables Mendix projects for use with 3rd party agentic coding tools like Claude Code and Copilot. Includes a… The licence is Apache-2.0.
6 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit a924d11. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
gitFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use git, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Check Syntax loads about 8.4k tokens when it runs. Until then it costs about 65 tokens; SKILL.md has 4,244 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from mendixlabs/mxcli at commit a924d11, republished under its Apache-2.0 licence (© mendixlabs). 4,244 words, ~8,397 tokens.
.claude/skills/check-syntax/SKILL.md (or your agent's skills folder).This skill ensures MDL scripts are validated before presenting them to users or executing them.
ALWAYS use this skill before:
mxcli execexec refuses what check rejectsmxcli exec runs the same semantic checks before writing anything. A script whose
checks report an error is not executed at all — nothing is written — because
exec applies statements one at a time and cannot roll back, so a known-bad
script would leave the model partly updated. Warnings are printed and do not stop
the run.
mxcli exec script.mdl -p app.mpr # checked, then applied
mxcli exec script.mdl -p app.mpr --no-check # applied regardlessThis does not replace running check yourself. check is faster, needs no
write connection, and reports the warnings worth reading before you commit to a
run. What the gate guarantees is narrower and still valuable: a script that slips
past you cannot half-apply.
It also does not mean the script is correct. mxcli check validates MDL syntax
and mxcli's own rules; it does not validate the Mendix model. Run
mx check (or mxcli docker check -p app.mpr) after applying a slice.
-p resolves references — there is no separate opt-inmxcli check script.mdl alone checks syntax and the semantic rules that need no
model. Pass -p and it also resolves every reference — modules, entities,
pages, microflows and icons — against that project. It reaches inside stored
documents where a name can only be answered there: an ALTER PAGE … SET is
dry-run against the page it edits, so a widget the page does not have, or a
property the stored widget does not declare, is reported here rather than
stopping the script partway through exec.
mxcli check script.mdl # syntax + model-free rules
mxcli check script.mdl -p app.mpr # ... and every reference resolved--references is implied by -p and is kept only so existing scripts keep
working. It used to be required, which meant mxcli check script.mdl -p app.mpr
printed an unqualified Check passed! having resolved nothing — a misspelled
icon or entity sailed through a command that had been handed the project. A run
without a project now says what it did not check, so a pass is never read as
more than it is.
An excluded document's dangling references are warnings, not errors. Mendix
does not validate excluded documents (Feedback v4.0.2 ships an excluded page bound
to nanoflows it lacks, and the project checks at 0 errors), so check and exec
print them as Reference warning lines for excluded microflows, nanoflows, rules,
and pages/snippets exec will write excluded (@excluded, or a stored namesake that
is). A missing data-source flow is a warning only when the bindings inside it are
qualified (Attribute: Module.Entity.Attr, {1} = Module.Entity.Attr,
Visible: Module.Entity.Attr in (…)) — the form describe writes there. The
widgets inside bind against the entity that flow returns, so with the flow missing
a bare binding cannot be resolved; it is refused, naming the widget, because on
11.13.0 a bare attribute reference left a project mx could not load. A missing
entity still blocks.
A plain create of a document the project already carries is a check error,
not something to discover at exec time:
statement 4: association already exists in project: Sales.Order_Customer — use CREATE OR MODIFY to update itThe reason it belongs in check is that exec stops at the first one having
already written everything before it. A script whose fourth statement
conflicts leaves three statements' worth of changes in the project and no
fourth — so "run it and see" is not a free experiment. check reports every
conflict in the script before anything is written.
Three spellings say "fine if it already exists", and none is reported:
create or modify, create or replace, and create <kind> if not exists <name>
(which leaves the stored element untouched rather than rewriting it; every
create that names one element takes it, e.g. create page if not exists M.P …
— mxcli syntax create-if-not-exists). create module M;
is never reported either — it is a no-op when the module exists, which is what
lets it open every script.
The types covered are the ones exec refuses: entity, enumeration, constant,
association, microflow, nanoflow, rule, page, snippet, layout, java action,
javascript action, workflow, menu, task queue, scheduled event, regular
expression, database connection, REST client, OData client and service, message
definition collection, the integration/agent document types, module roles,
user roles, demo users and configurations. Annotations are the one known gap
(they have no name to compare). If you find another that exec refuses and
check does not, that is a bug of exactly the shape
TestEveryCreateStmtIsClassified and TestEveryCreateDocTypeIsProjectChecked
exist to prevent.
Separately, check reports MDL-DUPNAME for a name Mendix will not let two
elements share — a nanoflow named like a microflow, a page and a snippet, an
enumeration and an entity, or the same kind spelled in another case
(M.act_login next to M.ACT_Login, CE0122). It covers rename … to and
move … to Module onto a taken name too. mxcli help MDL-DUPNAME has the
table.
create or modify entity is on the list above — it is never a conflict, because
"fine if it already exists" is exactly what it says. What it does not say is
that it rebuilds the entity from the statement, so every member the statement
omits is deleted. Slice an app into ordered scripts and that becomes a real
hazard: an attribute added by a later alter entity — a calculated one whose
microflow does not exist until then is the usual reason — is gone the moment the
earlier script is re-run on its own. Script order is load-bearing, even though
each script is individually idempotent.
check now says so before anything is written, as MDL087:
⚠ applying this script to the project removes 1 member(s) from entity
ServiceCore.LithoSystem that it does not restate: OpenRequestCount
— anything still bound to them (widgets, microflows) fails the build with CE1613
at ServiceCore.LithoSystem
→ … or add them incrementally with 'alter entity ServiceCore.LithoSystem
add attribute <name>: <type>;' in this script; if they are meant to go,
say so with 'alter entity … drop attribute <name>;'exec prints the same list — but as it applies the statement, by which point the
attribute is gone. Left unreported entirely, the loss surfaces slices later as
CE1613 on whatever still binds it, naming the page, not the script that
removed the attribute (ako/mxcli#562).
Two properties of the rule are worth knowing, because they are what keep it from becoming noise you learn to scroll past:
alter entity … add attribute loses nothing and is silent. So the combined slices check
clean and slice 01 alone does not, which is precisely the difference that bit.drop attribute, rename attribute
and drop entity say what they do. Only a member the project holds, that the
script neither restates nor asks to remove, is a warning.It is a warning: "modify to this shape" is a legitimate intent and check
still exits 0. The defect was the silence, not the behaviour. It also covers the
members that are not attributes — the four audit system fields and an omitted
extends — because those drop the same way.
exec would refusecreate or modify microflow|nanoflow on a stored flow is a patch. A change the
patch cannot make (inside a loop body or error handler, a redrawn connector, a
return added) is refused by exec under mdl 1;, and rebuilt (IDs, merges and
curves lost) without the header. With -p, check runs the same verdict exec
and diff run: an MDL-V1-REBUILD error quoting exec's refusal under mdl 1,
the MDL-V1-REBUILD warning without the header, and MDL090 for an alter microflow|nanoflow exec would refuse. Use alter for the change, or drop and
create the flow. A flow an earlier statement of the script touches is not
predicted (exec sees that statement's result), and fmt --upgrade --header -p
keeps the header off a file it would make refuse (ako/mxcli#876).
A /** … */ doc comment documents the statement right after it, and only a
create of something with documentation stores one. Above a drop, grant,
revoke, set, alter or create module it is ignored, so MDL089 warns
and names the next statement that could have taken it. In drop-then-create, put
the comment between the drop and the create (ako/mxcli#877).
Resolution does not stop at the entity. An attribute named in a create or
change activity is looked up on that entity and its generalizations, so a
typo is reported by check rather than by mxbuild as CE1613 "The selected attribute '…' no longer exists" a whole build later:
Sales.ACT_Close: Sales.Order has no member "IsArchived" (in change $Order)
— it has OrderNo, Status — mxbuild reports this as CE1613 …This needs the target's entity to be known, and that is the boundary worth understanding rather than assuming:
| the object comes from | checked? |
|---|---|
a create Module.Entity (…) | yes — the entity is in the statement |
| a microflow/nanoflow parameter | yes |
retrieve $L from Module.Entity | yes |
retrieve $L from $Obj/Module.Assoc | yes, when $Obj is itself typed |
a loop over any of those | yes — the iterator inherits the element type |
anything else (send rest request, response: file as $Doc, …) | no |
Widget positions are resolved too:
database from Module.Entity source — every step
is followed, so a bare name must be an attribute of the entity it lands on and
a Module.Name step must be an association or an entity;ContentParams / CaptionParams) rooted in a
variable. That one needs no project and fires under a bare
mxcli check, because the answer is in the statement.The template-parameter rule is narrower than "no $ roots", and the difference
is measured rather than reasoned — the writer strips one prefix on one branch:
{1} = … | |
|---|---|
OrderNo | fine |
Order_Customer/Name | fine — association hop, then attribute |
$currentObject/Order_Customer/Name | fine — the prefix is stripped |
$currentObject/OrderNo | CE1613 |
$Order/Name | CE1613 |
Note the two-segment form: Assoc/Attr, not the XPath Assoc/Entity/Attr,
which mxbuild also rejects.
Two more things reach mxbuild as CE0117 "Error(s) in expression" and are now
reported by check:
CHANGE $Order (Status = Closed) is E013. Write 'Closed'
(a literal), $Closed (a variable), or Module.Enum.Value (an enumeration).
Scoped to the whole value of a create/change member: a bare name nested
in a list-operation predicate is legal — FILTER($L, Status = 'Open')
resolves Status against the item under test — and is not reported.LOG … WITH ({1} = $Order/Qty) is E009. Measured on 11.13.0: Integer, Decimal, Boolean,
DateTime and an object each fail; a String attribute is clean; and
toString(…) around any of them is clean. So wrap the non-String ones —
the writer is fine, Mendix simply does not coerce here.create association Order_Probe …) — MDL074, no
project needed. exec always refused it; check now does too, which matters
because exec is not transactional: the statements before the failure are
already applied, and re-running hits "already exists" on them.RETURNS void AS $x — MDL075, no project needed. An alias names the
variable a flow returns, so it cannot be paired with void; mxcli used to
believe the alias and write return $x into a flow with no such variable
(CE0109). Write RETURNS void, or give the alias the type it holds.empty($List) — E014. empty is a Mendix keyword, not a function, so
the parser stops at the (. Write $List = empty or length($List) = 0.One thing to know about hint ordering: the reference check runs before expression checking and exits on its first error, so an unrelated mistake anywhere in a file hides every expression hint in it. If you expect an E0xx and see none, fix the reference errors first and re-run.
A variable this cannot type is left unchecked, never guessed at — a false
"no such member" would block a script that builds cleanly. Two more things are
deliberately not reported: a qualified member (Module.Assoc), which exec
already refuses when it cannot be an attribute, and any member on an entity the
script itself creates or whose attribute the script adds earlier — the
add-the-column-then-populate-it shape stays valid.
Before writing any MDL, verify these requirements:
mdl 1;A script without the header is checked and executed as mdl 0, the alpha language,
where some statements mean something else. Write mdl 1; as the first line of every
new script. To edit a headerless one, upgrade it first (mxcli fmt --upgrade --header -p app.mpr -w script.mdl) — never mix the two in one file; see choose-edit-mode.
Supported in Microflows:
declare $Var type = value; (primitives only: String/Integer/Long/Decimal/Boolean/DateTime/Enumeration)$entity = create Module.Entity (...); / retrieve $entity from ... first; (objects — never declare an object; that fails CE0053/CE0038 and is flagged MDL043)$list = create list of Module.Entity; (lists — never declare a list; that fails CE0053/CE0038 and is flagged MDL040)set $Var = expression;$Var = create Module.Entity (attr = value);change $entity (attr = value);commit $entity [without events] [refresh]; (omitted = with events, Mendix's default)delete $entity;retrieve $Var from Module.Entity [where condition];$Result = call microflow Module.Name (Param = $value); (NOT set $Result = ...)$Result = call nanoflow Module.Name (Param = $value);show page Module.PageName (Param = $value);close page;validation feedback $entity/attribute message 'message';log info|warning|error [node 'name'] 'message';if condition then ... [else ...] end if;loop $item in $list begin ... end loop;return $value;on error continue|rollback|[without rollback] begin handler end error;Now Supported (previously not):
rollback $entity [refresh]; - Reverts uncommitted changesretrieve ... first - Returns a single entity; limit n [offset n] returns a list (a bare limit 1 is the object only without the mdl 1; header, and warns MDL-V1-LIMIT1)boolean without default - Auto-defaults to falsebuttonstyle: warning and buttonstyle: info - Now parse correctlycaption, label, title, text, content, format, range, source, check, etc. all work unquotedNOT Supported (will cause errors):
set $var = call microflow ... - Use $var = call microflow ... (no SET)while ... end while - Use loop with listscase ... when 'String' ... - Case values are bare enum identifiers, never quoted or qualified; case ... when Value then ... end case; itself IS supported (enum splits only), and takes no else (MDL008) and no AS aliasTRY ... CATCH - Use on error blocksbreak / continue - Not implementedcommit message 'text' - Not in current grammar (session command only)Best practice: Always quote all identifiers (entity names, attribute names, parameter names) with double quotes. This escapes every MDL parser keyword conflict — quotes are stripped automatically by the parser.
Caveat — quoting does not exempt platform-reserved member names. Quoting only escapes MDL parser keywords. Names the Mendix platform reserves for entity members are still rejected after the quotes are stripped:
Type(CE7247, MDL021), the system audit attributesCreatedDate/ChangedDate/Owner/ChangedBy(MDL020 — use theAutoCreatedDate/AutoChangedDate/AutoOwner/AutoChangedBypseudo-types instead), plus the CE7247 word list (ID,GUID,CurrentUser, Java keywords, …)."Type": Stringstill fails MDL021 — rename to a non-reserved name (e.g.ResourceType,TypeValue). "Always safe to quote" covers parser keywords, not these.The parse error tells you which case you are in.
'Title' is a keyword in MDL. Quote it to use it as a namemeans quoting works and nothing has to be renamed;'Type' is reserved by MENDIX itself, not just by MDLmeans it does not. Measured across the keywords mxcli hints on: 38 are rescued by quoting, 3 (Type,Default,Owner) are not.Third case — OQL keywords, where quoting works but in a different grammar.
Year,Month,Quarter,Week,Day,Hourand the other date-part words are neither MDL parser keywords nor platform-reserved: they are accepted everywhere and build at 0 errors. They bite only inside a view entity's OQL, and only unquoted (CE0174). OQL takes double-quoted identifiers just like SQL —s."Month",from Module."Year" as s— and mxcli writes them through unchanged, so the usual fix is a quote in the OQL, not a rename. mxcli reports MDL071 as a warning atCREATE/ALTERso the name is still cheap to change if you would rather rename. Applies to the entity name as well as its attributes.The exception is an alias, and that limit is OQL's own: it takes a bare identifier there for any name —
as "Total", reserved nowhere, is CE0174 too (MDL072). A view entity's attribute name is also its select alias, so a view column cannot be calledMonthat all — that one needs a rename, not a quote.Exception — never quote
$-prefixed variable/parameter references. The quote rule is for bare names (entities, attributes, associations, declared parameter names). Variable and parameter references in expressions and widget bindings stay unquoted:datasource: $X,params: ( $X: MES."Order" ),$currentObject. Quoting them ("$X") breaks resolution ("parameter … references '$X' but no such parameter is declared").Enumeration values: no
=. Value names may be quoted like any identifier, but the caption follows as a quoted string — there is no equals sign:create enumeration Mod.E ("Grade1" 'Grade 1', Grade2 'Grade 2');(orGrade1 caption 'Grade 1'). Writing"Grade1" = 'Grade 1'fails withmismatched input '='— the=is the problem, not the quotes.
mdl 1;
create persistent entity Module."Customer" (
"Name": string(200),
"status": string(50),
"create": datetime
);Both "Name" and `Name` syntax are supported. Prefer double quotes for consistency.
Run mxcli syntax keywords for the full list of 320+ reserved keywords.
Always run these checks:
# Step 1: Syntax check (no project needed)
./bin/mxcli check script.mdl
# Step 2: reference validation (needs project)
# Validates microflow bodies, entity/enum references, and widget tree references
# (datasource microflow/nanoflow/entity, action page/microflow, snippet refs)
./bin/mxcli check script.mdl -p app.mpr --references| Error Message | Likely Cause | Fix |
|---|---|---|
mismatched input 'set' after call microflow | SET not valid with CALL | Use $var = call microflow ... |
mismatched input 'create' | Structural keyword as identifier | Use "create" (quoted) or rename |
no viable alternative at input | Unsupported syntax | Check supported statements list |
microflow not found | Referenced before created | Move microflow definition earlier or check spelling |
page not found | Page doesn't exist | Check qualified name with --references |
entity not found | Typo or wrong module | Use fully qualified name |
Both are decidable from the MDL alone and now fail check, because a project
found them the hard way — four scripts passed check with 0 errors, executed
cleanly, and mx check then reported them:
| Rule | MxBuild | What it catches |
|---|---|---|
MDL-SEC20 | CE0156 | CREATE USER ROLE with no System module role — nobody holding it can sign in or read System entities. Add System.User. Warning by default, error when the script enables security (see below). |
MDL-PAGE20 | CE5601 | A page with parameters and a Url where the URL has no segment for a parameter. Mendix binds each parameter from the URL, so the page cannot be opened by link. |
MDL-SEC20's severity follows the security level, because the underlying error
does. Measured on Mendix 11.13: the same role is CE0156 at security level
Prototype and no error at all at level Off, where roles are stored but not
validated. A blank project ships Off. So the rule warns by default and is an
error only when the script itself contains ALTER APP SECURITY LEVEL set to
something other than Off — at which point the author has said which world they
are in.
MDL-PAGE20 accepts an attribute path in the segment (url: 'p006/{Customer/Name}'),
which is the usual shape — it matches the segment's leading name, not the whole
segment.
MDL-SEC21 (CE0106)With a project (check -p), check simulates the script's creates, drops,
grants and revokes and reports a microflow or nanoflow the script leaves with
no allowed role while something that needs one names it. MxBuild's error:
CE0106 "At least one allowed role must be selected if the microflow is used from navigation, a page, a nanoflow or a published service."
Measured on Mendix 11.14: a page button or data source, a snippet, a navigation or menu-document item, or a nanoflow call needs a role (even from an unused snippet, menu document or nanoflow). A published REST operation does not, nor a microflow called only from another microflow, nor an excluded page. It is an error at security level Prototype or Production and a warning at Off, where MxBuild does not check it.
The usual cause is drop + create in separate runs: a create in a later run
is a new flow, and a new flow in a module that has its own module roles gets no
access. Within one run, and with create or modify, the stored roles are kept.
Fix: grant execute on microflow M.Flow to M.Role; in the same script, or rebuild
with create or modify microflow instead of dropping. Only what the script
changes is reported — a project that already has CE0106 does not fail an
unrelated script; mxcli docker check shows those.
check is still necessary, not sufficient. Run mx check (or
mxcli docker check) after every exec; these two rules narrow the gap, they do
not close it.
Read the skill files:
cat .claude/skills/write-microflows/SKILL.md
cat .claude/skills/overview-pages/SKILL.mdCheck help for specific syntax:
./bin/mxcli syntax microflow
./bin/mxcli syntax page
./bin/mxcli syntax entitySave to a file:
cat > script.mdl << 'EOF'
-- Your MDL here
EOFRun syntax check:
./bin/mxcli check script.mdlIf errors, check specific syntax:
./bin/mxcli syntax keywords # Reserved words
./bin/mxcli syntax microflow # microflow syntaxRun reference check (with project):
./bin/mxcli check script.mdl -p app.mpr --referencesExecute only after all checks pass:
./bin/mxcli exec script.mdl -p app.mprIMPORTANT: Script execution is atomic per statement, NOT per script.
When a script fails on statement N, statements 1 through N-1 have already been committed:
Statement 1: create module ✓ (committed)
Statement 2: create entity ✓ (committed)
Statement 3: create association ✓ (committed)
Statement 4: create view entity ✗ (failed - execution stops here)
Statement 5: create page (never executed)Recommendations:
create or modify to make scripts idempotentgit status — a settled script changes nothingOrganize scripts in dependency order:
mdl 1;
-- ============================================
-- PHASE 1: Enumerations (no dependencies)
-- ============================================
create enumeration Module.Status (
Active 'Active',
Inactive 'Inactive'
);
-- ============================================
-- PHASE 2: Entities (depend on enumerations)
-- ============================================
create persistent entity Module.Customer (
Name: string(200),
status: Module.Status
);
create persistent entity Module.Order (
OrderNumber: string(20)
);
-- ============================================
-- PHASE 3: Associations (depend on entities)
-- ============================================
create association Module.Order_Customer
from Module.Order to Module.Customer
type reference;
-- ============================================
-- PHASE 4: Microflows (depend on entities)
-- ============================================
create microflow Module.ACT_Save ($Customer: Module.Customer)
returns boolean as $success
begin
declare $success boolean = false;
commit $Customer;
set $success = true;
return $success;
end;
-- ============================================
-- PHASE 5: Pages (depend on microflows)
-- ============================================
create page Module.Customer_Edit (
Title: 'Edit Customer',
Layout: Atlas_Core.PopupLayout,
Params: ( $Customer: Module.Customer )
) {
dataview dvCustomer (DataSource: $Customer) {
textbox txtName (Label: 'Name', Attribute: Name)
-- Can reference the microflow created in Phase 4
actionbutton btnSave (Caption: 'Save', Action: call microflow Module.ACT_Save(Customer = $Customer))
}
};A reference to a document that hasn't been created yet in the script:
Error: snippet not found: MyModule.NavMenu
Error: page not found: MyModule.Customer_NewEditScript execution is sequential — each CREATE commits immediately. Forward references
fail because the target doesn't exist in the database at the moment the referencing
document is created.
Fix options:
CREATE earlier in the script (simplest fix)CREATE OR MODIFY — which preserves the
original UUID so all existing bindings remain valid
(see Resolve Forward References)Declaration order that avoids most forward references:
enumerations → entities → snippets (placeholder) → pages → snippets (fill-in) → microflows → navigationNever use
CREATE OR REPLACEfor the placeholder fill-in step. OR REPLACE deletes the placeholder and creates a new document with a different UUID, silently breaking every page or snippet that references it.
The word X is either:
The parser expected something different:
end if, end loop, etc.Extra tokens found:
When Studio Pro's embedded MCP server is available alongside mxcli (i.e. you are
not using mxcli's own --mcp backend, but mxcli writes the .mpr directly while
Studio Pro is open), use Studio Pro MCP only for reading and verification. Never
author with ped_create_document / ped_update_document — mxcli owns the .mpr, and
mixing authoring tools corrupts intent and diverges UUIDs.
| Task | Tool |
|---|---|
| Create/modify entities, microflows, pages, nanoflows, nav | mxcli MDL |
| Verify CE errors after exec | ped_check_errors |
| Inspect widget tree / microflow body detail | ped_read_document |
| Check if a document exists before creating | ped_find_document |
| Full model validation | ./mxcli docker check |
This is the opposite of what you might expect. mxcli writes directly to the .mpr
SQLite file, but Studio Pro serves ped_* reads from its in-memory model, which
does not hot-reload when an external process changes the file. So after mxcli exec:
ped_read_document / ped_check_errors will show the stale pre-exec model until
Studio Pro re-scans — call refresh_project first (or reload the project in the UI).<project>.mpr.lock is beside the .mpr; exec --force
(or MXCLI_ALLOW_STUDIO_PRO_OPEN=1) overrides it, e.g. for a lock left by a crash.Safest practice: don't keep the same project open-and-saving in Studio Pro while
mxcli writes it. Either close (or don't save in) Studio Pro during MDL authoring, or
refresh_project after every mxcli exec before verifying. If you need both writing
and a live Studio Pro, use mxcli's --mcp backend (which authors through Studio
Pro) instead of writing the file directly.
After ./mxcli exec script.mdl -p app.mpr succeeds:
refresh_project (Studio Pro MCP) so the in-memory model reflects the new file.ped_check_errors on each created/modified document for CE errors. The argument
depends on the Studio Pro release — read the tool's input schema:{"documents": [{"documentType": "Microflows$Microflow", "documentName": "Mod.Name"}]}{"filters": {"documentType": "Microflows$Microflow", "documentNamePrefix": "Mod.Name"}}.
11.15 silently ignores documents and checks the whole project. documentNamePrefix
is a prefix (Mod.Order also matches Mod.OrderLine), so read the 'Mod.Name' (Type):
header above each problem. More than 100 problems come in pages: repeat the same
filters with pagination: {checkId, offset, size} using the Check ID from the first answer.Do not treat an empty
DESCRIBEas proof of a dropped construct.DESCRIBErenders from the MDL emitter, which does not yet render every activity/widget type (e.g. Java/JavaScript action calls, exclusive splits, some nanoflow buttons). The construct may be present in the model even whenDESCRIBEomits it. To tell a real write-drop from an emitter gap, confirm withped_read_document(the live model) or./mxcli docker check— only flag an engine bug once the live model is also missing it.
© mendixlabs, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/mendix/check-syntax of mendixlabs/mxcli.
Open the folder on GitHubat commit a924d11
Check Syntax next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Check Syntax this skillmendixlabs/mxcli | 128 | — | ~8.4k | Automated safety check: Pass | Apache-2.0 | |
| Presentationsasgeirtj/system_prompts_leaks | 69k | — | ~858 | Automated safety check: Pass | CC0-1.0 | |
| Executealirezarezvani/claude-skills | 28k | — | ~831 | Automated safety check: Pass | MIT | |
| PresentationRightNow-AI/openfang | 18k | — | ~829 | Automated safety check: Pass | Apache-2.0 | |
| Executive Presentation Builderamd/gaia | 1.6k | — | ~1.7k | Automated safety check: Pass | MIT | |
| AI Presenter VideoNousResearch/hermes-agent | 252k | — | ~2.3k | Automated safety check: Pass | MIT |
asgeirtj/system_prompts_leaks
Help choose a presentation's audience, story, outline, or use of evidence and visuals.
alirezarezvani/claude-skills
/cs:execute <decision — Generate a 90-day execution plan with weekly milestones, DRIs, and check-in cadence from an approved decision.
RightNow-AI/openfang
Presentation expert for slide structure, storytelling, visual design, and audience engagement
amd/gaia
Turns a source document such as a README or spec into an executive slide deck as one self-contained HTML file that prints to PDF, one slide per page.
NousResearch/hermes-agent
Produces a presenter-led video from a topic or script plus one authorized presenter image, with captions, lip-sync checks and acceptance reports.
code-yeongyu/oh-my-openagent
Executes a written ulw-plan work plan with Boulder state, evidence ledger, worktree discipline, and parallel subagents.
mendixlabs/mxcli
Push OData query options into the SQL of a Mendix resource served by a read microflow, so $filter, $orderby, $top, $skip, $count and the key lookup reach the database instead of being silently…
mendixlabs/mxcli
Chart a Mendix app with Vega-Lite through a pluggable widget that takes the specification and the data as separate properties, so the model emits rows and never assembles a chart payload.
mendixlabs/mxcli
Author Mendix AI agent documents in MDL — Model, Knowledge Base, Consumed MCP Service and Agent, with variables, tools and multi-line prompts.
mendixlabs/mxcli
Run set-based INSERT, UPDATE and DELETE against Mendix entities through OQL statements, which the runtime supports and Studio Pro cannot author.
mendixlabs/mxcli
Stand up an HTTP endpoint you control instead of a live third-party API, and point the Mendix app at it — Prism from an OpenAPI contract, a constant swap, or a forward proxy.
mendixlabs/mxcli
Call external REST APIs from Mendix — the three approaches (inline REST CALL, consumed REST client document, generated from OpenAPI) and how to choose.
Validate MDL with mxcli check before presenting or executing it, including reference resolution against a project. Check Syntax is an agent skill from mendixlabs/mxcli. Validate MDL with mxcli check before presenting or executing it, including reference resolution against a project.
Run `npx skills add mendixlabs/mxcli --skill check-syntax -a claude-code`. Or copy the skill folder (.claude/skills/mendix/check-syntax in mendixlabs/mxcli) into .claude/skills/check-syntax in your project. Claude Code loads it when a task matches its description.
Run `npx skills add mendixlabs/mxcli --skill check-syntax -a codex`. Or copy the skill folder (.claude/skills/mendix/check-syntax in mendixlabs/mxcli) into .agents/skills/check-syntax in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add mendixlabs/mxcli --skill check-syntax -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/check-syntax, .gemini/skills/check-syntax, .github/skills/check-syntax and .opencode/skills/check-syntax in your project.
Going by SKILL.md and its folder, Check Syntax needs the command-line tools its instructions call (git). Our summary lists: Docker.
SKILL.md contains no URLs. Its commands use git, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Check Syntax is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 8.4k tokens (SKILL.md is roughly 34k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Check Syntax: Presentations (asgeirtj/system_prompts_leaks, 69k stars), Execute (alirezarezvani/claude-skills, 28k stars), Presentation (RightNow-AI/openfang, 18k stars) and Executive Presentation Builder (amd/gaia, 1.6k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
mendixlabs (a GitHub organization) maintains it in mendixlabs/mxcli, which has 128 GitHub stars. The repository holds 75 skills in this directory. The repository was last updated on October 7, 2026.
Source: mendixlabs/mxcli on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.