Repository navigation
[0.31.0] - 2026-11-09
Headline: Publish your app's microflows as an MCP server, and keep secrets off the command line. create published mcp service writes the MCP Server document Agent Editor starts at runtime, and agents gain tool approval, display text and streaming. The secret run flags and --constant take @env:VAR and @file:path, and the brain can be started before the project and edited in place. Alongside them come a long run of fixes that make check --references catch more of what the build would refuse, and mxcli test --local runs that start clean every time.
Added
-
create published mcp servicepublishes the app's microflows as an MCP server (ako#2020) — the model configuration of MCP Server 5.x: an Agent Editor 2.6publishedMCPServicedocument that AgentEditorCommons starts at startup throughMCPServer.CreateMCPServerandAddTool.create [or modify],alter … set / add tool / drop tool,describe,list published mcp servicesanddrop, withtool name ( Microflow: …, Description: …, Title: …, Schema: … )blocks and the OAuth settings (AuthenticationEnabled,AuthenticationMicroflow,AuthorizationServerUrl,Scopes). The server is served at<app URL>/<EndpointPath>/mcp;ServerName, which Studio Pro stores but its editor does not show, defaults to the document name and is kept when omitted oncreate or modify. A rewrite keeps the stored layout, each tool'suuidand every key mxcli does not model;describe→execof the Studio Pro 11.16 sample writes nothing.checkreports whatCreateMCPServerwould refuse at startup (MDL-MCPSERVER01): a reserved or sub-pathEndpointPath,Scopeswithout an authorization server, an authorization server without an authentication microflow, a tool without a microflow. -
Tool approval, display text and streaming on an agent (ako#2021, ako#2022) — Agent Editor's human-in-the-loop and streaming settings now have MDL. A
toolormcp serviceblock takesUserAccessApproval: HiddenForUser | VisibleForUser | UserConfirmationRequired,DisplayTitleandDisplayDescription. Aknowledge baseblock takesMinSimilarityandIsVisible. The agent takesEnableBackendStreamingandEnableUIStreaming; streaming is stored on the agent, not the model.describe agentprints them andalter agent … setsets the streaming switches. Oncreate or modify, a setting the statement leaves out keeps its stored value.describenow prints an MCP tool as anmcp serviceblock, where a"mcp"/"MCP"mismatch printed a generictool. Measured on Studio Pro 11.12–11.16 documents. -
mcp-serverskill: publish an app as an MCP server with runtime configuration (part of ako#2020) — the MCP Server module (3.x–4.x) publishes through a startup microflow callingMCPServer.CreateMCPServer,AddToolandAddPrompt, which MDL already writes ascall java action. The skill gives the four microflows (authentication, tool, prompt, initialize) with their measured parameters and return types, and the per-versionProtocolVersionvalues; it was written into copies with MCP Server 4.0.0 and 5.4.0 (Mendix 11.16), wheremx checkreported nothing new. It also gives the 5.x OAuth parameters (AuthorizationServerUrl,Scopes, toolTitle) and the 1:1 mapping onto Agent Editor's Published MCP service document, which AgentEditorCommons turns into the same Java action calls at startup. -
checkwarns on an AI model or knowledge base Provider Agent Editor does not import (ako#2023, MDL-AGENT01) —Provider: TotallyMadeUpwrote, built and round-tripped, because mxbuild does not read the value;ASU_AgentEditorthen failed the import at startup.checknow warns, with or without a project, when a model's Provider is notMxCloudGenAI,AzureorFuse(the valuesImportDeployedModelswitches on) or is in the wrong case, when a knowledge base uses anything butMxCloudGenAI, and onalter … set Providertoo. It warns rather than refuses, so a provider a newer Agent Editor adds stays writable. -
The catalog records a page's and a layout's own class and style, and the widgets of every layout (ako#1302, #1311) — a Starlark rule "no inline styles" passed a page with
Style: 'color: red;'and a styled container in a layout, the two places whose styling reaches every page.pages()andlayouts()gainclass_name,styleanddynamic_classes, andwidgets()returns a layout's widgets withcontainer_type"LAYOUT"; a microflow that only a layout's button calls now has that layout as its caller inrefs. Built-in rules that read widgets report a finding in a layout against the layout, and the React-client rule skips native layouts as it skips native pages.update widgetsstill changes page and snippet widgets only. Full catalog; the schema moves to version 34, so a cached catalog is rebuilt once. -
drop X boundary event Ndrops one boundary event of several (ako#808) — numbered asdescribe workflowlists them. Without a number the op named no event, so undermdl 1an activity with several could not lose any of them; a number past the last is refused with nothing written. -
Associations to include on a
call external actionargument (ako#1914, #1721) —command = $Cmd include associations (Odata.Quantity (Odata.Unit))is Studio Pro's Associations to include: the associations whose objects are sent in the OData request with that argument, as a tree. Without them a sub-object linked to the argument was silently missing at runtime. Which end each association is on is worked out from the domain model; a self-association, or one that does not touch the entity on its side, is refused bycheck -pandexec.describeprints the clause.include associations ()removes them all. Left out oncreate or modify, the stored tree is kept, andcheck -pandexecwarn (MDL-ODATA10). That now also holds when the rewrite is spliced in place, which dropped the tree. Mendix 10.11+ for a non-empty clause. Seemxcli syntax odata.consume. -
send external objectanddelete external object(ako#1939, #1735) — Studio Pro's Send external object and Delete external object activities, which save and remove an external (OData) object, now have MDL:send external object $Obj [refresh] [on error …];anddelete external object $Obj [refresh] [on error …];.describeprints them, so a flow that holds one survives a drop + create from its description, which used to delete it silently.checkrefuseson error continueon either (CE6035, MDL076). Seemxcli syntax odata.write. -
A module's version and module type from MDL (ako#1921) — the General tab of Studio Pro's Module settings dialog:
create or modify module Inventory (Version: '2.3.1', ModuleType: addon)andalter module Inventory set (Version: '2.4.0').describe moduleprints the settings that differ from a new module's (App, 1.0.0), and the location as a comment when it is Marketplace modules;list modulesgainsVersionandTypecolumns. The version must be SemVer, the typeapporaddon(Mendix 9.12+), and a statement that restates the stored settings writes nothing. Measured on 11.16: the type is the settings'ExportLevel(Source/Protected), notProtectedModuleType, which isAddOnon every module. -
--constant Module.Name=@env:VARand=@file:pathkeep a secret out ofpsand shell history (#1765) —mxcli runandmxcli test --localread the value from an environment variable or from a file, so a token no longer has to be typed into the command line, which shows it inpsfor as long as the app runs. An unset or empty variable and an empty file are errors, not an empty value; the owner-only check on a file is made on Unix and not on Windows; a relative@file:path is stored as an absolute one, sorun restartworks from another directory; a file readable by its group or by others is refused (chmod 600); one trailing newline is dropped. A value that really starts with@is written@@…. The run state keeps the@env:/@file:form, never the value. -
The secret
runflags take@env:VARand@file:path, so a password stays off the command line andrun restartstill works (supersedes #1761) —--db-password,--db-admin-password,--screenshot-password,--hub-secretand--debug-passresolve a reference the way--constantdoes: an unset or empty variable, an empty file and a file its group or others can read are refused, naming the flag and the source, never the value. The reference, not the secret, is whatpsshows and what.mxcli/run-state.jsonstores, so a run started with one can be--detached andrun restarted; each start resolves it again in its own environment, and a relative@file:path is stored as an absolute one. #1761 proposed reading the password from stdin, which cannot be read again and so ruled out--detachandrun restart; its fix for a flag value that looks like-pbeing dropped from the detached command is included. -
braincan start before the project, and entries can be edited, moved, sourced and listed (ako#1949, ako#1950, ako#1951, ako#1952) — the brain's store now lives as long as the project does, from before it exists, and changes in place:-C/--dir <dir>names the brain's directory on everybraincommand, so you can fill a brain before its.mprexists, andmxcli newadopts a target directory that holds only a brain.brain initno longer takes an argument it used to ignore.brain edit <id> [<text>] [-a @Anchor]…rewrites a staged or committed entry in place and keeps its id;brain move <id> --slice <s>moves a requirement to another slice.capture --source <doc>[#<locator>]andedit --sourcerecord which document an entry came from, and where in it. The path is stored relative to the project, so it works on other machines.brain list [--slice] [--kind] [--open] [--json]returns the committed store as data instead of rendered markdown, and reports malformed blocks rather than dropping them.
-
alter page setreaches a Data grid 2 column's attribute and a text template's parameters (ako#1644, ako#1966) —set (Attribute: …) on <grid> column(…)binds the column ascreatedoes (bare name,Module.Entity.Attror anAssoc/…/Attrpath).set (CaptionParams: …)on a button andset (ContentParams: …)on a dynamic text replace the template's parameters. Before this, you had to replace the whole widget. -
A queued call's retry policy in MDL (ako#1931) —
in queue … retry fixed|exponential (…)writesQueues$QueueFixedRetry/QueueExponentialRetry;describeprints a stored retry so it round-trips, andcheckrefusesRetries: 0(CE7044). A flow with a queued retry could not be rewritten before; a rewrite that would drop the stored retry is now refused.
Changed
- A secret
runflag value starting with@is refused unless it is@env:,@file:or@@—--db-password,--db-admin-password,--screenshot-password,--hub-secretand--debug-passfollow the--constantrule; write@@…for a password that really starts with@. - A
--constantvalue starting with@is refused unless it is@env:,@file:or@@(#1765) — it used to be applied literally; now a mistyped@evn:TOKENis not quietly used as the constant's value. Write@@…for a value that really starts with@.
Fixed
- Building a flow no longer reads every microflow of the project once per called flow (ako#2043) — resolving a
call microflowtarget looked its name up by reading and decoding every unit of the type, so one large flow in a large project took minutes, and outlasted the per-statement limit. A lookup now records where each name is and later reads that one unit, re-checking its name, type and module so a unit renamed or moved outside mxcli is not returned; a miss scans as before. On TestApp a flow calling 44 microflows builds in 0.29 s instead of 0.6 s; the saving grows with the number of flows in the project. - A statement that times out or panics no longer crashes
execpast its rollback (ako#2043, #1780) — a statement that outlasted the per-statement limit kept running afterExecutereturned the timeout;execthen closed the project to roll back, the statement read through the closed reader, and the nil-pointer panic in its goroutine ended the process before the rollback and before the timeout was printed. The drop and every earlier statement stayed written.Closenow waits (up to 2 minutes) for such a statement to stop, and a panic in any statement is that statement's error, so the script is rolled back as for any other failure. - References to entities named as a type or reached through an association (ako#1829) — a flow whose action result, created list or Java/JavaScript entity-type argument names an entity, a snippet's parameters, and the entity an association path arrives at made no
refsrow, soshow references,impactand the unused-entity check missed them (five entities in use on one project read as unreferenced), and an incremental build left a flow stale when an enumeration value it named was added. They are nowtype,parameter,memberandxpathedges to the entity, andvalueto the enumeration when the value does not exist. Annotation and text prose and module-role names no longer produce member edges. Full catalog; the schema moves to version 37, so a cached catalog is rebuilt once. - The test endpoint's generated Java source is git-ignored (ako#2033) — while
run --test-endpointhosts the endpoint,javasource/mxtest/actions/RegisterTestEndpoint.javais in the working tree, and agit add -Ain that window committed it.run --test-endpointnow ignores/javasource/mxtest/(and.mxcli/, which holds the endpoint's token) before installing it, creating the project's.gitignorewhen there is none; the.gitignoremxcli initwrites, or adds to, carries the entry too. run --local --watchno longer rebuilds after the boot because the build wrote a new module's theme scaffold (ako#2033) — with--test-endpointthe boot build createsthemesource/mxtest/, whose files are watched theme source newer than the boot's baseline, so build #2 started with nothing edited: ~30 s of 404s ondist/pagesand a forced client reload, right asrun --detachreturned. A themesource/ folder a build creates is now its own output up to the build's end; edits to existing theme files, and later edits to the new folder, rebuild as before. Measured on a blank 11.12.6 app: build #2 every boot before, build #1 only after.marketplace installandupdatedownload the module's managed Java dependencies (ako#2028) — a module such as MCP Client 4.4.0 declares Maven dependencies that Studio Pro downloads intovendorlib/on import. A headless install copied only the declarations, somx checkpassed andrun --local/test --localfailed with ~180package … does not existerrors. The install now runs the sync, and printsmxcli sync-java-deps -p …when it cannot. The sync retries once when mx cannot reach the Maven repository ("Failed to find some hosts"), and a version range such as[2.21.2,3)counts as vendored when a version inside it is — it used to read as missing after every successful sync, sorun --localre-synced on every boot.- Lint SEC013 warns when the security level ignores the project's access rules (ako#2027) — a blank app ships at security level Off, where the runtime applies no entity access, page or microflow grant and creates no demo user; at Prototype it applies no entity access, so XPath constraints have no effect. check,
mx check,test --localand lint all passed while a customer read every row. SEC013 names what the level ignores and suggests Production; the manage-security skill says up front that a blank app ships Off. - Lint ARCH001 no longer flags the System workflow entities a task page must use (ako#2034) — the
System.WorkflowUserTaskdata view of every task page and a task inbox over it were reported as cross-module data access, though Mendix requires them (CE7410/CE7412, CE1843) and offers no view entity or microflow instead.System.Workflow*is exempt; other cross-module references are reported as before. - References to import and export mappings and to JSON structures (ako#1861, #1703) — a flow that applies a mapping, through an import or export action or a REST or web service call, and a mapping built on a JSON structure made no
refsrow, sorefs,show callersand orphan checks reported mappings and structures in use as unreferenced. They are nowmapping_calledges (counted byshow callers) andstructureedges, and an import or export activity'sActionRefnames its mapping. Full catalog; the schema moves to version 36, so a cached catalog is rebuilt once. - Rewriting an agent, model or knowledge base kept nothing mxcli does not model —
alter agent,alter knowledge baseandcreate or modifyrebuilt the document's JSON from mxcli's own fields. What Agent Editor stored beyond those was lost without a warning: each tool's user approval and display title and description, the agent's streaming switches and selected model, and a knowledge base tool's minimum similarity. The knowledge base's Portal name was written empty, and oncreate or modifyso was the model the Model document had picked.create or modify agentalso ignored a tool'sDocument:, which left the tool running no microflow. It gave every tool a new, empty id and blanked the entity reference, and its MCP service tools lost their service. A rewrite now writes onto the stored JSON in Studio Pro's layout and key order, and restated tools keep their stored ids. Measured on Studio Pro 11.16 projects:describe→execof all 33 agent documents of one app now writes nothing. - The catalog's source text is what
describeprints (ako#2036) —CATALOG.SOURCEkept every stored layout annotation for speed, so a script generated from it stated layoutdescribeleaves out (376 of one project's 858 microflows). It now stores the canonical description; a cold source build pays for telling derived layout from authored, and the incremental source build (#1790) carries unchanged rows after it. - The agents skill showed calls to the agent Java actions that do not exist (ako#2024) — it said
call agentwas missing and gaveAgentCommonsexamples with parameters the actions do not have (UserMessage,ChatContext). Studio Pro's Call Agent toolbox actions are exposed Java actions thatcall java actionalready writes. The skill now leads with theAgentEditorCommonsactions, which take an agent document by name (Agent = 'Module.MyAgent'). It lists each action's real parameters, measured on 11.16 projects. TheAgentCommonsactions are kept for agents built at runtime. brain captureandbrain promotehonour--json(ako#1953) — they printed prose, so a caller scraped the new id out of a sentence.capture --jsonreturns the id, kind, slice, shard and whether it was added (status:queued,already_queued,already_committed);promote --jsonthe id, kind, shard and the file written. A duplicate capture also named a freshly minted id no entry had ("Already queued as …"); it now names the queued twin's.drop user rolerefuses a role a demo user still holds (#1775 follow-up) — it passedcheckandexecand left the demo user naming a role that no longer exists, whichmx checkreports as CE1613.check --referencesand exec now refuse it and name the demo users to drop first; dropping them earlier in the same script is followed.drop user rolerefuses the administrator's user role instead of leaving a project every build crashes on (ako#2015, #1775) — dropping the roleSecurity$ProjectSecurity.AdminUserRolenames (the templateAdministratorof a new app) passedcheck,execandmx check, and every build then failed with a NullReferenceException in mxbuild.check --referencesand exec now refuse it. The administrator's role can be moved first withalter app security ( AdminUserRole: <UserRole> ), which must name an existing role, anddescribe app security/show project securityprint it asAdmin User Role.check --referencesstill reports the flow changes exec would refuse when it finds a reference error (ako#2014, #1774) — it stopped at the reference errors, so acreate or modifyexec refuses (MDL-V1-REBUILD) went unreported until the reference error was fixed and the script checked again. The flow verdicts now run either way and the run reports both. The other project checks stay skipped after a reference error; the summary already counted reference errors (ako#1928).- A snippet call is recorded as a reference to the snippet (ako#2017) — the catalog stored a snippet call's snippet as the page a widget opens, so
refsheld ashow_pageedge to aPAGEfor every snippet call and none hadTargetTypeSNIPPET; a query for what uses a snippet, from a layout or anywhere else, found nothing. Snippet calls are nowsnippet_calledges to aSNIPPET,widgetsgainsSnippetRef(snippet_refin Starlark), andshow callerscounts them. Full catalog; the schema moves to version 35, so a cached catalog is rebuilt once. searchfinds usages in flow, page and expression bodies on a project that has never built the source index (ako#2004, #1771) — it searched only string literals and documentation, answered "No matches found." for a name used only in a microflow body, and exited 0 with just a stderr warning. The first search now builds the source index, saying so; later searches keep it current incrementally.search --no-buildnever builds it, and exits 3 when it is missing, so an incomplete answer is never read as "nothing matched".create persistent entity … extendsa non-persistent entity is refused instead of silently created non-persistent (ako#2005, #1772) — a specialization has no persistability of its own: Mendix stores it only on the root of the generalization chain, so the stated keyword was dropped and exec said "Created entity". Apersistentornon-persistentthat contradicts the root is now an error fromcheck --referencesandexec, naming the root; one that matches it, or none, is accepted as before, sodescribeoutput still re-runs.- The catalog indexes widgets inside tables, scroll containers, headers and split panes (ako#1895) — the widget walk followed only the container keys it knew, so every widget in a legacy table cell, a scroll container region, a header side or a split pane was missing from
widgetswhilexpath_expressionsnamed it. On FactoryManagement 213 widgets were absent, among them the MxModelReflection snippets' list view and combo boxes, and lint rules that read widgets did not see them. The catalog schema moves to version 33, so a cached catalog is rebuilt once. check --referencesreports a snippet call into an add-on module (CE1406) (ako#1998 follow-up) — a page or snippet in an app module that called a snippet of a protected (add-on) module passed check, and mxbuild refused the build: "Snippet call 'sc1' is not allowed to use snippet 'Lib.Sn' because app modules cannot reference hidden elements in add-on modules". Like a page, such a snippet is refused whatever export level it stores (measured on 11.12.6, with Hidden and with API), so the call is reported whenever the snippet's module is an add-on; a call from inside the add-on, or into an app module, is not.- Packaged and sealed add-on modules (
modules/*.mxmodule) are read like any other module (ako#1780, ako#1998, #1762) — a module the project holds as a package file has no unit in the.mpr, so mxcli did not see it:show modulesleft it out,describesaid "not found", andcheck --referencesrefused valid calls into its public nanoflows. Its documents are now read from the package's ownproject.mpr(an ordinary v1.mpr, or the module tree a protected add-on ships), in v1 and v2 projects alike;show modulesanddescribe modulemark it as packaged. It is read-only: a write into it is refused bycheck --referencesand by exec, and nothing is written. - An
alter microflowfragment can name members of a created list, a cast, a nanoflow call's result and a mapped import or REST result (ako#1796) — those stored outputs were untyped for the fragment, so a member of one was refused with "cannot qualify member" althoughcreate microflowtypes them. A name that two stored origins type differently now stays untyped whatever kind the origins are; before, of two direct origins (a retrieve, a create, a call) the last one won. run restartno longer suggestsPGPASSWORDfor a run it cannot restart — refusing a run whose literal secret was not stored, it said to set the database password inPGPASSWORD. The runtime's database password never reads that variable (only--ensure-db'spsqldoes), so a run started that way connected with the defaultmendix. It now says to start the run with--db-password @env:VARor@file:path, which restart resolves again.widget sync --pagetakes the qualified name it documents (ako#1997) —--page Module.Pagematched nothing and reported no drift; only the bare name worked, and it matched a page of that name in every module. A bare name is still accepted when it is unambiguous and refused when it is not, the plan names pages by their qualified name, and an applying run no longer prints "Read-only: nothing was written."git mergekeeps your text resolutions when it stops for a model decision (ako#1982, #1751) — after you resolved and staged a non-model conflict and re-ran, a model conflict that needs a decision aborted the merge and threw the resolution away;--planthen wrote the model and failed at the commit on "unmerged files", leaving the merge half done. The abort now records your resolutions in the plan template and--planrestores them, and--planstops before it touches the model while a text conflict is still open.create constantwritesExportLevel: Hidden, as Studio Pro does (ako#1980, #1749) — it wrote"", whichmx checkaccepts butmx diffcrashes on against aHiddencopy (exit 129), takinggit merge's report with it.create or modify constantnow keeps a stored level instead of clearing it, and repairs a stored"".git mergereports the side whosemx difffailed instead of dropping the report (ako#1981, #1750) — when one side's diff failed, no property-level report was printed at all. The side that worked is shown, and the failing side reads(diff unavailable: <why>).widget synckeeps the integers it does not change as integers (ako#1976, #1748) — syncing a widget wrote every int32 and int64 in it back as a double, a text box in the widget's slot included, whoseMaxLengthCode -1.0Mendix reads as unlimited (CE6510). A unit already synced by an earlier version keeps its doubles; re-create the page to repair it.- A Marketplace Calendar written by mxcli passes a plain
mx check(#1632) — every Calendar failed with CE0463 "The definition of this widget has changed" untilmxcli fix widgetsor Studio Pro's "Update all widgets";mxcli docker checkhid it, since it runs that update on a temporary copy first. The Calendar'stoolbarItemsobject list declares its sub-properties directly under<properties>, not inside a<propertyGroup>, and the.mpkparser behind generated widget templates read only the grouped shape, so the list was stored with no definition of its items. Both shapes are now read, a direct sub-property takes its category from its own<category>element, and the stored Calendar equals whatmx update-widgetswrites. The other object-list widgets indoctype-tests/32-pluggable-widget-object-lists-v010.mdl(Accordion, PopupMenu, Maps, area and line chart, heat map) are stored unchanged. alter workflowno longer guesses which outcome to drop (ako#808) —drop X outcome 'V'with two outcomes of valueVdropped the first; it is refused as ambiguous now.check --referencesalso resolves an activity reference by name before caption, asexecdoes, so its guards no longer go silent on a target captioned like another activity's name.- describe → exec keeps a decision whose true branch is empty (ako#1963, #1742) —
describe microflowfolded such a decision intoif not(X) then <false branch> end if;, and executing that storednot(X)with the true and false outcomes swapped: the same behaviour, a different model in Studio Pro. It is now printed as stored,if X then else <false branch> end if;, which builds Studio Pro's shape. A script written from the old output still means the same thing; analter microflowtarget written in the foldedif not(X) thenform no longer resolves, and is refused rather than applied. marketplace installinstalls protected (add-on) modules shipped as.mxmodule— such a package carries its model not as an SQLite.mprbut as one BSON document holding the module as a tree, so install failed withfile is not a database, andmx module-importrefuses protected modules outright ("Importing protected module is not supported", exit 111). The reference project is now built by splitting that tree into units and writing them with the same raw-unit writer the transplant uses; protection settings travel unchanged. Measured on Menditect's MtaPluginModule 11.5.5 (Marketplace 214717) into an 11.15 MPR v2 app: 32 units,mx check0 errors, module listed as Protected AddOn, and the plugin starts and serves its endpoint. The package's declared files (javasource/,javascriptsource/, …) are written beside the reference project asmx module-importwould, somarketplace diffandupdatedo not report every Java or JavaScript action as changed; the units are not converted to the project's Mendix version, so a package saved with a newer Mendix than the project is refused.test --attachon Mendix 11.14.0 says why it is refused instead of blaming an entity — that version'smxbuild --servefails every build after its first, so since ako#1917 the attach builds on a fresh serve process, whose first build asks for a runtime restart whatever changed. The refusal claimed "an entity or association changed" and suggested restarting the dev loop, which does not help; it now says the build could not be done incrementally and points to--local. The hosting app's pages survive either way. 11.15.0 builds incrementally and attaches as before.describe microflowno longer leaves out a note linked to the start event or to another note (ako#1933, #1731) — such a note counted as linked, so it was not printed as a free note, and the element it is linked to prints no@annotation, so it was not printed at all; re-executing the description deleted it. It is now described as a free note, after a-- WARNINGline saying the link itself has no MDL form and a rewrite drops it.- Rebuilding a described decision no longer adds a merge (ako#1929, #1727) — a
case,split typeorif … elsifone of whose branches returns is described with its own merge as a label (end case; join shared1; merge shared1;). Executing that as a fresh create built the decision's merge and a second one for the label, wired merge to merge, and every further describe → drop + create added another (join junctionN; merge junctionN;). The label's merge is now the decision's merge when nothing else reaches it, so the round trip keeps one merge. describe microflowprints a blankcall external actionargument as= nothing(ako#1915) — Studio Pro 11.16 stores an optional OData action parameter left blank as an empty argument, anddescribeprinted it asadditional = ), which does not parse, so everymdl 1;create or modifyof such a microflow was refused (MDL-V1-REBUILD).call external actionnow takesParam = nothing, the blank-argument spellingcall microflowandcall nanoflowalready use;Param = empty(what 11.14 stored) stays a different value, and each round-trips as itself.- The description of an AccessibilityHelper re-executes (ako#904) — an
attr (attribute: 'aria-label', …)item was read bycheck --references, whichexecruns first, as an attribute binding with no data container, so describe → exec refused every helper that sets an HTML attribute. An object-list item's properties are now the item's own. - A Delete button in a data grid's control bar deletes the grid's selection (ako#1932, #1730) —
action: delete $grid1stores the selection as Studio Pro does (SourceVariable= a page variable naming the grid), anddescribeprints a stored one back that way; it printed plaindelete, so a describe → exec round trip dropped it. A baredeletewith no object to delete — in a control bar, or outside every data widget — wrote a button mx check reports as CE7005;checkandexecnow refuse it (MDL-PAGEDEL01).delete $Paramdeletes a page or snippet parameter. - A script that would rebuild a flow holding unsupported activities is refused before it runs — under
mdl 0, acreate or modifythe splice cannot make is rebuilt as a whole, and a flow holding an activity MDL cannot express (-- Unsupported action: …) refuses that rebuild whenexecreaches it, after the statements before it were written.check -pandexec's preflight now refuse the script up front (MDL-FLOW-UNSUPPORTED), as they already do for a drop + create of such a flow. retrieve … offset nwithout a limit keeps its offset (ako#1941, #1737) — an offset with nolimitwas written as the "all" range, so the retrieve returned the first objects instead of skippingn, anddescribeprinted no offset. It is now written as a Custom range with that offset and no limit, whichmx checkaccepts.marketplace updateno longer removes the module and then fails (ako#1934, #1732) — every update failed withopen package target.mpk: no such file or directoryafter it had already dropped the installed module, leaving the project half-updated: it looked for the downloaded package under a different name than it was saved under. It now uses the downloaded package, and checks the package and the new version's module before it changes anything, so an update that cannot complete stops with the project untouched and says so.create or modify microflowno longer inverts a decision whose condition changes (ako#1930, #1728) —describeprints a decision whose true path goes straight on asif not(X) then …with its paths swapped. Fed back with only the condition changed, the in-place edit stored the printednot(Y)as the decision's expression while its paths stayed, so the decision did the opposite of what the script said, withcheck,execanddiffall clean. The edit now stores the condition the decision means.test --attachno longer breaks the hosting app's pages (ako#1917, #1723) — after a greenmxcli test --attachagainstrun --local --test-endpoint, the app answered 404 on its page bundles and every page showed the generic error dialog until it was restarted. The attach's builds went to the app's ownmxbuild --serve, where on Mendix 11.12.5 and later any build after the first leaves the client bundle without its pages. The attach now finishes such a build on amxbuild --serveof its own, which it stops afterwards, and leaves the app's untouched; this costs a cold build each time it happens.run stopremoves--test-endpointfrom the project on Windows (ako#1917, #1723) — a detachedrun --local --test-endpointstopped withrun stopleft theMxTestmodule, its after-startup microflow,themesource/mxtest/andjavasource/mxtest/in the project, because on Windows the stop ends the run without its teardown; the next build then failed with CE1613 once the module was dropped. The run now records how to remove the endpoint when it installs it, andrun stop(or the next--test-endpointrun) removes it when the run could not, on any platform, leaving the project file byte-identical.- A jar dependency change keeps the module's Module ID and Marketplace checksum (ako#1920) —
alter module … add | set | drop jar dependencyrebuilt the module's settings from the keys mxcli models, so the rest came back as defaults: the Module ID (PackageId) and a Marketplace module'sChecksumwere wiped, and detailed troubleshooting was switched on. The change is now written onto the stored settings, and only the jar dependencies change. create or modify microflowkeeps a call external action's "Associations to include" (ako#1914, #1721) — MDL has no syntax for them, so a rewrite that restated the call wrote it with none, and the OData request then silently left out the associated objects;check,lintand the build all passed. The associations Studio Pro stored on each parameter — a tree, not a flag: an association ticked under another is nested in it — are now carried onto the rewritten call, matched by action and parameter name, and only while the parameter still binds the same entity. When a microflow calls the same action twice with different associations, the rewrite is refused rather than guessing which call has which. A drop followed by a create still starts without them.validation feedbackon an attribute namedErrorparses (ako#1913, #1720) —validation feedback $E/Error message 'x', which is whatdescribewrites for such an attribute, failed with "missing MESSAGE" becauseError messagewas read as theerror messageclause keyword. After a/or.the word is now always a member name, in any case and anywhere an attribute path appears; theerror messageclause itself is unchanged.dateFormat: customon a dynamic-text parameter is stored as Custom (ako#1864, #1706) —checkaccepts a parameter'sdateFormatandenumFormatin any case, but the writer stored the value as written, and"custom"is not a value Mendix knows, so the runtime showed the default format. The values are now stored in Mendix's spelling (Custom,DateTime,Image) on dynamic text and on Data grid 2 column templates.- A doc comment above
alter entity … add attributeis stored on the attribute (ako#1863, #1705) —/** Why */written above the statement was read by nothing: exec reported "Added attribute" and the attribute had no documentation, with only a latercheckwarning MDL089. It now documents the attribute the statement adds, as it does above acreate entityattribute, foralter entitiestoo. When the statement adds two attributes, or the attribute has its own comment, the comment is still not stored andcheckstill warns. mxcli test --watchno longer shows a green run for a rebuild that failed — when the rebuild after an edit failed (or the changed tests could not be parsed or injected), the loop printed the error and then ran the suite again at once, against the model from before the edit, so a broken microflow could pass. The round is now reported as an error row naming the step and the reason, in the terminal and in the JUnit file, the suite does not run, and the loop waits for the next change. The change baseline is taken when the change is detected, so a save made while the rebuild is failing starts a new round, and the "run #N" counter only advances for a round that ran. Ctrl-C after a failed change ends the watch with the red result, so the command exits non-zero. (#1766)- A copied app folder no longer inherits the original's run state, and run state no longer stores secrets (#1764) —
.mxcli/run-state.json,run-local.jsonandtest-endpoint.jsonrecord the project they were written for, but nothing compared it, so in a copy of a running appmxcli runrefused to start andmxcli run stopsignalled the original's process, andmxcli test --attachtalked to the original's app. All three are now ignored when they name another project (symlinks resolved, case-folded on macOS and Windows);run statusandrun stopsay that they ignored one.--constantvalues, the password flags and theDatabasePasswordandMicroflowConstantsruntime settings are no longer stored inrun-state.json, and the dev-loop handshake no longer holds the resolved constants. The handshake filerun-local.jsonstill holds the database password (re-applying constants needs it); it is written owner-only (0600). Behaviour change: a run started with--db-password(or another inline secret) cannot berun restarted;run restartsays so and names the alternatives (thePGPASSWORDenvironment variable, or re-runningmxcli runwith the password) instead of starting the app with a placeholder. A run recorded from a devcontainer or WSL path is treated as another folder by the host side, so its state is ignored there. mxcli testfailure line shows the actual value of an enumeration compare (#1763) —@expect $Paid/Status = Procurement.InvoiceStatus.PAIDfailed with onlyexpected …, because the actual value was reported only when the operand type was known and an attribute path next to an enumeration value never was. An enumeration value on one side now pins the other, so the line readsexpected $Paid/Status = Procurement.InvoiceStatus.PAID, actual: APPROVED(the enumeration key, viatoString()).mxcli test --localno longer carries state or noise between runs — a run of the suite now reports only what the suite did:- Each run starts on an empty test database, on hsqldb and on PostgreSQL (where only the scratch
<app>_testdatabase is cleared, never the dev loop's) (ako#1853). - When
mxbuild --servestops answering, the boot restarts it and builds once more instead of failing withcontext deadline exceeded; a test that does not build has its errors repeated above the summary rather than lost among the "not run" rows (ako#1834). - No more
Module 'MxTest' already existson a clean project (ako#1856), and no MDL-V1-SLASH / MDL-DEPR001 per test on a headerless suite (ako#1855).
- Each run starts on an empty test database, on hsqldb and on PostgreSQL (where only the scratch
check --referencescatches more of whatexecor the build would refuse:- An image reference is matched case-sensitively, as Mendix does (a case difference is CE1613), and the hint names the stored spelling.
drop,renameandmoveof a document that does not exist, andalter enumeration/alter microflow/alter nanoflowon one, are reported with the module's near names (ako#1821).- A
show pagepassing a parameter that an earlieralter page … add parametersdeclared is accepted (ako#1940). alter page … set (DateFormat: Custom, CustomDateFormat: …)is accepted in either order (ako#1965).
- Page widgets that
mx checkrefused — a text template bound to an unset optional data source is stored as null, as Studio Pro does, and no longer CE0463 (ako#1967). Asnippetcallpassing a data view's object names the widget instead of a page parameter the page lacks (CE0115) (ako#1968). On a 9.x project, editing a pluggable widget keeps its Database source type instead of turning it into XPath (ako#1208). - Association paths are checked from the context entity (ako#834) —
database from $ctx/A1/A2resolves multi-hop paths the way an association source does, and a hop that does not start at the context entity is refused instead of written as a step that cannot be followed. - An import mapping rooted at a JSON array returns one object (ako#1938) — the import activity was written as returning a list, which mx check reported as CE0243.
- External entities keep their OData capabilities when
$metadataaliases a vocabulary (ako#1977) — aliased Insert/Update/DeleteRestrictions and Core terms were skipped, socreate external entitiesimported entities as not creatable or deletable (CE6630). - Workflows on Mendix 9 — the user-task claim MDL-WORKFLOW10 suggests uses
System.WorkflowUserTask_Assigneeon Mendix 9 and_Assigneesfrom 10.0 (ako#1810). An annotation is written asWorkflows$Annotation; the old storage name made Studio Pro throwTypeCacheUnknownTypeException(ako#1784). describeoutput that did not re-execute — a text holding$$(such as a JSON sample) is written as a string literal (ako#1003). A message definition member is printed by the attribute it references after a rename, andcheckrefuses a member naming an attribute the entity lacks (ako#1935).marketplace diffandupdateno longer report every Java action of a protected module as changed — the reference project now holds the package's Java and JavaScript sources, asmx module-importwrites them.- Lint MPR008 names the loop when a loop's box causes the overlap (ako#1839) — it gives the gap needed instead of asking for
@positionannotations that are already there. mxcli syntaxdocuments every built-in expression function and everydropstatement (ako#1866, ako#1911) — the function list is rendered from the type checker's own signature table, so the reference andcheckagree.
Full Changelog: v0.30.0...v0.31.0