Skip to content

Commit 1ad450a

Browse files
akoclaude
andcommitted
style: convert MDL keywords to lowercase in docs and skill files
Applies the same lowercase convention to all code examples in documentation and skill files. Code blocks and inline backtick spans are converted; prose text is left unchanged. Keywords in qualified names (e.g. Module.Entity) are preserved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent dd85cb1 commit 1ad450a

200 files changed

Lines changed: 15975 additions & 15975 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/debug-bson.md

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ Use when encountering:
2525
### Step 1: Reproduce the Error
2626

2727
```bash
28-
# Create a page via MDL
28+
# create a page via MDL
2929
./bin/mxcli exec script.mdl -p /path/to/app.mpr
3030

31-
# Run mx check to get the error
31+
# run mx check to get the error
3232
reference/mxbuild/modeler/mx check /path/to/app.mpr
3333
```
3434

@@ -58,8 +58,8 @@ import json
5858
conn = sqlite3.connect('/path/to/app.mpr')
5959
cursor = conn.cursor()
6060

61-
# Find the document containing the widget
62-
cursor.execute("SELECT UnitData FROM Unit$ WHERE ContainmentName = 'Document' AND Name = ?", ('PageName',))
61+
# find the document containing the widget
62+
cursor.execute("select UnitData from Unit$ where ContainmentName = 'Document' and Name = ?", ('PageName',))
6363
row = cursor.fetchone()
6464
doc = bson.decode(row[0])
6565

@@ -72,7 +72,7 @@ print(json.dumps(doc, indent=2, default=str))
7272
Extract the widget's mpk to understand its schema and mode-dependent rules:
7373

7474
```bash
75-
# Find the mpk in the project's widgets folder
75+
# find the mpk in the project's widgets folder
7676
ls /path/to/project/widgets/*.mpk
7777

7878
# Extract (mpk is a ZIP archive)
@@ -81,8 +81,8 @@ cd /tmp/mpk-widget && unzip /path/to/project/widgets/com.mendix.widget.web.Datag
8181
```
8282

8383
Key files inside the mpk:
84-
- **`{Widget}.xml`** — Property schema: types, defaults, enumerations, nested objects
85-
- **`{Widget}.editorConfig.js`** — Mode-dependent visibility rules (which properties hide/show based on other values)
84+
- **`{widget}.xml`** — Property schema: types, defaults, enumerations, nested objects
85+
- **`{widget}.editorConfig.js`** — Mode-dependent visibility rules (which properties hide/show based on other values)
8686
- **`package.xml`** — Package version metadata
8787

8888
### Step 5: Read editorConfig.js for Mode Rules
@@ -108,18 +108,18 @@ Use binary search to find the exact property causing the error:
108108
# Mutation test: change a single property on a known-good widget
109109
import bson
110110

111-
# Read the working widget BSON
111+
# read the working widget BSON
112112
with open('working-widget.bson', 'rb') as f:
113113
doc = bson.decode(f.read())
114114

115-
# Change only one property value
115+
# change only one property value
116116
# ... modify the specific property ...
117117

118118
# Re-encode and write back
119119
with open('test-widget.bson', 'wb') as f:
120120
f.write(bson.encode(doc))
121121

122-
# Then insert back into the MPR and run mx check
122+
# then insert back into the MPR and run mx check
123123
```
124124

125125
### Step 7: Extract Fresh Templates
@@ -131,7 +131,7 @@ If the widget template is outdated, extract a fresh one:
131131
reference/mxbuild/modeler/mx convert -p /path/to/app.mpr
132132
reference/mxbuild/modeler/mx update-widgets /path/to/app.mpr
133133

134-
# Then extract using mxcli
134+
# then extract using mxcli
135135
./bin/mxcli extract-templates -p /path/to/app.mpr -widget "com.mendix.widget.web.datagrid.DataGrid2" -o /tmp/template.json
136136
```
137137

@@ -159,20 +159,20 @@ Three Mendix tools parse the same BSON but with **different strictness levels**:
159159
```bash
160160
# Self-diff: is the project's BSON clean?
161161
mx diff project.mpr project.mpr output.mpr
162-
# Success = all BSON matches schema. Crash = some mxunit has bad properties.
162+
# success = all BSON matches schema. Crash = some mxunit has bad properties.
163163

164-
# Cross-diff: compare baseline vs modified
164+
# cross-diff: compare baseline vs modified
165165
# 1. Extract baseline from git
166-
mkdir /tmp/baseline && cd project-dir && git archive HEAD -- *.mpr mprcontents/ | tar -x -C /tmp/baseline/
167-
# 2. Run diff (file names must match!)
166+
mkdir /tmp/baseline && cd project-dir && git archive head -- *.mpr mprcontents/ | tar -x -C /tmp/baseline/
167+
# 2. run diff (file names must match!)
168168
mx diff /tmp/baseline/App.mpr ./App.mpr /tmp/diff-output.mpr
169169
```
170170

171171
### Interpreting mx diff Output
172172

173173
**Detailed error** (when both sides have same-ID objects):
174174
```
175-
Objects with ID b6fc893f-... of type Settings$ServerConfiguration do not have the same properties.
175+
objects with ID b6fc893f-... of type settings$ServerConfiguration do not have the same properties.
176176
baseNames = ApplicationRootUrl, ConstantValues, CustomSettings, ..., Tracing;
177177
newNames = ApplicationRootUrl, ConstantValues, ...
178178
```
@@ -186,15 +186,15 @@ Sequence contains no matching element
186186

187187
### Finding the Offending mxunit File
188188

189-
Write a Go tool (or use the pattern below) to compare property keys of mxcli-written files against Studio Pro-native files of the same `$Type`:
189+
Write a Go tool (or use the pattern below) to compare property keys of mxcli-written files against Studio Pro-native files of the same `$type`:
190190

191191
```go
192-
// Walk mprcontents/, group files by $Type, compare key sets
192+
// Walk mprcontents/, group files by $type, compare key sets
193193
// Files with EXTRA keys (vs native files of same type) = the crash cause
194194
// Files with MISSING keys = also crash cause for mx diff
195195
```
196196

197-
The principle: for each `$Type`, ALL instances must have the **exact same set of non-$ property names**. Any deviation → crash.
197+
The principle: for each `$type`, ALL instances must have the **exact same set of non-$ property names**. Any deviation → crash.
198198

199199
### Version-Specific Properties
200200

@@ -229,7 +229,7 @@ Some properties only exist in certain Mendix versions. Before adding a property
229229

230230
**Symptom**: Studio Pro crashes when opening a project with `System.InvalidOperationException: Sequence contains no matching element` at `Mendix.Modeler.Storage.Mpr.MprProperty..ctor`.
231231

232-
**Root cause**: A BSON document contains a property (field name) that does not exist in the Mendix type definition for its `$Type`. Studio Pro's `MprProperty` constructor uses `First()` to look up each BSON field in the type cache, and crashes on unrecognized fields.
232+
**Root cause**: A BSON document contains a property (field name) that does not exist in the Mendix type definition for its `$type`. Studio Pro's `MprProperty` constructor uses `First()` to look up each BSON field in the type cache, and crashes on unrecognized fields.
233233

234234
**Diagnosis workflow**:
235235

@@ -242,10 +242,10 @@ type_props = defaultdict(set)
242242

243243
def walk_bson(obj, tp):
244244
if isinstance(obj, dict):
245-
t = obj.get("$Type", "")
245+
t = obj.get("$type", "")
246246
if t:
247247
for k in obj.keys():
248-
if k not in ("$Type", "$ID"):
248+
if k not in ("$type", "$ID"):
249249
tp[t].add(k)
250250
for v in obj.values():
251251
walk_bson(v, tp)
@@ -272,7 +272,7 @@ for t, props in crash_props.items():
272272

273273
3. **Extra properties = the crash cause**. The fix is to remove those fields from the writer function.
274274

275-
**Example**: `DomainModels$CrossAssociation` had `ParentConnection` and `ChildConnection` copied from `DomainModels$Association`, but these fields don't exist on `CrossAssociation`. Removing them fixed the crash.
275+
**Example**: `DomainModels$CrossAssociation` had `ParentConnection` and `ChildConnection` copied from `DomainModels$association`, but these fields don't exist on `CrossAssociation`. Removing them fixed the crash.
276276

277277
**Key principle**: When copying serialization code between similar types (e.g., Association → CrossAssociation), always verify which fields belong to each type by checking a baseline project's BSON.
278278

@@ -282,7 +282,7 @@ for t, props in crash_props.items():
282282

283283
**Root cause**: Two variants:
284284

285-
1. **Association stored as Attribute**: In `ChangeActionItem` BSON, an association name was written to the `Attribute` field instead of the `Association` field. Check the executor code that builds `MemberChange` — it must query the domain model to distinguish associations from attributes.
285+
1. **Association stored as Attribute**: In `ChangeActionItem` BSON, an association name was written to the `attribute` field instead of the `association` field. Check the executor code that builds `MemberChange` — it must query the domain model to distinguish associations from attributes.
286286

287287
2. **Entity treated as Enumeration**: In `CreateVariableAction` BSON, an entity qualified name was used as `DataTypes$EnumerationType` instead of `DataTypes$ObjectType`. Check `buildDataType()` in the visitor — bare qualified names default to `TypeEnumeration` and need catalog-based disambiguation.
288288

.claude/skills/design-mdl-syntax.md

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ When principles conflict, higher-priority ones win.
1818

1919
MDL targets citizen developers and business analysts, not software engineers. Statements should read as natural English sentences.
2020

21-
- Use keyword words (`FROM`, `WHERE`, `IN`), not symbols (`->`, `|>`, `=>`)
22-
- Spell out full words (`MICROFLOW`, `ASSOCIATION`), not abbreviations (`MF`, `ASSOC`)
23-
- Use prepositions to clarify relationships: `GRANT READ ON Entity TO Role`
21+
- Use keyword words (`from`, `where`, `in`), not symbols (`->`, `|>`, `=>`)
22+
- Spell out full words (`microflow`, `association`), not abbreviations (`MF`, `ASSOC`)
23+
- Use prepositions to clarify relationships: `grant read on entity to role`
2424

2525
**Test**: Read it aloud. A business analyst should understand on first hearing.
2626

@@ -30,34 +30,34 @@ Reuse existing patterns. Never create a second syntax for the same concept.
3030

3131
| Operation | Pattern | Example |
3232
|-----------|---------|---------|
33-
| Create | `CREATE [MODIFIERS] <TYPE> Module.Name (...)` | `CREATE PERSISTENT ENTITY Shop.Product (...)` |
34-
| Modify | `ALTER <TYPE> Module.Name <OPERATION>` | `ALTER ENTITY Shop.Product ADD (...)` |
35-
| Remove | `DROP <TYPE> Module.Name` | `DROP ENTITY Shop.Product` |
36-
| List | `SHOW <TYPE>S [IN Module]` | `SHOW ENTITIES IN Shop` |
37-
| Inspect | `DESCRIBE <TYPE> Module.Name` | `DESCRIBE ENTITY Shop.Product` |
38-
| Security | `GRANT/REVOKE <perm> ON <target> TO/FROM <role>` | `GRANT READ ON Shop.Product TO Shop.User` |
33+
| Create | `create [MODIFIERS] <type> Module.Name (...)` | `create persistent entity Shop.Product (...)` |
34+
| Modify | `alter <type> Module.Name <operation>` | `alter entity Shop.Product add (...)` |
35+
| Remove | `drop <type> Module.Name` | `drop entity Shop.Product` |
36+
| List | `show <type>S [in module]` | `show entities in Shop` |
37+
| Inspect | `describe <type> Module.Name` | `describe entity Shop.Product` |
38+
| Security | `grant/revoke <perm> on <target> to/from <role>` | `grant read on Shop.Product to Shop.User` |
3939

40-
Do NOT use alternative verbs: `ADD` instead of `CREATE`, `REMOVE` instead of `DROP`, `LIST` instead of `SHOW`, `VIEW` instead of `DESCRIBE`.
40+
Do NOT use alternative verbs: `add` instead of `create`, `remove` instead of `drop`, `list` instead of `show`, `view` instead of `describe`.
4141

4242
### 3. Optimize for LLMs
4343

4444
- Keep patterns regular so one example is sufficient for generation
4545
- Statements must be self-contained (no implicit state from prior statements)
46-
- Use consistent keyword order: `<VERB> [MODIFIERS] <TYPE> <NAME> [CLAUSES] [BODY]`
46+
- Use consistent keyword order: `<VERB> [MODIFIERS] <type> <NAME> [CLAUSES] [body]`
4747
- Prefer flat statement sequences over deeply nested structures
4848

4949
### 4. Make Diffs Reviewable
5050

5151
- One property per line in multi-property constructs
5252
- Allow trailing commas
53-
- `DESCRIBE` output uses deterministic property order
53+
- `describe` output uses deterministic property order
5454
- Default values omitted unless non-obvious
5555

5656
### 5. Token Efficiency (Without Sacrificing Clarity)
5757

58-
- Omit noise words: `CREATE ENTITY` not `CREATE A NEW ENTITY`
59-
- Support `OR MODIFY` to avoid check-then-create
60-
- Allow type inference for obvious cases: `DECLARE $Count = 0`
58+
- Omit noise words: `create entity` not `create A NEW entity`
59+
- Support `or modify` to avoid check-then-create
60+
- Allow type inference for obvious cases: `declare $count = 0`
6161
- Do NOT use symbols to save tokens at the cost of readability
6262

6363
## Design Workflow
@@ -72,37 +72,37 @@ Does an existing pattern cover this? If yes, extend it. Don't invent new syntax.
7272

7373
```
7474
New feature: "image collections"
75-
Existing pattern: CREATE/ALTER/DROP/SHOW/DESCRIBE
76-
Design: CREATE IMAGE COLLECTION Module.Name (...)
77-
DESCRIBE IMAGE COLLECTION Module.Name
78-
SHOW IMAGE COLLECTIONS [IN Module]
75+
Existing pattern: create/alter/drop/show/describe
76+
design: create image collection Module.Name (...)
77+
describe image collection Module.Name
78+
show image COLLECTIONS [in module]
7979
```
8080

8181
### Step 2: Pick the Statement Shape
8282

8383
Every MDL statement fits one of these shapes:
8484

8585
```
86-
DDL: <VERB> [MODIFIERS] <TYPE> <QualifiedName> [CLAUSES] [BODY];
87-
DML: <ACTION> <TARGET> [CLAUSES];
88-
DQL: <QUERY-VERB> <TYPE>S [FILTERS];
86+
DDL: <VERB> [MODIFIERS] <type> <QualifiedName> [CLAUSES] [body];
87+
DML: <action> <TARGET> [CLAUSES];
88+
DQL: <query-VERB> <type>S [FILTERS];
8989
```
9090

9191
If your feature doesn't fit any shape, it may belong as a CLI command (`mxcli <subcommand>`) rather than MDL syntax.
9292

9393
### Step 3: Choose Keywords
9494

9595
1. Reuse existing keywords first (check reserved words in grammar)
96-
2. Use SQL/DDL verbs: `CREATE`, `ALTER`, `DROP`, `SHOW`, `DESCRIBE`, `GRANT`, `REVOKE`, `SET`
97-
3. Use Mendix terminology: `ENTITY` not `TABLE`, `MICROFLOW` not `FUNCTION`, `PAGE` not `VIEW`
98-
4. Prepositions clarify structure: `FROM`, `TO`, `IN`, `ON`, `BY`, `WITH`, `AS`, `WHERE`, `INTO`
96+
2. Use SQL/DDL verbs: `create`, `alter`, `drop`, `show`, `describe`, `grant`, `revoke`, `set`
97+
3. Use Mendix terminology: `entity` not `table`, `microflow` not `FUNCTION`, `page` not `view`
98+
4. Prepositions clarify structure: `from`, `to`, `in`, `on`, `by`, `with`, `as`, `where`, `into`
9999

100100
### Step 4: Write the Property List
101101

102102
All property-bearing constructs use this format:
103103

104104
```mdl
105-
CREATE <TYPE> Module.Name (
105+
create <type> Module.Name (
106106
Property1: value,
107107
Property2: value,
108108
);
@@ -115,29 +115,29 @@ Rules:
115115
- Trailing comma allowed
116116
- One property per line (single line acceptable for 1-2 properties)
117117

118-
#### Colon `:` vs `AS` — When to Use Each
118+
#### Colon `:` vs `as` — When to Use Each
119119

120120
Use **colon** for property definitions (assigning a value to a named property):
121121

122122
```mdl
123-
CREATE ENTITY Shop.Product (
124-
Name: String(200), -- property: type/value
125-
Price: Decimal,
123+
create entity Shop.Product (
124+
Name: string(200), -- property: type/value
125+
Price: decimal,
126126
);
127-
TEXTBOX txtName (Label: 'Name', Attribute: Title)
127+
textbox txtName (label: 'Name', attribute: title)
128128
```
129129

130-
Use **`AS`** for name-to-name mappings (renaming, aliasing, mapping one name to another):
130+
Use **`as`** for name-to-name mappings (renaming, aliasing, mapping one name to another):
131131

132132
```mdl
133-
CUSTOM NAME MAP (
134-
'kvkNummer' AS 'ChamberOfCommerceNumber', -- old name AS new name
135-
'naam' AS 'CompanyName',
133+
CUSTOM NAME map (
134+
'kvkNummer' as 'ChamberOfCommerceNumber', -- old name AS new name
135+
'naam' as 'CompanyName',
136136
)
137-
ALTER ENTITY Shop.Product RENAME Code AS ProductCode -- old attr AS new attr
137+
alter entity Shop.Product rename Code as ProductCode -- old attr AS new attr
138138
```
139139

140-
**Rule of thumb**: if the left side is a *fixed property key* defined by the syntax, use `:`. If the left side is a *user-provided name* being mapped to another name, use `AS`.
140+
**Rule of thumb**: if the left side is a *fixed property key* defined by the syntax, use `:`. If the left side is a *user-provided name* being mapped to another name, use `as`.
141141

142142
### Step 5: Validate
143143

@@ -147,31 +147,31 @@ Run these checks before finalizing syntax design:
147147
2. **LLM generation test** — Give one example to an LLM, ask for a variant. Does it get it right?
148148
3. **Diff test** — Change one property. Is the diff exactly one line?
149149
4. **Pattern test** — Does it follow CREATE/ALTER/DROP/SHOW/DESCRIBE? If not, why?
150-
5. **Roundtrip test** — Can `DESCRIBE` output be fed back as input?
150+
5. **Roundtrip test** — Can `describe` output be fed back as input?
151151

152152
## Anti-Patterns (DO NOT)
153153

154154
### Custom Verbs for Standard Operations
155155

156156
```mdl
157157
-- WRONG: custom verb
158-
SCHEDULE EVENT Shop.Cleanup ...
158+
SCHEDULE event Shop.Cleanup ...
159159
REGISTER WEBHOOK Shop.OnOrder ...
160160
161161
-- RIGHT: standard CREATE
162-
CREATE SCHEDULED EVENT Shop.Cleanup (...)
163-
CREATE WEBHOOK Shop.OnOrder (...)
162+
create SCHEDULED event Shop.Cleanup (...)
163+
create WEBHOOK Shop.OnOrder (...)
164164
```
165165

166166
### Implicit Module Context
167167

168168
```mdl
169169
-- WRONG: implicit state
170-
USE MODULE Shop;
171-
CREATE ENTITY Customer (...);
170+
use module Shop;
171+
create entity Customer (...);
172172
173173
-- RIGHT: explicit qualified name
174-
CREATE ENTITY Shop.Customer (...);
174+
create entity Shop.Customer (...);
175175
```
176176

177177
### Symbolic Syntax
@@ -181,19 +181,19 @@ CREATE ENTITY Shop.Customer (...);
181181
$items |> filter($.active) |> map($.name)
182182
183183
-- RIGHT: keyword-based
184-
FILTER $Items WHERE Active = true
184+
filter $Items where Active = true
185185
```
186186

187187
### Positional Arguments
188188

189189
```mdl
190190
-- WRONG: meaning unclear without docs
191-
CREATE RULE Shop Process Order ACT_ProcessOrder
191+
create rule Shop Process Order ACT_ProcessOrder
192192
193193
-- RIGHT: labeled properties
194-
CREATE RULE Shop.ProcessOrder (
195-
Type: Validation,
196-
Microflow: Shop.ACT_ProcessOrder,
194+
create rule Shop.ProcessOrder (
195+
type: validation,
196+
microflow: Shop.ACT_ProcessOrder,
197197
);
198198
```
199199

@@ -208,16 +208,16 @@ CREATE RULE Shop.ProcessOrder (
208208

209209
Before merging any PR that adds new MDL syntax, verify:
210210

211-
- [ ] Follows `CREATE`/`ALTER`/`DROP`/`SHOW`/`DESCRIBE` pattern
211+
- [ ] Follows `create`/`alter`/`drop`/`show`/`describe` pattern
212212
- [ ] Uses `Module.Element` qualified names (no bare names)
213-
- [ ] Property lists use `( Key: value, ... )` format
213+
- [ ] Property lists use `( key: value, ... )` format
214214
- [ ] Keywords are full English words (no abbreviations)
215215
- [ ] Statement reads as English (aloud test passed)
216216
- [ ] One example sufficient for LLM generation
217217
- [ ] Small change = one-line diff
218218
- [ ] No new keyword overloading
219219
- [ ] No implicit context dependency
220-
- [ ] `DESCRIBE` roundtrips to valid MDL
220+
- [ ] `describe` roundtrips to valid MDL
221221
- [ ] Grammar regenerated (`make grammar`)
222222
- [ ] Quick reference updated (`docs/01-project/MDL_QUICK_REFERENCE.md`)
223223
- [ ] Full-stack wired: grammar, AST, visitor, executor, DESCRIBE

0 commit comments

Comments
 (0)