Skip to content

Latest commit

 

History

90 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

mx-codr

Your AI agent builds the Mendix app. mx-codr makes sure it is actually finished.

Claude Code, Codex, Cursor and OpenCode can already write Mendix domain models, microflows and pages. What they don't do on their own is prove the work: a test for every screen, a model that passes Mendix's own checks, microflows a colleague can read, screens that aren't glued together. mx-codr adds exactly that — one installer, and one command that answers DONE or NOT DONE.

It sits on top of mxcli:

  • mxcli opens command-line access to a Mendix model
  • mx-codr adds a harness — skills, rules and hooks — to turn it into a delivery workflow.

What you get

  • Test-first, automatically. The agent writes a failing browser test before each feature, and every page and action ends up with one.
  • One command decides "done". bash tests/gate.sh runs the browser tests, mx check, lint, test coverage, naming and layout together, in under half a minute.
  • Rules the agent keeps following. Hooks repeat them on every prompt and after every model change, so they don't fade by the third feature.
  • A model people can read. Business captions on every activity, process folders, shared snippets and sub-microflows instead of copies, spacing from the Atlas theme.
  • Your agent, your OS. Claude Code, Codex, Cursor and OpenCode, on macOS, Linux and Windows — Windows on ARM included.

Get started

Copy the mxcodr/ folder into your Mendix project — or into an empty folder, and the installer creates the app for you. Then, from that folder:

macOS and Linux

bash mxcodr/install.sh --with-deps

Windows — open PowerShell as administrator and run:

powershell -ExecutionPolicy Bypass -File mxcodr\bootstrap.ps1

Windows has no bash out of the box, so bootstrap.ps1 first installs Git for Windows (which brings Git Bash), Python and Node with winget, then runs the same installer. Administrator rights are needed because winget installs Docker Desktop. Already have Git Bash? Run bash mxcodr/install.sh --with-deps from Git Bash instead.

Start a new agent session and ask for a feature. That's it.

The installer sets everything up

You don't install the pieces one by one. The installer checks what this machine has, fetches what is missing, and tells you plainly about anything it could not do.

What the installer does
Your Mendix app Creates one with mxcli new if the folder has none (Mendix 11.12.1 unless you set MX_VERSION)
mxcli Uses the newest mxcli on the machine, offers the latest release when it is newer, and verifies the download's checksum
Docker Installs it when it is missing. It is optional: see Running without Docker
Python, Node, Playwright and its browser Installs them with --with-deps — the checkers and browser tests run on them
MxBuild Downloads the one for your Mendix version with --with-deps, so mx check runs
PostgreSQL Sets it up when you work without Docker, with --with-deps
Skills, lint rules, checkers, hooks Puts them where each of the four agents looks for them
Windows Applies the junctions and ARM64 fixes that Studio Pro's mxbuild needs

What cannot be installed unattended — a JDK, a Docker daemon that has to be started if you use one — is listed at the end with the command to run.

How a feature gets built

 you ask ─▶ agent writes a test ─▶ test fails (red) ─▶ agent builds it in MDL
                                                              │
      DONE ◀── gate: tests · mx check · lint · coverage · naming · layout ◀── test passes

You never run the checks yourself. The agent runs the gate, and the hooks make sure it does.

Does it make a difference?

Two A/B runs: the same prompt, the same model, a fresh app each time — once without mx-codr, once with it.

Without mx-codr With mx-codr
Browser tests written 0 5–7
Gate at the end NOT DONE (no tests, no coverage, spacing errors) DONE
First verified DONE never after 11.6–12.2 min
Whole session 11.0–11.4 min 15.2–15.9 min

About a minute more to reach a verified result; the rest of the extra time was the agent polishing after DONE.


How the pieces fit together

mxcodr/ is the whole bundle. Everything below is about installing and using it.

Nothing in this harness is a tool you operate. There is no Python script to invoke, no checker to remember the arguments of, no order to run things in. After install.sh, every piece is found and used by the agent on its own:

What How the agent finds it
The six rules, in prose SKILL.md files in the three directories each host looks in
The always-loaded reminder .claude/rules/ and .cursor/rules/, loaded on every turn
MOD001, REU001 mxcli lint discovers .claude/lint-rules/*.star by itself
check_mdl.py, check_test_coverage.py the skills that need them name the exact command; the gate runs them too
The gate host hooks fire it, and the test-first-delivery skill tells the agent to

The Python checkers exist because two of the rules cannot be expressed as lint rules — activity captions are not in the model catalog, and test coverage means reading tests/ off disk. They are an implementation detail of those two rules, installed at tools/mdl-checks/ so every host can cite one path. The agent calls them. You never have to.

The same is true of tests/gate.sh. The hooks run it, and the skills tell the agent to run it before claiming anything is finished. You can run it yourself when you want to see where a project stands — that is a convenience, not a step.

So the whole of your involvement is, from your project folder:

bash mxcodr/install.sh --with-deps

and then working with your agent as usual.

What it enforces

Rule What it asks for
test-first-delivery a failing test before the feature, and a test naming every page and ACT_ microflow
module-structure documents in process-named folders, ACT_/SUB_ split, microflows under 15 activities
naming-and-captions PascalCase, ENUM_/SNIPPET_ prefixes, _NewEdit/_View/_Overview pages, a business caption on every activity
reuse-and-snippets a snippet used on more than one page, a SUB_ microflow with more than one caller
organize-project nothing orphaned, nothing left at module root
spacing-and-layout widgets on one line spaced with Atlas design properties, never custom CSS

Requirements

Why
mxcli everything runs through it
Mendix Studio Pro or a cached mxbuild mx check validates the model
PostgreSQL the app's database, and a separate <project>_test one
bash the harness is shell scripts — Git Bash on Windows
Python 3 for the two checkers the agent calls; you never invoke it
Node + playwright-cli the browser tests
A JDK matching the Mendix version; Studio Pro installs one
Docker installed by default; optional: see Running without Docker

--with-deps installs the ones that can be installed unattended. It never installs a JDK — that wants a licence click.

Install

Copy mxcodr/ into your Mendix project and run the installer from the project folder, one level above mxcodr/ — not from inside mxcodr/:

cd MyApp                              # the folder with MyApp.mpr and mxcodr/
bash mxcodr/install.sh --with-deps

cd mxcodr && bash install.sh still installs into the folder above, but then the target is guessed rather than named, and with no app there it stops to ask.

bash mxcodr/install.sh [path-to-project] [--no-app] [--with-deps]

  path-to-project  where to install (default: the current directory, or the
                   parent project when run from inside the bundle)
  --no-app         never create a Mendix app; require one to be there already
  --with-deps      install missing prerequisites with this machine's package
                   manager. Without it they are only reported.

With no .mpr in the target and --with-deps, it creates a Mendix app for you.

Windows

There is no bash on Windows until something installs it, so there is a second entry point for that one job:

powershell -ExecutionPolicy Bypass -File mxcodr\bootstrap.ps1     # from the project folder

It installs Git for Windows, Python and Node with winget, then hands over to bash install.sh --with-deps.

Run it from an elevated terminal. winget's Docker Desktop install asks for administrator rights, and unelevated it fails with exit code: 4294967291 and is reported as missing.

If you already have Git Bash, skip bootstrap.ps1 and run bash mxcodr/install.sh from the project folder.

What lands in the project, and who reads it

.claude/skills/<name>/       Claude Code
.agents/skills/<name>/       Codex, and other tools on the open SKILL.md standard
.ai-context/skills/<name>/   mxcli, Cursor, OpenCode, Windsurf, Aider
.claude/rules/               the always-loaded rule (Cursor's copy in .cursor/rules/)
.claude/lint-rules/          found by `mxcli lint` with nothing to register
tools/mdl-checks/            the Python checkers the skills cite
tests/                       the harness scripts, plus tests/harness.env
.claude/settings.local.json  the hooks (Cursor, Codex and OpenCode get their own)

Three copies of the same skills, because each tool looks somewhere different. All of it is discovered — nothing here needs registering, importing or configuring.

The five harness scripts are replaced on every install: a fix in gate.sh that never reaches an installed project is not a fix. Your own verify-*.test.sh and credentials.env are never overwritten.

The gate

One command, five checks, run concurrently — the browser suite, mx check, mxcli lint, test coverage and naming/captions. Every step runs even when another fails, so one call reports the whole picture. Exit 0 only when all five pass.

== gate
   tests: Total: 12  Passed: 12  Failed: 0  Time: 2m14s
   mx check: 0 errors
   lint: 59 issues: 0 errors, 24 warnings, 35 info
   coverage InvoiceDesk: PASS  14/14 elements covered by 12 test script(s)
   naming: PASS  0 failure(s) over 246 lines
   DONE — every check passed

The agent runs this. The installed hooks run it too, and refuse to let Codex or Cursor finish a turn while it is red. When you want to look yourself:

bash tests/gate.sh                    # the done gate
bash tests/gate.sh --boot-if-needed   # boot the app first if nothing answers
bash tests/gate.sh --only <feature>   # one test, warm browser, red loop
bash tests/orient.sh                  # what is in this project
bash tests/diagnose.sh                # why is the app not answering

Configuration

tests/harness.env is written by the installer and read by every harness script. The environment still wins, so any of it can be overridden for one run.

Key What it is
MDL_MXBUILD_PATH the Studio Pro or cached mxbuild mx check runs
MDL_DB_HOST / _NAME / _USER / _PASSWORD the database
JAVA_HOME a JDK on a path with no spaces (see below)
MDL_BOOT_COMMAND how the gate boots the app when nothing answers

Windows: what the installer repairs, and what it cannot

Four things stand between a Windows machine and a running Mendix app, and none of them reports itself usefully. The installer fixes three, without being asked.

Symptom if unfixed
A JDK on a path with spaces mxbuild splits its own command line, so C:\Program Files (Arm)\zulu21 arrives as four unrecognised arguments and it exits printing usage
No Gradle in the mxbuild cache No supported Gradle installation found, raised after mxbuild is already answering, so it reads as a model problem
ARM Studio Pro ships win-arm64 tools only mxbuild launches win-x64 and dies with Win32Exception (2) before it listens

Junctions, so nothing is copied and no administrator rights are needed.

The fourth cannot be fixed from outside mxcli. Its liveness probe is os.Process.Signal(0), and Windows rejects every signal except Kill — so a perfectly healthy mxbuild and a perfectly healthy runtime both read as "exited during startup" on the first poll. This is not an ARM quirk; no Windows machine can boot an app with mxcli run --local.

The harness works around it for booting: the installer writes MDL_BOOT_COMMAND="bash tests/run-app.sh", which drives mxbuild and the standalone runtime over the M2EE admin API instead. gate.sh --boot-if-needed then works.

There is no equivalent for mxcli test --local, which boots the app itself. Microflow tests need a patched mxcli on Windows until the fix is upstream.

Two more Windows notes

Ports. Studio Pro running an app holds 8080 and 8090. The harness defaults to 8081, which still collides on the admin port. Pass APP_PORT / ADMIN_PORT if you are running both at once.

Screenshots need playwright (the npm package), not playwright-cli (the session tool mxcli playwright drives). Having only the second is what makes Playwright look installed while mxcli run --local --screenshot does nothing. Its Chromium is a separate download, pinned per package, so one tool's browser does not satisfy the other.

If a test run fails partway, check AfterStartupMicroflow

mxcli test points the project's after-startup microflow at its own injected MxTest.RegisterEndpoint while tests run. A run that dies before cleanup leaves it there, overwriting whatever the app had — with no record of the old value. The next run then fails somewhere else entirely, because it reads the leftover as your setting.

./mxcli -p <app>.mpr -c 'SHOW SETTINGS'     # look at AfterStartup
./mxcli -p <app>.mpr -c "ALTER SETTINGS MODEL AfterStartupMicroflow = 'Module.Microflow'"

mxcli does warn that the project was left modified. It does not say what the value was, so note it before running tests against a project you care about.

Rebuilding the bundle

mxcodr/ is a copy of files that live in the harness repo — mxcodr/README.md has the table of which file comes from where. Edit it there, not here.

About

No description, website, or topics provided.

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages