From dux
Validates DESIGN.md against the getdesign.md alpha spec and WCAG contrast. Use when the user says 'lint DESIGN.md', 'validate DESIGN.md', or selects DL from Mayasura's menu.
How this skill is triggered — by the user, by Claude, or both
Slash command
/dux:dux-design-md-lintThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Validates the project's `DESIGN.md` against the getdesign.md alpha spec and WCAG 2.1 AA contrast, producing a self-contained HTML report under `{design_output_folder}/lint/{timestamp}.html`. The report groups findings by severity, renders failing color pairs as inline swatches, and ships concrete fix snippets.
Validates the project's DESIGN.md against the getdesign.md alpha spec and WCAG 2.1 AA contrast, producing a self-contained HTML report under {design_output_folder}/lint/{timestamp}.html. The report groups findings by severity, renders failing color pairs as inline swatches, and ships concrete fix snippets.
The deterministic work (parse, schema check, coverage, token-ref resolution, contrast math) lives in Python scripts. The prompt interprets findings, decides edge-case severity, walks the user through the report, and offers handoff to dux-design-md for fixes.
The workflow runs under Mayasura, the Visual Architect — that persona is established by dux-agent-mayasura and carries through unchanged. Do not re-greet, do not break character.
Args: --headless for CI gating (exits non-zero on any AA-level contrast failure or spec error). Optional path arg to a non-default DESIGN.md location.
references/contrast-rules.md) resolve from the skill root.{skill-root} resolves to this skill's installed directory.{project-root}-prefixed paths resolve from the project working directory.{skill-name} resolves to the skill directory's basename.Load module config from {project-root}/_bmad/config.yaml and {project-root}/_bmad/config.user.yaml — root level plus the dux section. Bind:
{design_md_path} from dux.design_md_path (default {project-root}/docs/DESIGN.md){design_output_folder} from dux.design_output_folder (default {project-root}/_bmad-output/design)If {design_md_path} does not exist, exit early with a clear pointer to dux-design-md (DM) — there is nothing to lint. Do not create a placeholder file.
Read {design_workspace}/.dux-design-md.decision-log.md if it exists. The DESIGN.md decision log is owned by dux-design-md; this workflow reads it to surface rules the user has explicitly chosen to relax (with reasons) and adjust severity accordingly. Never write to it. Lint's own per-run state lives entirely inside the HTML report.
Run the deterministic checker:
python3 scripts/lint.py {design_md_path} -o {design_output_folder}/lint/{timestamp}.findings.json
The script parses DESIGN.md (YAML front matter + prose sections), runs all six checks, and emits a single findings JSON document. It does no interpretation — every finding includes a category, a severity, a location (section, line, or token), a detail, and a fix snippet where one is unambiguous. See scripts/lint.py --help for the full check list.
Exit codes from the script:
0 — no findings at error severity1 — at least one error-severity finding (spec violation, broken token ref, AA body-text contrast fail)2 — script error (malformed file, unparseable YAML)In interactive mode, run regardless of exit code and continue. In headless mode, propagate the exit code on completion.
Read the findings JSON. The script assigns a default severity to every finding; this stage is where prompt judgment refines edge cases the deterministic logic can't decide:
disabled / placeholder roles — AA still applies but a 3:1 minimum is conventional rather than 4.5:1. Downgrade body-text fails on these to warning if context makes it clear they're disabled-state pairs.hairline colors used purely as 1px non-functional borders are not text contrast; suppress contrast findings against hairline when no text role pairs with it.<role> because ", downgrade matching findings to info and annotate with the recorded reason.success text on surface-card when the brand never uses success text on cards) get downgraded to info if no component actually composes them.Do not invent findings the script did not surface. The script is the source of truth for what exists in DESIGN.md; the prompt's job is to interpret severity, not to add new defects.
Severity tiers (final, after adjustment):
| Tier | Examples |
|---|---|
| error | Required YAML block missing, prose section out of order or missing, YAML↔prose 1:1 broken, token ref points at non-existent token, AA body-text contrast fail (< 4.5:1) on a real component pair |
| warning | AA large-text contrast fail (< 3:1), Known Gaps section empty or platitudinous, semantic-color pair the brand actually uses falls short of AAA |
| info | AAA aspiration (any pair < 7:1 body / 4.5:1 large), spec quirks worth noting but not breaking, suppressed-by-relaxation findings |
Render the HTML report:
python3 scripts/render-report.py {findings-json-path} --design-md {design_md_path} -o {design_output_folder}/lint/{timestamp}.html
The renderer produces a single self-contained HTML file — no external CSS, no CDN, no images. Every failing color pair renders as an inline swatch (background-color + on-color rendered as actual CSS) so the user sees the failure, not just the math. Findings group by severity (errors → warnings → info), and each entry includes its detail, exact contrast ratio (for contrast findings), and fix snippet ready to paste.
If interactive, also write a small companion summary line to stderr and offer to open the report.
In interactive mode, present findings to the user in order: errors first, walking each one with the exact location and the concrete fix. After errors, offer to skim warnings and info. Soft-gate at the end: "anything you want to dig into, or shall we hand off to DM to apply fixes?"
In headless mode, skip the walkthrough.
If errors exist and the user accepts, dispatch dux-design-md in Update mode with the findings JSON as the change brief. DM is the authoritative writer; lint never edits DESIGN.md directly.
If no errors exist, mention the report path and exit. Mayasura's menu stays available.
--headless runs Stages 1, 2 (script-level severity only; no prompt adjustment in headless), and 3 — then exits.
Emit JSON on stdout:
{
"status": "pass" | "fail",
"errors": <count>,
"warnings": <count>,
"info": <count>,
"report": "{design_output_folder}/lint/{timestamp}.html",
"findings_json": "{design_output_folder}/lint/{timestamp}.findings.json",
"design_md": "{design_md_path}"
}
Process exit code:
0 if errors == 01 if any error-severity finding existsThis is the contract CI consumers depend on; do not break it.
dux-agent-mayasura. Do not re-greet, do not break character.npx claudepluginhub yash-1511/bmad-dux-visual-architect --plugin duxProvides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.