Repository navigation
Releases: MendixMau/mxcli-project-toolkit
Release list
1.0
mxcli-project-toolkit 1.0
What it is. A shared process layer for building and changing Mendix apps with an AI coding
agent and mxcli. It gives the agent a staged pipeline
with recorded decisions (PROJECT.md), skills it loads only when a task calls for them, and
mechanical gates (bin/gate-check.sh, lint, mxbuild, end-to-end journeys) that report what is
actually in your project. It runs for migrations, requirements-driven builds, greenfield builds
and changes to a live app, or a la carte to audit and test an app you already have.
1.0 is the first named milestone on top of the release train. Its cut is tagged v2026.10.19,
the first tag published to GitHub, and the GitHub Release on that tag is titled "1.0". Earlier
dated headings in the CHANGELOG were never pushed as tags. All 1.0 work merged into the
release/v1.0 branch while master stayed frozen; that branch then merged to master, where the
cut and its tag were made. Every PR named below has merged, some through the integration batch
#329. Every line traces to an entry in
CHANGELOG.md or to a linked PR. How milestones relate to tags:
docs/RELEASE-PROCESS.md §8.
1. Performance improvements
Does the toolkit help?
tests/behaviour/ gives the mdl helper the same drafting tasks with the toolkit's rules and
without them (#389,
tests/behaviour/results/2026-10-15-*.tsv). 5 runs per arm is a small sample. Without the
toolkit, no run refused a planted bad binding (a page task that asks to bind a system attribute,
AutoChangedBy): 0 of 5, against 5 of 5 with it. No page draft passed mxcli check (0 of 5,
against 2 to 3 of 5), 1 of 5 microflow drafts passed (against 5 of 5), and 2 of 5 committed
inside a loop (against 0 of 5). Tool calls were not compared. The runs without the toolkit still
inherited the host project's own CLAUDE.md (a generic mxcli guide), so this compares the
toolkit's rules against an ordinary mxcli setup, not against no guidance. Every PR that changes
always-loaded text or an agent stub is to run the suite base against head before merge, and the
without-toolkit arm reruns at each release cut.
Testing at key moments
A twenty-task UX-fix retro measured what testing every change costs
(#274): UI-only changes were
re-proven 5 to 10 times (their own journey, the regression journeys of 4 to 5 other modules,
reviewer re-runs), a full mxcli test took about 6 minutes at every batch close, and 143 minutes
of unit tests found stale strings and credential problems, not logic bugs.
The toolkit now runs tests at fixed moments and keeps a change small. Per change, the build gate
plus what the change touched. The full run happens once when the build is complete and once
before every later deploy. Unit tests are off by default and switched on only where logic needs them
(#290,
#417). They are chosen per flow: a module brief lists the
Unit flows: worth a test, one line each with a reason, and affected-tests.sh runs only the
listed flows a change touched. That follows the maintainer's policy that unit-testing everything
is overkill: logic and integrations get unit tests, and UI journeys catch the rest
(#435, #436).
| Moment | What runs |
|---|---|
| Every change (build and feedback) | The gate, plus what the change touched |
| Module done | That module's journeys, plus its listed unit flows |
| Build complete | Everything, once |
| Before every later deploy | Everything, once again |
| You ask | Everything |
"What the change touched" comes from the script itself: ./bin/affected-tests.sh <script.mdl> lists
the unit tests and journeys a change owes, from the elements the script writes and the flows
that call them
(#416). On three real change
scripts in a five-app project it selected 0 to 1 of 20 journey files and 0 to 1 unit test files
per change. It is advisory and exits 0. It also reports journeys unmapped N of M for journey
files that name-based selection cannot reach (12 of the 20 held no qualified name), so an empty
selection is never read as "nothing owed". exec.sh prints the affected tests: hint on every
MDL run. The first call takes about 19 seconds (it builds the mxcli catalog), later calls about 3
seconds.
Other speed items
- A pasted error finds its bug-ledger entry.
bin/bug-lookup.shnow ranks ledger entries
against the whole pasted error message, offline and with no embeddings. On a held-out set
written before the ranker ran, the right entry is in the top 3 for 100% of queries (12
positives), up from 0% for the old keyword match; on the development set, which was also used
for tuning, 94%, up from 9%. It can still give a confident wrong answer: 3 of 18 held-out
queries, all errors with no CE code and no ledger entry, and 3 of 40 development queries. A
better no-match test is a follow-up
(#395). - Where an exec spends its time. The run summary and
docs/BUILD-LOG.mdnow carry per-step
seconds (steps: guards Ns check Ns snapshot Ns baseline Ns exec Ns gate Ns lint Ns score Ns),
and a run whose gate fails keeps its gate seconds. Those failed or rolled-back runs were 47 of
238 rows in the measured project and its costliest 20%. The timing costs about 0.2 seconds per
exec, 0.5 to 0.7% of a 28 to 41 second exec
(#413). - Fewer build rows. A
BUILDrow is now one use case, and a script is the rollback unit.
Two Stage 4 runs on the same requirements had produced 137 and 246 rows (2.5 rows per use
case); build cost followed the row count, 11 versus 25 model calls per row and about 11 versus
about 40 hours. A Stage 4 A/B on two fixture modules (22 use cases) gave 1.05 rows per use case
with the new text and 2.27 to 2.45 with the old. - Stage 5 drafts in parallel. Every build-plan row whose dependencies are applied, minus rows
that write the same document, is drafted at once, one helper per script. Applies stay one at a
time throughbin/exec.sh, and the ready set is recomputed after each
(#343). - Less to read at the start. The always-loaded skill tier went from 79,997 to 76,259 words
with no rule removed
(#315). A helper reads only the
baseline rows for its own role. The mdl helper at Stage 5 went from 56,236 to 43,599 words
(the runbook slice for its stage) and then to 30,647 (a routing row on demand for one role)
(#385).
Routing tables are trigger lists, so a session no longer re-reads the whole runbook (about 24k
tokens) on every later call
(#183). At release the
always-loaded tier stands at 73,682 words (bin/render-routing.sh --check). - The app map refreshes only what changed. On a 17,500-unit app the loop sweep re-described
every loop-containing microflow: 1,917 describes in 2 hours 45 minutes at 6 workers, while about
80 units had changed between rounds. It now describes only changed units. On a synthetic
2,000-unit app with 1% changed that is 20 describes instead of 2,000, andbin/status.shshows
how stale the map is. No field run of the incremental sweep yet. - The UI loop skips a redundant build and waits on the page.
exec.shran two mxbuilds per
exec. It now skips the baseline mxbuild when the model is byte-identical to its last clean pass.
Journeys and the page audit wait on the page's own state instead of a fixed sleep: a fast page
settles in 775 ms instead of 1,200, and a page with a 1.8 second progress bar is no longer
captured half-loaded. In the field run that prompted it,exec.shtook 22% of tool time
(#220). - Helpers are dispatched on purpose. In a measured 20-task run, 15 of 21 top-tier helpers
were on that tier only because they inherited the lead's model: 7.2% of all tokens.
agent-roles.mdnow says to name the model tier on every call, start scans as fresh agents
instead of forks, give a fix round to a fresh fixer, and batch notices
(#292). - Nine routing triggers that never fired are fixed. An audit ranked 55 labelled phrasings
against each routing row's trigger. The right row was in the top 3 for 46 of 55. Nine
triggers now start with the words people type, and the right row is in the top 3 for 55 of 55
(#391, audit in
#394). - Context packs cut helper tool calls and time; see section 3.
2. Settings you control
These are the settings a project owner controls: what runs and when, how much the agent
asks, and what it is allowed to touch. They survive git pull and bin/sync-project.sh.
| What you want | The line or command | Where it lives |
|---|---|---|
| Unit tests across the project | Unit tests default: no (the default) or yes |
PROJECT.md, intake Q13 |
| Unit tests for one module | Set the ... |