| name | mx-page-audit |
| description | Read-only audit of a Mendix page against project doctrine. Flags SmartHub class usage (DEPRECATED), classes not in the OS2 catalog (snowflakes), missing design-properties bindings, page-template deviations (Template A or B), accessibility-tree red flags, and any class that does not exist in the project's theme catalog. Uses the mendix-context MCP tools (theme_catalog, os2_class_groups, validate_classes, theme_architecture) to ground every finding in doctrine. Auto-invoke before merging any page change, after /mx-handoff completes, and as part of the standard pre-codex flow for Mendix work. Also invocable as /mx-page-audit <page-name-or-path>. |
mx-page-audit
The "is this page well-formed against our system" primitive. Pure read-only. Catches the class of error that's expensive to fix later: snowflake CSS classes, SmartHub residue, page-template drift, hand-rolled patterns where an OS2 component already exists.
North star
Catch convention violations before they ship, not after they multiply.
The cost of a snowflake class is invisible the day it's added. It compounds across pages and becomes maintenance debt that drives the OS2 prefix split that already happened once.
When to invoke
Auto-invoke when:
- A
/mx-handoff reports "done" -- audit the touched page before declaring success.
- A page got modified through any path (Studio Pro UI, mxcli, Maia generation).
- About to merge a branch that touches
*.page.xml or page contents.
- Part of the
/pre-codex flow when the diff includes Mendix page changes.
- Onboarding a new page from another project (carbon copy + audit before adopting).
Do not invoke for:
- Pages that haven't been touched recently.
- Microflow-only changes (no page surface).
- Pages on a non-allowlisted project (refuse via testbed allowlist).
What it does
Phase 0 -- prerequisites
- Resolve project root; verify against
~/.claude/rules/mendix-testbed.md allowlist.
- Resolve target page. Three input shapes:
- Page name (
CustomerDetail) -- find via mxcli search or grep.
- Page path (
Customer.CustomerDetail qualified) -- use directly.
- File path (e.g., a JSON/XML page export, if mxcli produces one).
- Confirm
mendix-context MCP server is reachable (stdio or HTTP). Without it, the audit can still run but loses the OS2 grounding.
Phase 1 -- catalog grounding
Call (in parallel where possible):
mendix-context.theme_catalog(project) -- the full class catalog.
mendix-context.os2_class_groups(project) -- class buckets.
mendix-context.theme_architecture(project) -- DESIGN_SYSTEM_RULES.md + os2/README.md text.
mendix-context.gold_pages(project) -- to know if the audited page IS a gold page (different bar) or should be patterned after one.
Cache these for use by phases 2-4.
Phase 2 -- extract page facts
Use mxcli describe <Module.Page> (read-only) to get:
- Top-level structure (layout, dataView, listView, etc.).
- Every class string referenced by every widget.
- Every design-property binding.
- Every action call.
If mxcli can't expose this granularly (alpha limitation), fall back to reading any per-page metadata that DOES expose classes, or note the limitation in the report.
Phase 3 -- audit checks
Run every check; compose findings into a structured report. Each finding has a severity (BLOCK / FLAG / NIT).
Class-level checks:
- SmartHub class detection (BLOCK). Any class starting
sh- or in the smarthub bucket from os2_class_groups. Per rules/mendix-os2.md, NEVER allowed.
- Hallucinated class (BLOCK). Any class string that doesn't exist in the theme catalog. Suggest near-matches via
validate_classes.
- Snowflake class (FLAG). Any class in the "other" bucket from os2_class_groups (page-specific, not in os-* / os2-* / atlas / tailwind-compat). Recommend mapping to an existing utility or component.
- Wrong-bucket usage (NIT). Using
os-* utilities where an os2-* component already covers the pattern -- recommend the higher-level component.
Page-template checks:
- Template A or B? Per
DESIGN_SYSTEM_RULES.md, every page uses Template A (standard content + optional sidebar) or Template B. Identify which (or "neither" -- which is a FLAG; demand explicit justification).
- Section-header pattern (NIT). Section headers should use
.section-header, not page-specific headers.
Design-property checks:
- Hardcoded class where a design-property exists (FLAG). Per
DESIGN_SYSTEM_RULES.md, prefer design-property bindings over hardcoded classes for badges, buttons, popups, inputs. Cross-check against the design_properties MCP tool's schema.
Accessibility checks (best-effort):
- Missing
aria-label on icon-only buttons (FLAG).
- Heading-level skips (FLAG). h1 -> h3 without h2.
- Form inputs without labels (FLAG).
(These checks are limited by what mxcli surfaces from the .mpr; consider deferring full a11y audit to the runtime via /mx-test-page.)
Gold-page comparison:
- If the audited page is NOT a gold page, compare its structure to the closest gold-page sibling (e.g., if the page is a dashboard-like page, compare to
RequestSource_Dashboard). Flag major structural deviations.
Phase 4 -- structured report
## /mx-page-audit: <page-name>
**Project:** <root>
**Page kind:** <data-view | list-view | dashboard | form | other>
**Page template:** <Template A | Template B | other -- justify>
**Is this a gold page?** <yes / no -- closest gold page: X>
### BLOCK (must fix)
- <category> -- <finding> -- <suggested fix>
### FLAG (justify or fix)
- <category> -- <finding> -- <suggestion>
### NIT (optional polish)
- <finding>
### Class summary
- Total classes used: N
- os2_components: N (good)
- os_btn_icons: N
- os_utilities: N
- tailwind_compat: N
- smarthub: N (DEPRECATED -- BLOCK if > 0)
- other (snowflake): N (FLAG if > 0)
- not-in-catalog (hallucinated): N (BLOCK if > 0)
### Doctrine sources cited
- rules/mendix-os2.md
- mendix-context.theme_catalog (class verification)
- mendix-context.theme_architecture -- DESIGN_SYSTEM_RULES.md, os2/README.md
- gold pages: RequestSource_Dashboard (and any project-registered)
### Verdict
- READY-TO-MERGE (no BLOCK, FLAGs justified)
- NEEDS-WORK (BLOCK present, OR FLAGs unjustified)
Hard rules
- Read-only, period. No flag, no edge case lets this skill mutate the page or the model.
- Refuse on non-allowlisted projects. Use the testbed-refusal block.
- SmartHub classes are ALWAYS BLOCK. Per
rules/mendix-os2.md, no exceptions, no "well in this case."
- Hallucinated classes (not in the theme catalog) are ALWAYS BLOCK. A class that doesn't exist is a runtime style-failure waiting to happen.
- Cite sources for every finding. Doctrine without a pointer is just opinion.
- If mxcli can't expose enough page detail to run a check, mark that check as SKIPPED and explain. Don't fabricate findings on missing data.
Anti-patterns this skill exists to prevent
- Page that ships with
sh-customer-card (SmartHub fossil leaks past code review).
- Page that uses
.my-customer-detail-wrapper (snowflake) when .os-card covers it.
- Page that hardcodes
class="badge-primary" instead of using a Badge design-property binding.
- Page that uses neither Template A nor B and nobody noticed.
- "Looks fine in Studio Pro" but the class doesn't exist in the compiled theme.
Cross-reference
- OS2 doctrine:
~/.claude/rules/mendix-os2.md (the rules being checked).
- Testbed allowlist:
~/.claude/rules/mendix-testbed.md.
- Runtime verification (post-render):
~/.claude/skills/mx-test-page/SKILL.md.
- Pre-push gate (Mendix-aware):
~/.claude/skills/pre-codex/SKILL.md, /mx-doctor.
- mendix-context MCP tools:
theme_catalog, os2_class_groups, validate_classes, theme_architecture, gold_pages, design_properties.