Skip to content

Choose a tag to compare

@MendixMau MendixMau released this 19 Oct 10:09
· 74 commits to master since this release

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.sh now 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.md now 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 BUILD row 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 through bin/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, and bin/status.sh shows
    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.sh ran 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.sh took 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.md now 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 Unit row of the module brief's Test plan to yes and name why: | Unit (.test.mdl) | yes | <the calculation, mapping, Java or REST logic, or the fixed bug> | architecture/modules/<Module>/module-brief.md, skills/module-brief.md
What runs at each moment ## Test strategy table, offered at CAC-5 (architecture and offer, before the build). Status CONFIRMED, or ASSUMED in auto mode. Change any cell in your answer to the offer PROJECT.md, checkpoint-build.md
Everything, now Say "run everything". The full suite runs once on request in chat
Which flows get a unit test List them in the module brief as Unit flows:, one - ACT_X: reason line each. A list wins for its module even under Unit tests default: yes architecture/modules/<Module>/module-brief.md
Per-change test selection depth ./bin/affected-tests.sh <script> --depth N, or MXTK_AFFECTED_DEPTH (default 1) shell
Context packs Context packs: on (default), no-brain or off; MXTK_CONTEXT_PACKS for one command PROJECT.md
When the progress report is written Progress report: off | ask | auto, default ask. off never writes the page; ask and auto set whether the agent asks first or opens it at a stage gate or module close (#434) PROJECT.md
Ask before each exec bin/exec-approval.sh <project> --set auto (default) or --set ask; --clear removes it .mxtk/exec-approval, or Exec approval: in PROJECT.md
Claude Code permission prompts Permission profile: project (the default), wrappers or full, intake Q12; bin/permission-profile.sh <project> --set <profile> overrides it (#216) PROJECT.md, or .mxtk/permission-profile
Fewer or more questions bin/interview-mode.sh <project> --set steering|assist|auto Interview mode: in PROJECT.md
Keep sync from restoring the look-ledger hook Create the file .mxtk/no-hook-repair project root
Check staged files for real secret values bin/check-staged-secrets.sh (staged blobs) or --tree (everything tracked). Opt-in; not part of the pre-commit hook project
Install only some scripts on sync bin/sync-project.sh <project> --only-bin <script.sh> toolkit clone
Commit before an exec that needs a clean model bin/exec.sh --commit-first shell
Longer verify-module rungs on a big app VM_TMO_GRAPH, VM_TMO_COVERAGE, VM_TMO_JOURNEYS (defaults 300, 300, 900 seconds) shell
A lint rule off enabled: false under rules: in .claude/lint-config.yaml, recorded in PROJECT.md project

The test strategy and the unit default are two settings. The strategy says when a test set runs.
The unit default says whether unit tests exist in that set. affected selects from the tests
that exist and does not ask for new ones.

3. Context packs

A helper that builds one step of a module used to get a reading list. With context packs it gets
one file (#198). The module brief has a ### Build steps table, one row per dispatch: what the step
builds, which existing elements it reads, the app's own example to copy, and the mxcli brain
slice. bin/context-pack.sh <Module> <Step> turns that row into a pack made of the folder from
the brief's folder plan, the why from mxcli brain brief, the brief's architecture constraints,
and a live DESCRIBE of every element the step reads, of the example, and of anything it
changes. The pack also lists the rule files the step must read, the attributes a TEXTBOX
cannot bind on a page step (mxcli check passes them, mx check fails with CE2421), and the
mxcli impact list when the step changes an existing element. The pack is regenerated per
dispatch and never committed.

Why it helps, as measured. On a real app's scratch copy, 3 helper runs with a pack against 3
without, same brief and brain: about 40% fewer tool calls (13 against 21) and about 40% less
time (60 seconds against 101). The token saving is not proven: token counts were too noisy at
these run counts. Every run passed
mxcli check and executed with no new mx errors. Page steps with the later pack used about 25%
fewer tool calls and about 30% less time (n=2 each, too few runs to quote tokens).

The switch. Context packs: on | no-brain | off in PROJECT.md, default on.
no-brain leaves out the mxcli brain section. off makes context-pack.sh exit 3 and the
dispatcher falls back to the reading list in iterative-build-loop.md, so a CLI change that
breaks DESCRIBE or brain brief is switched off with one line in PROJECT.md.

Older briefs. A module brief with no ### Build steps table, written before packs existed,
also exits 3 and falls back to the reading list (#202). A project mid-build keeps going after a pull
without retrofitting its briefs.

4. Everything else

Reports and visibility

  • One progress report replaces build-plan.html. architecture/progress-report.html is a
    single self-contained page. It keeps what the old page showed (phases, built and proven) and
    adds stages P to 6 with links to their artifacts, a progress bar and a stage nav
    (#434).
    • Session logs are optional. Without one, time and token data are marked unavailable. With a
      Claude Code session log it adds time per stage, sub-agent use, context size and an estimated
      token and cost figure.
    • A session cache makes a refresh take about a second.
    • Autoreload keeps your scroll position, and only runs while a build is active.
    • Tips sit in a side column, grouped by theme and collapsed by default, with calm severity.
    • An old build-plan.html is still accepted and never deleted.
    • When no session log is found, the page shows one calm line, and the details sit under "How
      this was measured"
      (#454).
    • A plan row marked "done " counts as built, both in the card and in the plan table
      (#454).
    • A sign-off placeholder that is still unfilled on a later stage shows PENDING instead of FAIL
      (#454).
    • Every plan State the build-plan skill lists (built, partial, not built, blocked) reads the same
      in the phase card, the plan header and the phase badge. Partial rows show the phase as in
      progress, and blocked rows count as not built
      (#456).
    • The full plan tables (one per phase, plus views A and B) sit in one closed fold below the
      phase cards, so a large plan no longer pushes the rest of the report off screen
      (#457).
  • build-plan.json stays current. build-plan-status.sh --refresh updates an existing
    build-plan.json, so a day of building no longer reads as 0 built
    (#437).
  • A bug log you can file safely. docs/bugs.jsonl per project and bin/file-bugs.sh, which
    redacts every title and body, searches for duplicates, and posts only after you confirm each
    bug at a terminal (#433).
  • Studio Pro History shows CLI commits. History reads a git note that Studio Pro writes, and
    the toolkit told CLI pushes to write an empty one, so a field project showed "Model changes 0"
    for 270 of 270 commits. A post-commit hook now writes the note from the changed units, and
    mx-metadata-note.py sync publishes it
    (#271).
  • A build metrics ledger. Every exec.sh run adds a row to
    .claude/loop/metrics-ledger.tsv: outcome, time, mxbuild errors, lint total and the
    mxcli report score. metrics-trend.sh summarises it. The score costs about 7 seconds after a
    clean mxbuild, and MXTK_NO_SCORE=1 skips it
    (#265).
  • Change requests stay visible. A change request updates the module brief and shows as
    "waiting" at session start and module close until it is built
    (#430).

Process map and BRD report

  • Process map. One swimlane map per business process, each step on its wireframe once
    screens exist, every open question and ASSUMED decision pinned to the step it is about. It is
    drawn twice: a draft at Stage 2 close (shown at CAC-3) and the full map at Stage 3. In its
    field run the map placed all 102 pinnable items, 19 of them under the whole app and none
    unplaced (#429).
  • BRD report with the map on top. The Stage 2 report opens with the process map and lists
    requirements and open questions under it, each tied to its step. A click on a step filters the
    list, and what no step covers stays under "whole app". open-questions.html is retired, and
    the Stage 3 prototype and the map link to each other
    (#438).
  • Follow-ups. Migrating an old anchors file no longer trusts a regex: it checks what changed,
    says what it did, accepts a string targets, and lists unfilled entries instead of dropping
    them (#453).
  • The map counts only what is still open. Answered questions show their answer, an assumption
    the owner agreed to has its own colour, and CONFIRMED decisions from the project register,
    which the map used to leave out, are listed as decided. An "Open only" filter hides the settled
    items. A field map had said "50 open questions" when every one was answered or assumed with the
    owner's consent (#465).

Skills learned

  • rest-between-mendix-apps: for two or more Mendix apps that read each other over REST. A
    contract to write down before the first script, 17 publisher and consumer rules, and a
    six-rung cross-app test ladder
    (#273).
  • demo-recording-polish: 60 fps capture, a drawn cursor with a click ripple, eased scroll,
    and a zoom rendered after the take, so re-framing re-renders the same take
    (#404).
  • Workflow notes: a Jump has one fixed target, so one failure handler for several steps is a
    child workflow; three probed build errors; workflow seed reset
    (#415).
  • Skill trims. Five skill findings (detection gaps, date tokens, Atlas selectors, grants for
    the default home page, CSS traps) landed as compact rows paid for by trimming provenance
    prose, so the always-loaded total went from 75,225 to 75,204 words
    (#422).
  • load-test: load test a page without correlating Mendix's client protocol by hand.
    Playwright records the real /xas/ calls, a probe maps each opaque runtimeOperation to its
    microflow through Jaeger, and the chosen call is replayed with the session's own cookie and
    CSRF token. It lists eleven field traps and a four-line report that says what the run does not
    prove. One of them: a local runtime without a licence allows 6 concurrent sessions and stops
    after 2 to 4 hours, so a run above 6 users on a trial fails for licence reasons. No instrument
    ships yet, only the skill
    (#431, #439).
  • unit-test: how to write and run a microflow unit test whose assertion is live: what is
    worth a test and what is not, equality-only @expect, a positive control that must fail, and a
    four-line report. Whether and when unit tests run stays with the project's test strategy
    (#432).
  • learned-multilingual-app: a second language is four decisions the translations never see: source
    language, enabled languages, the user's starting language, and a switch a normal role can use.
    A field run wrote 418 strings per language correctly and the language picker still failed with
    every check green. The skill gives the recipe and the traps
    (#449, from #387 by CarlesZ).
  • Five legacy-widget field notes from an existing-app rebuild went to the inbox for triage
    (first proposed as #309, landed
    as #450, thanks to AlvinnYeo).
  • Decompose and rehost. Three on-demand skills for working from an existing Mendix app:
    decompose-app (split a monolith into several apps, choosing the cut on business fit and
    coupling), rehost-app (regenerate a whole .mpr into a fresh app with pipelines/mendix-mpr/
    and read the fidelity ledger) and mendix-service-seam (OData and REST patterns between two
    Mendix apps). bin/cut-score.sh scores a proposed split and prints a clean, costly or blocked
    verdict per partition, and bin/cut-ledger.sh writes one row per crossing edge and exits 1
    while any edge has no resolution
    (#341, #342, #345, #346).
  • mxpatch and the hash check. project-bin/mxpatch.py is a shared patch core that finds a
    unit or element, changes a value and writes the unit and its .mpr ContentsHash in one step.
    exec.sh --patch now runs mxcli fix hashes before and after the script, so the two shipped
    workflow patchers no longer leave a stale hash
    (#374, from jopterhorst).

Fixes

  • The gate no longer races a running app. mxbuild and a live mxcli run --local --watch both
    write deployment/. In a field project 17 of 27 failed gates were "gate could not run", against
    0 of 22 gates in copies without the watcher. The gate now pauses this project's own watcher (never
    another project's, a copy or a worktree) while mxbuild runs and resumes it right after, also on
    the next exec.sh if a run was killed. A gate whose mxbuild exits 1 or 3 with no error code and an
    empty error file is retried once (#451).
  • A failed gate keeps its evidence. The full mxbuild output of a gate that did not pass is
    written to .mpr-snapshots/.mxbuild-logs/, both attempts when it retried, and the BUILD-LOG row
    names the file. The newest 30 are kept; a gate that passes on the first try writes nothing
    (#452).
  • A crashed mxbuild rolls the write back. When a baseline was measured and mxbuild then
    exits non-zero without an error list, exec.sh restores the snapshot and logs one row, instead
    of keeping a model nothing can load
    (#424).
  • Lint no longer goes blind after a context compaction. mxcli's session-start hook rewrites
    its bundled lint rules on every compaction and subagent start, which put stock rules back over the
    toolkit's and left exec.sh reporting LINT BLIND for the rest of a Stage 5. exec.sh now
    restores the toolkit rules itself and lints again; a rule you edited by hand is left as it is, or
    kept as a backup copy when its toolkit header is gone, and
    MXTK_NO_LINT_RESTORE=1 keeps the old behaviour
    (#463).
  • Windows: Git Bash paths and the progress report's figures. Scripts that hand a list of paths
    to Python now convert Git Bash paths (/c/...) first, so the BRD and extraction reports and the
    facts lock no longer lose the second and later paths on Windows. The progress report now finds a
    Windows project's own Claude Code log: on a real Windows run it counted 2 sessions and 51
    sub-agents where the release before this fix found 1 session and 0 sub-agents, so its cost
    figure was far too low
    (#462).
  • Doctor on Windows ARM64 installs the ARM64 mxcli build instead of the x64 one, and the docs
    say --install needs --yes when no terminal is attached
    (#464).
  • Sync keeps your .claude/settings.json rules. A re-wire runs mxcli init, which
    overwrites that file. wire-agents.sh now merges: your entries win and keep their order, and
    entries only the new file has are appended
    (#421).
  • The macOS sync fix. The exec-approval rewrite failed on stock macOS awk while sync printed
    "Rewrote" on every run. It now works there and prints a WARN: when a rewrite fails
    (#427).
  • The right JDK for your Mendix version. find_java asks for JDK 25 on Mendix 11.14 and
    newer, JDK 21 otherwise, and a warning names a missing JDK
    (#410). It adds about 45 ms
    per exec when JAVA_HOME is unset.
  • The look-ledger hook comes back. A project whose .claude/settings.json lost the
    look-ledger hook (so the ledger read 0 of 31 pages seen with 22 screenshots on disk) gets it
    restored by sync, and doctor.sh warns. Opt out with .mxtk/no-hook-repair
    (#414).
  • A staged-secrets check. check-staged-secrets.sh compares your project's real secret
    values against staged blobs and prints the file and key name, never the value. On a synthetic
    6,000-file repo, 230 staged files take 1.0 seconds and a whole-tree scan 2.6
    (#411).
  • exec.sh locks per project, offers --commit-first, ends every applied script with a
    restart verdict, and bin/app-restart.sh restarts only this project's own run --local
    (#304,
    #324,
    #322). In a 20-task field run,
    57 of 148 exec.sh runs had applied nothing, and a different project's write had blocked
    another. A fixture runs 10 rounds of 12 contenders and asserts at most one lock holder.
  • Merges no longer need --no-verify. The doc numbering check examines only files a merge
    itself changes
    (#418).

Quality gates

  • Every merge is reviewed by someone who did not write it (MERGE, MERGE-AFTER-FIX or HOLD,
    on value, regression risk after sync, correctness and context cost). Nine PRs had merged on
    2026-10-13 without one (#316).
    Several fixes in this release came out of those reviews. Every PR now also states its cost in a
    five-row Impact block (docs/RELEASE-PROCESS.md §4a).
  • A missing navigation item fails the journey. navTo throws
    navigation item "<title>" not found instead of clicking nothing, so a control that must fail
    can no longer pass. Replayed on a five-app project, none of the 26 real journeys turned red and
    the 4 deliberately broken controls now fail
    (#412).
  • Lint you can trust and tune. UX001/002 and Batches 1 to 4, including SEC014 (an external
    role that can write status, audit or ownership members). When mxcli init reverts toolkit
    rules to stock, the lint gate stops as BLIND instead of blaming the next script
    (#238,
    #305,
    #308,
    #312).
  • A lint rise lists the new findings. lint-gate.sh printed the first three findings of a
    risen rule in model order, so it could not say which were new. It now prints the new ones, at
    most 3 per rule, with the rest in .claude/loop/lint-last.json. In the report that prompted it,
    3 findings were shown and 40 were new
    (#407).
  • End-to-end proof that fails for the right reason. The journey runner preflights the suite
    and journeys can declare requires, leaves and consumes. OQL rows are read by SELECT alias,
    an app that dies mid-suite reads APP-DOWN rather than FAIL
    (#302,
    #310,
    #319).
  • Themed palettes compare correctly. check-design-reaches-app.sh compares a design system
    whose palette lives in scoped blocks such as :root.theme-light block for block, and no longer
    warns "0 of N tokens carry the design's value" on a correct port
    (#423).
  • Stage 3 designs how users reach each page. design/interaction-model.md comes before the
    first wireframe: a home per role, an inbox per user task, and per page how it is reached and
    what it receives (#317).
  • Changing an existing app reports the delivery round from a ## Rounds table, logs
    mid-build feedback as a change-log row before any edit, and owes a final whole-app LOOK at
    Stage 6 (#326,
    #306,
    #303).

Known gaps

  • Field runs still owed. Fixtures pass, but no real-project run is cited yet for the
    property-set check, the page-fidelity rescoring, per-BRD conformance ledgers, the incremental
    app map, and the test strategy end to end (the A/B that compares a scripted change on a lab
    copy against master).
  • A defect a module-close full run used to catch may now surface only at the full run before
    deploy. That is the trade the test strategy makes.
  • #291 parts 2 and 3 (gate
    facts for the interaction model, and the model-side check) are not built.
  • affected-tests.sh in a multi-app folder over-reaches because module names can repeat
    across apps.
  • A lint rise stops the step even when the build is clean
    (#443). When any mxcli lint
    rule count goes above the project's baseline, exec.sh keeps the model change but exits 1 with
    LINT ROSE. In a growing app this happens often: fix the new findings, or accept them on purpose
    with bin/lint-gate.sh --update-baseline --reason "<why>". A softer exit is planned after 1.0.
  • Automatic time, token and cost figures need Claude Code logs. A project built with another
    agent (Codex CLI, GitHub Copilot, Cursor, Gemini CLI) still shows gates, stages, plan progress,
    module proof, bugs and the build times from the exec log, but no time per stage, tokens or
    cost, unless you keep them by hand in docs/progress/TIME-LEDGER.md. Reading Codex and Copilot
    CLI logs is planned after 1.0.
  • On Windows and Linux without Studio Pro, exec.sh skips its mxbuild gate unless mxbuild is
    found; run bin/doctor.sh --install <project> or set MXBUILD_PATH.
  • A Data grid 2 or a Gallery written by mxcli can fail mxbuild with CE0463 ("the definition of
    this widget has changed") although mxcli check passes it. Seen on a Data grid 2 with a column
    filter in a field run, and on a Gallery in an earlier one. exec.sh rolls the script back. Until
    mxcli fixes it, use a list view for that list, or open the page in Studio Pro and choose
    "Update widget".
  • The progress report trusts the build plan's State column. If the agent builds a row but does
    not mark it, the report shows it as not built.
  • A plain ASSUMED counts as "to confirm" until the owner's consent is recorded, also for
    decision rows in PROJECT.md.
  • Not yet run on Windows: Stage 6 (the test machine had no Docker), and the gate's watcher
    pause.

5. How to update

Pin the toolkit clone to the 1.0 tag v2026.10.19, then sync each project:

git -C ~/Mendix/mxcli-project-toolkit fetch --tags
git -C ~/Mendix/mxcli-project-toolkit checkout v2026.10.19
~/Mendix/mxcli-project-toolkit/bin/sync-project.sh <project-root> --repair-intake

The checkout is detached on purpose: a pinned clone stays on the tag. The session-start ritual
runs git pull --ff-only, which fails off a branch and warns that the clone is not on master;
that warning is expected. To unpin:
git -C ~/Mendix/mxcli-project-toolkit checkout master && git -C ~/Mendix/mxcli-project-toolkit pull.
Skills update with the checkout. Sync refreshes what was copied into the project and prints the
Toolkit release: you are on. --repair-intake is needed where the project predates the new intake questions: it appends the
questions older projects lack, numbered after the highest one present (Q13, unit tests default,
in a fresh project). An appended question must be answered, because an unanswered one fails the
Stage P gate. The README's plain update is git pull followed by
bin/sync-project.sh <project-root>; the pinned form above is the one for stability
(docs/RELEASE-PROCESS.md §8).

After updating:

  • Answer SEC014's question (which roles are external), then re-baseline lint once, as the sync
    NOTE says.
  • On mxcli v0.26 or later, sync runs a read-only property-set check. If it reports a repair is
    needed, run bin/doctor.sh --fix-property-sets <project>
    (#314).
  • Projects with per-BRD coverage ledgers: run conformance once; old rows are re-keyed
    (#307).
  • oqlScalar now returns the first SELECT alias. A journey that relied on navTo silently
    clicking a missing item now fails at the nav step.
  • If you installed the interview-gate hook earlier, re-run bin/install-claude-hooks.sh --full. The
    old copy in ~/.claude/hooks calls bin/questions-report.sh, which is removed, so it would write
    no report. bin/doctor.sh now warns when an installed hook copy calls a toolkit script that no
    longer exists, and names the fix: re-run bin/install-claude-hooks.sh --full
    (#455).
  • Sync adds /.claude/progress-report-sessions.txt to .gitignore; commit that line. An old
    build-plan.html and docs/open-questions.html are left in place and can be deleted. The line
    is now also added in a project checked out as a git worktree, and when the cache file is
    already tracked, sync and doctor print the git rm --cached command for it
    (#455).
  • PROJECT.md ## Test strategy is not written by sync. A project with no such section uses
    the printed defaults and says so.

If you cannot update today, paste this into your session:

Do not run mxcli test, unit tests or the full journey suite after individual fixes. After each
fix, run only the affected tests (./bin/affected-tests.sh <script>). Run the full suite once when the build is complete,
and again before each deploy.

Found something? See CONTRIBUTING.md. The bar is "it happened and you
wrote it down".

6. From here on: bundled releases, and we need you

Releases come in bundles. 1.0 is the first release cut this way, and the ones after it follow
the same shape. Work collects on a release branch while master stays stable. Then it ships
together as one tagged release with notes like these: what changed, what it means for your
project, how to update, and what is still a known gap. You update when a release lands, not on
every merge, and you can pin your clone to the tag (section 5) and move on your own schedule.

We need you to contribute. Every rule, gate and skill in this toolkit exists because a real
project hit a real wall and someone wrote it down. The four people thanked below shaped a large
part of this release that way. Whatever you learn on your own projects is what we build the next
release from: a bug, a workaround, a gate that went green on something broken, a question the
pipeline should have asked, or simply what felt slow or confusing. Every piece of learning and
feedback goes into a better foundation for your team and for every other team using the toolkit.

The bar is low on purpose: it happened and you wrote it down. Drop a note in contrib/inbox/,
run bin/harvest-learnings.sh <project-root> at the end of a project, or open an issue with the
Toolkit release: line bin/sync-project.sh prints. CONTRIBUTING.md
has the detail. Contributions are credited by name in CHANGELOG.md and in the release notes.

7. Thanks

A big thank you to the four people whose field work shaped this release:

  • Alvinn Yeo (@AlvinnYeo) sent the legacy-widget field notes that landed as
    #450, and earlier the lint stock-revert
    guard, the catalog edge guard, per-BRD conformance ledgers and the port-holder report
    (#313). The bug reports #259 to #264
    found gate and harness faults that only show on a real project.
  • Jop ter Horst (@jopterhorst) brought mxpatch and the hash check, mxcli fix property-sets in the
    upgrade path, delivery rounds, the incremental app map and token-burn rates
    (#374, field notes #294 to #301).
  • Carles (@CarlesZ) wrote up the multilingual app findings from a field run, now the
    learned-multilingual-app skill (#449).
  • Joshua Moesa (@joshuamoesa) filed nine precise reports (#356 to #361, #381 to #383): the journey
    screenshot names (#408), sync and
    install-manifest warnings, the test-agent journey path, the missing checkpoint files, and MDL
    learnings that are now STOP rows in the preflight.

Independent reviewers caught several defects before they shipped.