|
| 1 | +# Proposal: Version-Aware Agent Support |
| 2 | + |
| 3 | +**Status:** Draft |
| 4 | +**Date:** 2026-04-02 |
| 5 | + |
| 6 | +## Problem Statement |
| 7 | + |
| 8 | +Three use cases require mxcli to be version-aware at the MDL level: |
| 9 | + |
| 10 | +1. **Generate**: An AI coding agent creates MDL for a Mendix project but doesn't know which features are available in the project's version. It writes `CREATE VIEW ENTITY` for a 9.x project and gets a cryptic BSON error. |
| 11 | + |
| 12 | +2. **Validate**: A user runs an MDL script that uses 11.0+ syntax on a 10.24 project. The script executes, writes corrupt BSON, and the error only surfaces when Studio Pro tries to open the project. |
| 13 | + |
| 14 | +3. **Upgrade**: A customer wants to migrate from 10.24 to 11.6 and leverage new capabilities. They need to know what patterns can be modernized and what new features become available. |
| 15 | + |
| 16 | +Today, version knowledge is scattered across: |
| 17 | +- `sdk/mpr/version/version.go` (6 hardcoded features) |
| 18 | +- Comments in MDL example scripts (`-- @version: 11.0+`) |
| 19 | +- CLAUDE.md documentation (prose, not machine-readable) |
| 20 | +- Implicit knowledge in the BSON writers (version-conditional serialization) |
| 21 | + |
| 22 | +There is no way for an agent or user to **query** what's available, no **pre-flight check** before writing, and no **upgrade advisor** for migration. |
| 23 | + |
| 24 | +## Design Principles |
| 25 | + |
| 26 | +1. **Single source of truth** -- One structured data format defines version capabilities. Everything else reads from it. |
| 27 | +2. **Machine-readable first** -- An AI agent should be able to query capabilities, not read prose. |
| 28 | +3. **Queryable at runtime** -- `SHOW FEATURES` returns capabilities for the connected project's version. |
| 29 | +4. **Fail-fast with actionable messages** -- Error before writing BSON, not after Studio Pro crashes. |
| 30 | +5. **Incremental updates** -- Adding a new version's capabilities should be a data change, not a code change. |
| 31 | +6. **Reuse existing infrastructure** -- Linter rules, skills, executor commands follow established patterns. |
| 32 | + |
| 33 | +## Architecture |
| 34 | + |
| 35 | +``` |
| 36 | + Version Feature Registry |
| 37 | + (sdk/versions/*.yaml) |
| 38 | + | |
| 39 | + +--------------+--------------+ |
| 40 | + | | | |
| 41 | + SHOW FEATURES Executor Linter |
| 42 | + (MDL command) Pre-checks Rules (VER0xx) |
| 43 | + | | | |
| 44 | + v v v |
| 45 | + Agent queries Error before Upgrade |
| 46 | + capabilities BSON write recommendations |
| 47 | +``` |
| 48 | + |
| 49 | +### Layer 1: Version Feature Registry |
| 50 | + |
| 51 | +A structured YAML file per major version, embedded via `go:embed`: |
| 52 | + |
| 53 | +``` |
| 54 | +sdk/versions/ |
| 55 | + mendix-9.yaml |
| 56 | + mendix-10.yaml |
| 57 | + mendix-11.yaml |
| 58 | +``` |
| 59 | + |
| 60 | +Each file defines features, their introduction version, syntax, deprecations, and upgrade hints: |
| 61 | + |
| 62 | +```yaml |
| 63 | +# sdk/versions/mendix-10.yaml |
| 64 | +major: 10 |
| 65 | +supported_range: "10.0..10.24" |
| 66 | +lts_versions: ["10.24"] |
| 67 | +mts_versions: ["10.6", "10.12", "10.18"] |
| 68 | + |
| 69 | +features: |
| 70 | + domain_model: |
| 71 | + entities: |
| 72 | + introduced: "10.0" |
| 73 | + mdl: "CREATE PERSISTENT ENTITY Module.Name (...)" |
| 74 | + view_entities: |
| 75 | + introduced: "10.18" |
| 76 | + mdl: "CREATE VIEW ENTITY Module.Name (...) AS SELECT ..." |
| 77 | + notes: "OQL stored inline on OqlViewEntitySource (Oql field)" |
| 78 | + calculated_attributes: |
| 79 | + introduced: "10.0" |
| 80 | + mdl: "CALCULATED BY Module.Microflow" |
| 81 | + entity_generalization: |
| 82 | + introduced: "10.0" |
| 83 | + mdl: "EXTENDS Module.ParentEntity" |
| 84 | + |
| 85 | + microflows: |
| 86 | + basic: |
| 87 | + introduced: "10.0" |
| 88 | + show_page_with_params: |
| 89 | + introduced: null |
| 90 | + available_in: "11.0+" |
| 91 | + workaround: "Pass data via a non-persistent entity or microflow parameter" |
| 92 | + send_rest_request: |
| 93 | + introduced: "10.1" |
| 94 | + notes: "Query parameters require 11.0+" |
| 95 | + |
| 96 | + pages: |
| 97 | + page_parameters: |
| 98 | + introduced: null |
| 99 | + available_in: "11.0+" |
| 100 | + pluggable_widgets: |
| 101 | + introduced: "10.0" |
| 102 | + widgets: |
| 103 | + - ComboBox |
| 104 | + - DataGrid2 |
| 105 | + - Gallery |
| 106 | + - Image |
| 107 | + notes: "Widget templates are version-specific; MPK augmentation handles drift" |
| 108 | + design_properties_v3: |
| 109 | + introduced: null |
| 110 | + available_in: "11.0+" |
| 111 | + notes: "Atlas v3 design properties (Card style, Disable row wrap)" |
| 112 | + |
| 113 | + security: |
| 114 | + module_roles: |
| 115 | + introduced: "10.0" |
| 116 | + demo_users: |
| 117 | + introduced: "10.0" |
| 118 | + |
| 119 | + integration: |
| 120 | + rest_client: |
| 121 | + introduced: "10.1" |
| 122 | + notes: "Full BSON format requires 11.0+" |
| 123 | + database_connector: |
| 124 | + introduced: "10.6" |
| 125 | + notes: "EXECUTE DATABASE QUERY BSON format requires 11.0+" |
| 126 | + business_events: |
| 127 | + introduced: "10.0" |
| 128 | + |
| 129 | + workflows: |
| 130 | + basic: |
| 131 | + introduced: null |
| 132 | + available_in: "9.0+" |
| 133 | + |
| 134 | +deprecated: |
| 135 | + - id: "DEP001" |
| 136 | + pattern: "Persistable: false on view entities" |
| 137 | + replaced_by: "Persistable: true (auto-set)" |
| 138 | + since: "10.18" |
| 139 | + severity: "info" |
| 140 | + |
| 141 | +upgrade_opportunities: |
| 142 | + from_10_to_11: |
| 143 | + - feature: "page_parameters" |
| 144 | + description: "Replace non-persistent entity parameter passing with direct page parameters" |
| 145 | + effort: "low" |
| 146 | + - feature: "design_properties_v3" |
| 147 | + description: "Atlas v3 design properties available for richer styling" |
| 148 | + effort: "low" |
| 149 | + - feature: "association_storage" |
| 150 | + description: "New association storage format (automatic on project upgrade)" |
| 151 | + effort: "none" |
| 152 | +``` |
| 153 | +
|
| 154 | +### Layer 2: MDL Commands |
| 155 | +
|
| 156 | +#### `SHOW FEATURES` |
| 157 | + |
| 158 | +Lists all features available for the connected project's Mendix version: |
| 159 | + |
| 160 | +```sql |
| 161 | +SHOW FEATURES; |
| 162 | +``` |
| 163 | + |
| 164 | +Output: |
| 165 | +``` |
| 166 | +| Feature | Available | Since | Notes | |
| 167 | +|------------------------|-----------|--------|------------------------------------------| |
| 168 | +| Persistent entities | Yes | 10.0 | | |
| 169 | +| View entities | Yes | 10.18 | OQL stored inline on source object | |
| 170 | +| Page parameters | No | 11.0+ | Use non-persistent entity workaround | |
| 171 | +| Pluggable widgets | Yes | 10.0 | ComboBox, DataGrid2, Gallery, Image | |
| 172 | +| Design properties v3 | No | 11.0+ | Atlas v3 required | |
| 173 | +| REST client | Partial | 10.1 | Query parameters require 11.0+ | |
| 174 | +| Database connector | Partial | 10.6 | EXECUTE DATABASE QUERY requires 11.0+ | |
| 175 | +| Business events | Yes | 10.0 | | |
| 176 | +| Workflows | Yes | 9.0 | | |
| 177 | +``` |
| 178 | + |
| 179 | +#### `SHOW FEATURES ADDED SINCE <version>` |
| 180 | + |
| 181 | +Shows what becomes available when upgrading: |
| 182 | + |
| 183 | +```sql |
| 184 | +SHOW FEATURES ADDED SINCE 10.24; |
| 185 | +``` |
| 186 | + |
| 187 | +Output: |
| 188 | +``` |
| 189 | +| Feature | Available In | Description | Effort | |
| 190 | +|----------------------|-------------|------------------------------------------|--------| |
| 191 | +| Page parameters | 11.0 | Direct page parameter passing | Low | |
| 192 | +| Design properties v3 | 11.0 | Atlas v3 Card style, Disable row wrap | Low | |
| 193 | +| REST query params | 11.0 | Query parameter support in REST clients | Low | |
| 194 | +| Portable app format | 11.6 | New deployment format | None | |
| 195 | +``` |
| 196 | + |
| 197 | +#### `SHOW DEPRECATED` |
| 198 | + |
| 199 | +Lists deprecated patterns in the current project: |
| 200 | + |
| 201 | +```sql |
| 202 | +SHOW DEPRECATED; |
| 203 | +``` |
| 204 | + |
| 205 | +### Layer 3: Executor Pre-Checks |
| 206 | + |
| 207 | +Before writing BSON, the executor checks version compatibility and produces actionable errors: |
| 208 | + |
| 209 | +```go |
| 210 | +// In cmd_entities.go, before creating a view entity: |
| 211 | +if s.IsViewEntity { |
| 212 | + pv := e.reader.ProjectVersion() |
| 213 | + if !pv.IsAtLeast(10, 18) { |
| 214 | + return fmt.Errorf( |
| 215 | + "CREATE VIEW ENTITY requires Mendix 10.18+ (project is %s)\n"+ |
| 216 | + " hint: upgrade your project or use a regular entity with a microflow data source", |
| 217 | + pv.ProductVersion, |
| 218 | + ) |
| 219 | + } |
| 220 | +} |
| 221 | +``` |
| 222 | + |
| 223 | +This pattern already exists informally in the codebase (version-conditional BSON writing). The proposal formalizes it with: |
| 224 | + |
| 225 | +1. A `CheckFeature(feature, version)` function that returns a user-friendly error |
| 226 | +2. Pre-checks at the start of each executor command |
| 227 | +3. Consistent error format with hints |
| 228 | + |
| 229 | +### Layer 4: Linter Rules (VER prefix) |
| 230 | + |
| 231 | +New linter rule category `VER` for version-related checks: |
| 232 | + |
| 233 | +| Rule | Name | Description | |
| 234 | +|------|------|-------------| |
| 235 | +| VER001 | UnsupportedFeature | Feature used that's not available in project version | |
| 236 | +| VER002 | DeprecatedPattern | Deprecated pattern that has a modern replacement | |
| 237 | +| VER003 | UpgradeOpportunity | Pattern that can be simplified on a newer version | |
| 238 | + |
| 239 | +**VER001** runs during `mxcli check` and `mxcli lint`: |
| 240 | +``` |
| 241 | +[VER001] CREATE VIEW ENTITY requires Mendix 10.18+ (project is 10.12.0) |
| 242 | + at line 42 in script.mdl |
| 243 | + hint: upgrade to 10.18+ or use a microflow data source |
| 244 | +``` |
| 245 | +
|
| 246 | +**VER003** runs during `mxcli lint --upgrade-hints`: |
| 247 | +``` |
| 248 | +[VER003] Page MyModule.EditCustomer uses non-persistent entity for parameter passing |
| 249 | + This pattern can be replaced with page parameters in Mendix 11.0+ |
| 250 | + effort: low |
| 251 | +``` |
| 252 | +
|
| 253 | +### Layer 5: Skills (AI Agent Guidance) |
| 254 | +
|
| 255 | +One skill file: `.claude/skills/version-awareness.md` |
| 256 | +
|
| 257 | +```markdown |
| 258 | +# Version Awareness |
| 259 | +
|
| 260 | +## Before Generating MDL |
| 261 | +
|
| 262 | +Always check the project's Mendix version before writing MDL: |
| 263 | +
|
| 264 | + SHOW STATUS; -- shows connected project version |
| 265 | + SHOW FEATURES; -- shows available features |
| 266 | +
|
| 267 | +## Version-Conditional Patterns |
| 268 | +
|
| 269 | +If a feature is not available, use the documented workaround: |
| 270 | +
|
| 271 | + SHOW FEATURES WHERE name = 'page_parameters'; |
| 272 | + -- If not available, use non-persistent entity pattern instead |
| 273 | +
|
| 274 | +## Upgrade Workflow |
| 275 | +
|
| 276 | +When migrating to a newer version: |
| 277 | +
|
| 278 | + SHOW FEATURES ADDED SINCE 10.24; -- what's new |
| 279 | + SHOW DEPRECATED; -- what to update |
| 280 | + mxcli lint --upgrade-hints -p app.mpr -- automated suggestions |
| 281 | +``` |
| 282 | + |
| 283 | +This skill is small and stable -- it teaches the agent to **query** mxcli rather than embedding version knowledge in the skill itself. The version data lives in the registry. |
| 284 | + |
| 285 | +### Layer 6: Keeping Data Current |
| 286 | + |
| 287 | +The version registry needs updates when Mendix releases new versions. Proposed pipeline: |
| 288 | + |
| 289 | +1. **Automated**: `mxcli diff-schemas 11.5 11.6` compares reflection data between versions, outputs added/removed types and properties as a diff report. |
| 290 | + |
| 291 | +2. **Semi-automated**: An agent reads the diff report + Mendix release notes and proposes updates to the YAML registry. Human reviews and merges. |
| 292 | + |
| 293 | +3. **On-demand**: `mxcli update-features` downloads the latest registry from a central source (GitHub release asset), similar to how `mxcli setup mxbuild` downloads tooling. |
| 294 | + |
| 295 | +4. **Community**: The `-- @version:` directives in MDL test scripts serve as executable documentation. If a test fails on a version, the directive gets updated — and that update feeds back into the registry. |
| 296 | + |
| 297 | +## Implementation Plan |
| 298 | + |
| 299 | +### Phase 1: Version Feature Registry + SHOW FEATURES (foundation) |
| 300 | + |
| 301 | +1. Create `sdk/versions/` package with YAML loader and `go:embed` |
| 302 | +2. Create YAML files for Mendix 9, 10, 11 (initial feature set from existing knowledge) |
| 303 | +3. Implement `SHOW FEATURES` command in executor |
| 304 | +4. Implement `SHOW FEATURES ADDED SINCE <version>` variant |
| 305 | +5. Wire into AST/grammar: add `FEATURES` keyword to MDLParser.g4 |
| 306 | + |
| 307 | +**Deliverable**: Agent can query `SHOW FEATURES` and get machine-readable output. |
| 308 | + |
| 309 | +### Phase 2: Executor Pre-Checks (fail-fast) |
| 310 | + |
| 311 | +1. Add `CheckFeatureAvailable(feature string)` method to Executor |
| 312 | +2. Add version checks to CREATE VIEW ENTITY, CREATE REST CLIENT, CREATE PAGE (with Params), EXECUTE DATABASE QUERY |
| 313 | +3. Produce error messages with version requirement, current version, and workaround hint |
| 314 | +4. Test: run MDL scripts with version-gated features on older projects |
| 315 | + |
| 316 | +**Deliverable**: Unsupported features fail immediately with actionable error instead of corrupting BSON. |
| 317 | + |
| 318 | +### Phase 3: Linter Rules (VER category) |
| 319 | + |
| 320 | +1. Implement VER001 (UnsupportedFeature) -- reads from version registry |
| 321 | +2. Implement VER002 (DeprecatedPattern) -- reads deprecated list from registry |
| 322 | +3. Wire into `mxcli lint` and `mxcli check` |
| 323 | +4. Add SARIF output support for CI integration |
| 324 | + |
| 325 | +**Deliverable**: `mxcli lint -p app.mpr` reports version issues. |
| 326 | + |
| 327 | +### Phase 4: Upgrade Advisor |
| 328 | + |
| 329 | +1. Implement VER003 (UpgradeOpportunity) linter rule |
| 330 | +2. Implement `SHOW DEPRECATED` command |
| 331 | +3. Implement `SHOW FEATURES ADDED SINCE` with effort estimates |
| 332 | +4. Implement `mxcli lint --upgrade-hints --target-version 11.6` |
| 333 | + |
| 334 | +**Deliverable**: Migration planning from any version to any newer version. |
| 335 | + |
| 336 | +### Phase 5: Skills + Agent Integration |
| 337 | + |
| 338 | +1. Create `.claude/skills/version-awareness.md` |
| 339 | +2. Update `.claude/skills/check-syntax.md` to include version pre-check |
| 340 | +3. Update `mxcli init` to include version-awareness skill in project setup |
| 341 | +4. Test: AI agent generates valid MDL for both 10.24 and 11.6 projects |
| 342 | + |
| 343 | +**Deliverable**: AI agents automatically adapt to project version. |
| 344 | + |
| 345 | +### Phase 6: Automated Registry Updates |
| 346 | + |
| 347 | +1. Implement `mxcli diff-schemas <from> <to>` using reflection data |
| 348 | +2. Create agent workflow: diff-schemas output + release notes -> YAML update PR |
| 349 | +3. Implement `mxcli update-features` for on-demand downloads |
| 350 | +4. Add to nightly CI: verify registry matches reflection data |
| 351 | + |
| 352 | +**Deliverable**: Registry stays current with minimal manual effort. |
| 353 | + |
| 354 | +## Relationship to BSON Schema Registry Proposal |
| 355 | + |
| 356 | +This proposal complements `BSON_SCHEMA_REGISTRY_PROPOSAL.md`: |
| 357 | + |
| 358 | +- **Schema Registry** handles **structural** version differences (field names, defaults, encoding) at the BSON level |
| 359 | +- **This proposal** handles **feature-level** version differences (what MDL commands are available) at the user/agent level |
| 360 | + |
| 361 | +The version feature registry (YAML) is simpler and more immediately useful than the full schema registry. It can be built first and later integrated with the schema registry as that matures. |
| 362 | + |
| 363 | +``` |
| 364 | +User/Agent Layer This Proposal "What can I do?" |
| 365 | + | |
| 366 | +MDL Layer Executor pre-checks "Will this work?" |
| 367 | + | |
| 368 | +BSON Layer Schema Registry "How do I serialize this?" |
| 369 | +``` |
| 370 | + |
| 371 | +## Open Questions |
| 372 | + |
| 373 | +1. **YAML vs JSON for registry?** YAML is more readable for humans editing it; JSON is easier to parse. Could use YAML as source, compile to embedded JSON at build time. |
| 374 | + |
| 375 | +2. **Granularity of features?** Per-statement (`CREATE VIEW ENTITY`), per-property (`Params:` on pages), or per-concept (`view_entities`)? Probably per-concept with per-property notes. |
| 376 | + |
| 377 | +3. **Should SHOW FEATURES work without a connected project?** Could accept `SHOW FEATURES FOR VERSION 10.24` without needing an MPR file. Useful for planning. |
| 378 | + |
| 379 | +4. **How to handle patch-level differences?** Most changes are at the minor level, but some patch releases introduce fixes. Use minor as the default, with patch-level overrides where needed. |
| 380 | + |
| 381 | +5. **Should the upgrade advisor be interactive?** E.g., `mxcli upgrade --from 10.24 --to 11.6 --dry-run` that shows a migration plan and optionally applies changes. |
0 commit comments