mxcli Language Poster mxcli · the language postermxcliMDLthe language posterLet AI agents read and change Mendix apps — in a SQL-like language, from the command line.RELEASE0.25.0 · nightly recommendedLANGUAGEmdl 1; — frozen betaPROJECTSMendix 9–11 · MPR v1 & v2LICENSEApache 2.0SOURCEgithub.com/mendixlabs/mxcliDOCSwww.mxcli.orgALSO IN MDLworkflowsnanoflowsrulesREST & ODataJSON mappingsbusiness eventsexternal SQLJava & JS actionsAI agents · 11.9+scheduled eventstask queuestranslationssettingsthemesmxcli syntax <topic> · mxcli help <command> · mxcli lint --list-rules — the tool is the referenceZoom into any panel · ▶ Present for the tourALPHA — back up the .mpr; close Studio Pro before writing01 Agents write MDL. mxcli does the rest.01 · THE IDEAAgents write MDL. mxcli does the rest.MDL is a SQL-like language for the Mendix model: 5–10× denser than model JSON, so one script is one model turn.mxcli's deterministic layer parses, checks and writes the .mpr — no Studio Pro needed.AI agentClaude Code · Cursor · CopilotWindsurf · OpenCode · …orders.mdlmdl 1;create entity …create microflow …create page …grant …mxcliparse (ANTLR4)check refs + idiomsexecute per statementwrite canonical BSONapp.mprv1 single SQLite filev2 + mprcontents/writeexecBSONheadless — no Studio Prodeterministic writesre-exec writes nothing8 agent toolsGo · single binarylist · describe · search · selectcontext from the catalog: 81 SQLite tablesmxbuild + runtimerun --local · hot reload ≈1 sor docker · Portable Appfeedback: check errors · lint · test results · page checks · screenshots02 Start with the bootstrap prompt02 · GET STARTEDStart with the bootstrap prompt1Open an empty repo in Claude Code — web, desktop or iPad2Paste the bootstrap prompt from www.mxcli.org3The agent installs mxcli, unpacks its skills and hands over to bootstrap-appthe prompt, abridgedThis is an empty repo. Provision it as a Mendixapp developed with mxcli.1. Make sure mxcli is available … # curl the release2. ./mxcli init --sync-skills3. Read .ai-context/skills/bootstrap-app/SKILL.md and follow it end to end.full text: www.mxcli.org/tools/bootstrap-prompt.htmlbootstrap-app then …interviews you about the appmxcli new + init --tool claudewrites README & FINDINGSrecords the plan in docs/braincommits, boots, checks HTTP 200takes the lint + report baselineprompt stays phone-sized — the steps ship in mxcliOR BY HANDcurl -fsSL -o mxcli …/releases/download/nightly/mxcli-linux-amd64 && mxcli new MyApp --version 11.8.003 mxcli init03 · SET UP A PROJECTmxcli initmxcli init --tool claude --tool cursor # or --all-tools · add-tool windsurffilesMyApp/├─ app.mpr├─ AGENTS.md # universal agent guide├─ CLAUDE.md # gates & conventions├─ .claude/│ ├─ skills/mendix/ # 74 skills│ ├─ commands/mendix/ # 10 slash commands│ └─ lint-rules/*.star # Starlark rules├─ .ai-context/skills/ # skills for any tool└─ .devcontainer/ # mxbuild · JDK 21 · DockerAfter an mxcli upgrade: mxcli init --sync-skills. Extra packs: mxcliskill list | add | upgrade.8 AGENT TOOLSClaude CodeCLAUDE.md · .claude/Cursor.cursorrulesGitHub Copilotcopilot-instructions.mdWindsurf.windsurfrulesContinue.continue/config.jsonAider.aider.conf.ymlOpenCodeopencode.jsonMistral Vibe.vibe/04 The CLI map04 · COMMANDSThe CLI mapCOREinitnewexeccheckdifffmtsyntaxEXPLOREdescribestructuresearchcallerscalleesrefsimpactcontextQUALITYlintreporttestevalRUN & DEBUGrundockerplaywrightdebugoqllogMODEL UPKEEPrenamelayoutfixmarketplacewidgetthemeAGENTS & EDITORSskillbrainlspmcptuiserveglobal flagsmxcli -p app.mpr -c "list entities in Sales" --json # -p optional with one .mpr here05 Read before you write05 · EXPLORERead before you writeMDLmdl 1;list modules;list entities in Sales;describe entity Sales.Customer;describe Sales.ACT_Order_Submit; -- type auto-detecteddescribe structure depth 1;search 'validation';CLImxcli -c "describe structure depth 1"mxcli describe -f mermaid Sales.Customermxcli context Sales.ACT_Order_Submit -d 2OR STAY IN THE REPLconnect local 'app.mpr'; list pages; status; exitlist is canonical in mdl 1. show … stillparses, flagged MDL-DEPR002.DESCRIBE -F MERMAID →CustomerName: StringEmail: StringIsActive: BoolOrderNumber: AutoNrDate: DateTime1 *Order_CustomerAlso -f json and -f elk. mxcli serve and the VS Codeextension render the same views for review.06 Query the model like a database06 · CATALOGQuery the model like a databaseMDLrefresh catalog full;select Name, ActivityCount from CATALOG.MICROFLOWS where ActivityCount > 10 order by ActivityCount desc;select SourceName, RefKind, TargetName from CATALOG.REFS where TargetName = 'Sales.Customer';list callers of Sales.ACT_Order_Submit transitive;list impact of Sales.Customer;81CATALOG.* tables & views in a localSQLite index — list catalog tables;ENTITIESATTRIBUTESMICROFLOWSACTIVITIESPAGESWIDGETSREFSPERMISSIONSWORKFLOWSSTRINGSSOURCEGRAPH_*CLI twins: mxcli callers · callees · refs · impact · search · graph-reportLIST CALLERS OF SALES.ACT_ORDER_SUBMIT TRANSITIVE →ACT_Order_SubmitSUB_Order_ValidateOrder_Edit (page)WF_Approval (workflow)07 Entities07 · DOMAIN MODELEntitiesMDLcreate persistent entity Sales.Customer ( Name: string(100) not null, Email: string(200) not null unique, IsActive: boolean default true, Credit: decimal) index (Email);create persistent entity Sales.Photo extends System.Image (Caption: string(200));alter entity Sales.Customer add attribute Phone: string(50);alter entity Sales.Customer rename attribute Phone to PhoneNumber;create or modify rebuilds the element anddrops attributes you leave out. Prefer ifnot exists / alter for re-runnablescripts.view entities: create view entity … asselect … (10.18+)CustomerNameString (100)EmailString (200)IsActiveBooleanCreditDecimalindex: Email · unique: Email08 Types & relations08 · DOMAIN MODELTypes & relationsMDLcreate association Sales.Order_Customer from Sales.Order to Sales.Customer type reference on delete cascade;create enumeration Sales.OrderStatus ( Draft 'Draft', Confirmed 'Confirmed', Shipped 'Shipped');alter enumeration Sales.OrderStatus add value Delivered caption 'Delivered';ATTRIBUTE TYPESstring(n)string(unlimited)integerlongdecimalbooleandatetimebinaryhashedstringautonumberModule.EnumAUDIT PSEUDO-TYPESautoownerautochangedbyautocreateddateautochangeddateMODIFIERSnot nulluniquedefault <v>calculated by M.MFASSOCIATION OPTIONStype reference | referencesetowner default | bothstorage column | tableon delete cascade | restrict | set nullfrom = the entity that owns the reference (the FK side).09 Microflows09 · LOGICMicroflowsMDLcreate microflow Sales.ACT_Order_Submit ( $Order: Sales.Order) returns booleanbegin retrieve $Lines from $Order/Sales.Line_Order; declare $count integer = 0; loop $line in $Lines begin change $line (IsConfirmed = true); set $count = $count + 1; end loop; if $count > 0 then commit $Order; log info 'Order submitted'; end if; return $count > 0;end;ACTIVITIESretrievecreatechangecommitdeleterollbackcall microflowcall java actioncall rest serviceshow pageclose pageshow messagevalidation feedbacklogFIND · FILTER · countloopwhilecaseon error rollbackRULES MXCLI CHECK ENFORCES; after every statementretrieve … first = one objectno return inside a loopno nested list ops (MDL-LISTOP02)no empty list as a loop sourceretrieveloop $linechangesetcommitthe same microflow in Studio Pro10 Pages & widgets10 · UIPages & widgetsMDLcreate page Sales.Customer_Edit ( params: ($Customer: Sales.Customer), title: 'Edit Customer', layout: Atlas_Core.PopupLayout) { dataview dvCustomer (datasource: $Customer) { textbox txtName (label: 'Name', attribute: Name) combobox cbStatus (label: 'Status', attribute: Status) footer { actionbutton btnSave (caption: 'Save', action: save changes, buttonstyle: primary) actionbutton btnCancel (caption: 'Cancel', action: cancel changes) } }};alter page Sales.Customer_Edit { set (caption: 'Save & Close') on btnSave; drop txtUnused;};WIDGETSdataviewdatagridgallerylistviewlayoutgridcontainertextboxtextareadatepickercomboboxcheckboxdynamictextimagesnippetcallactionbutton+ pluggableEdit Customer×NameJansen B.V.StatusConfirmed ▾CancelSave11 Roles, access & navigation11 · SECURITYRoles, access & navigationMDLcreate module role Sales.Manager description 'Full access';grant execute on microflow Sales.ACT_Order_Submit to Sales.Manager;grant view on page Sales.Customer_Edit to Sales.Manager, Sales.User;grant create, delete, read *, write * on entity Sales.Customer to Sales.Manager;grant read * on entity Sales.Order to Sales.User where [Status = 'Open'];create user role Manager (ModuleRoles: (Sales.Manager));alter app security (SecurityLevel: production);create or modify navigation Responsive home page Sales.Home_Web { menu item 'Orders' (OnClick: show page Sales.Order_Overview) };SecurityLevel production makes missingaccess a build error.user roleManagermodule role Sales.ManagerentityCRUD · XPath rowsmicroflowexecutepageview12 Run, test & debug12 · RUNTIMERun, test & debugshellmxcli run --local --watch --detach # warm loop: mxbuild --serve + runtimemxcli run wait --ready && mxcli run statusmxcli test tests/ --local # .test.mdl microflow testsmxcli playwright check /p/orders # text verdict per pagemxcli debug break Sales.ACT_Order_Submit # microflow debuggermxcli oql "select Name from Sales.Customer"mxcli docker up · reload # Portable App Distribution pathorders.test.mdl/** * @test Multiply * @expect $result = 50 */$result = call microflow Sales.Multiply(A = 10, B = 5);/≈1 shot reload_model~2 swarm test run:8080app · :8090 adminrun --hub → https://<name>.mxcli.orgbrowser preview from a cloud session · Linux builds13 The gates13 · QUALITYThe gateschecksyntax + references~2 scheapest first — stop at the first red.claude/lint-rules/*.starRULE_ID = "CUSTOM001"CATEGORY = "naming"SEVERITY = "warning"def check(): out = [] for e in entities(): if not is_pascal_case(e.name): out.append(violation( message = e.name + ' not PascalCase')) return outRULE FAMILIESCONVSECARCHQUALDESIGNMPRlint -f text | json | sarif · --list-rulesexecapply · twice = no writeslint~50 rules~3 sreport6 categories · 0–100docker checkmxbuild / mx check~25 stestmicroflow tests~2 s warmrunplaywright check14 74 skills, routed by description14 · SKILLS74 skills, routed by descriptionEach SKILL.md's description tells the agent when to load it.LOGICwrite-microflowswrite-nanoflowswrite-rulespatterns-crudpatterns-data-processingvalidation-microflowscheatsheet-variablescheatsheet-errorsresolve-forward-referencesxpath-constraintsregular-expressionsjava-actionsjava-dependenciesjavascript-actionsDOMAIN MODELgenerate-domain-modelmdl-entitiessystem-modulewrite-oql-queriesUIcreate-pagealter-pageoverview-pagesmaster-detail-pageswrite-layoutsfragmentscustom-widgetscreate-custom-widgetbulk-widget-updatesatlas-designtheme-stylingmigrate-design-prototypeSECURITY & SETTINGSmanage-securitymanage-navigationproject-settingstranslationsorganize-projectINTEGRATIONrest-clientrest-call-from-jsonjson-structures-and-mappingsodata-data-sharingdatabase-connectionsbrowse-integrationscatalog-searchmock-rest-apisconnect-rapidminer-graphdownload-marketplace-contentWORKFLOWS & AGENTSwrite-workflowsagentsscheduled-events-and-queuesbusiness-eventsRUN · TEST · DEBUGrun-localrun-appdocker-workflowruntime-admin-apianalyze-runtimetest-apptest-microflowsverify-with-oqldemo-datadebug-microflowsdebug-bsonSKILL PACKSmxcli skill addmendix-bulk-oql-dmlmendix-odata-pushdownmendix-vega-chartsPROCESS & QUALITYbootstrap-appchoose-edit-modecheck-syntaxlive-edit-with-studio-proproject-braingraph-analysisassess-qualitywrite-lint-rulesupgrade-mendix-versionrecord-narrated-demoteamserver-gitassess-migrationmigrate-oracle-formsmigrate-k2-nintexCLAUDE SLASH COMMANDS/mendix:explore/mendix:create-entity/mendix:create-crud/mendix:check-script/mendix:diff-script/mendix:diff-local/mendix:lint/mendix:test/mendix:validate-project/mendix:refresh-catalog“add an edit page for Customer”→ loads create-page, then writes MDL15 Describe, use, check15 · CUSTOM WIDGETSDescribe, use, check1 describe2 use3 checkshellmxcli widget describe \ htmlelement -p app.mpr# every .mpk in widgets/# becomes usable + a skillmxcli widget init -p app.mprProperties, types, defaults, editorrules, child slots — and a ready-to-runMDL example.describe widget type htmlelement;MDLhtmlelement frame ( tagName: 'div', tagContentMode: 'container') { attribute a1 ( attributeName: 'data-testid') tagcontentcontainer body { dynamictext t (Content: 'Hi') }}Name a widget by the last part of itsid; repeated items are blocks, notvalues.MDL-WIDGET25unknown widget + suggestionsMDL-WIDGET26unknown containerMDL-WIDGET27list given as a valueMDL-WIDGET30child has nowhere to gomxcli check script.mdl -p app.mprBuild your own: the create-custom-widget skill scaffolds a React/TypeScript widget and packs the .mpk.CE0463 after a widget upgrade?mxcli fix widgets -p app.mprresyncs definitions, keeps MPR v216 Marketplace modules & widgets16 · MARKETPLACEMarketplace modules & widgetssearchversionsinstalldiffupdatenew module or widgetlater: a newer versionshellmxcli auth login # Mendix PAT, oncemxcli marketplace search 'excel'mxcli marketplace versions 23513 --min-mendix 10.24.0mxcli marketplace install 23513 -p app.mprmxcli marketplace diff 23513 -p app.mpr --to 4.5.0mxcli marketplace update 23513 -p app.mpr --to 4.5.0 \ --save-edits ./local-editscontent id, not the name23513 installs Administrationlatest ≠ rightnewer releases may need a newer Mendixkeeps GUIDs & grantsupdate refuses over local editsstays MPR v2widgets land in widgets/AFTER AN INSTALL OR UPDATEmxcli fix widgetsmxcli fix design-propertiesupdate security <Module>mxcli docker check17 Logs, debugger & OpenTelemetry17 · RUNTIME INSIGHTLogs, debugger & OpenTelemetrylogsmxcli log list --filter Connmxcli log set \ ConnectionBus_Queries=TRACElevels NONE … TRACE · runtime.log in .mxcli/debuggermxcli debug enablemxcli debug break M.ACT_Save \ --activity '#3' \ --if '$Order/Total > 100'mxcli debug pausedmxcli debug inspect $Ordermxcli debug step overmxcli debug disablepauses real requests — always disabletelemetrymxcli run --local -p app.mpr \ --metrics \ --trace-otlp \ http://127.0.0.1:4318Prometheus at :8090/prometheus · OpenTelemetryspans to any OTLP collectortrace · ACT_Order_SubmitACT_Order_Submit 412 msretrievecall REST 290 msHTTP POST--trace-otlp keeps timestamps + parentsThe analyze-runtime skill lets the agent ask “why?”errors from logs · load from metrics · time from traces · model shape fromCATALOG.* — then fix the MDL and run again18 Working alongside Studio Pro18 · COLLABORATIONWorking alongside Studio Pro1One editor at a timemxcli refuses to write whileApp.mpr.lock exists. Close theproject in Studio Pro, run mxcli,reopen. (exec --force: stale lock)2Branches live on Team ServerCreate them in Studio Pro, orgit switch -c b && git push -uorigin b. A local-only branchcrashes Studio Pro.3Commits need metadataStudio Pro reads a git note(refs/notes/mx_metadata) onevery commit. mxcli git notewrites it for yours.after an mxcli changemxcli fix hashes -p app.mpr # MPR v2 index ok?git add App.mpr mprcontents && git commit -m '…'mxcli git note -p app.mpr --write # mx_metadata notegit push origin feature refs/notes/mx_metadataPush the notes ref straight away: Studio Pro's background fetch replaces unpushed notes. Merge in StudioPro, never git merge/rebase model history.Or edit live, with it openmxcli --mcp http://localhost/mcp \ --mcp-dial localhost:7782 -c '…'Writes go to Studio Pro's model,unsaved until you save there.skill: live-edit-with-studio-proskill: teamserver-git