How the design.md Lint Command Reports Validation Results and Exit Codes
The lint command in the design.md CLI validates DESIGN.md documents and returns exit code 0 for success, 1 for validation errors, and 2 for file read failures, outputting a structured report containing detailed findings and aggregated severity counts.
The google-labs-code/design.md repository provides a command-line interface for validating design system documentation. When you run the lint command, it performs comprehensive validation of your DESIGN.md file and reports results through both structured output and process exit codes. Understanding how validation results are reported and which exit codes are used enables reliable integration into CI/CD pipelines and automated workflows.
Validation Workflow and Reporting
The lint command follows a four-stage pipeline implemented across the CLI source tree. Each stage contributes to the final report and exit behavior.
Input Reading and Error Handling
In packages/cli/src/utils.ts, the readInput utility attempts to read the specified file path or stdin. If the file cannot be accessed, it throws a FileReadError and the command immediately terminates with exit code 2. This distinguishes I/O failures from validation failures.
The Lint Report Structure
Once input is successfully read, the raw markdown passes to the lint(content) function in packages/cli/src/linter/lint.ts. This function parses the document, builds a design-system model, runs all lint rules, and generates a Tailwind CSS configuration. The returned LintReport object contains:
findings– An array of individual issues, each specifying severity (error, warning, or info), message, and optional path.summary– Aggregated counts in the format{ errors, warnings, infos }.- Additional metadata – Includes
designSystem,sections, and other data not printed by default.
Output Formatting
The formatOutput utility (also in packages/cli/src/utils.ts) serializes the report based on the --format flag. By default, it outputs JSON, but it can also render markdown or plain text for human-readable reports.
Exit Code Behavior
After printing the formatted report, the command sets the process exit code in packages/cli/src/commands/lint.ts using this logic:
process.exitCode = report.summary.errors > 0 ? 1 : 0;
The exit codes follow this specification:
- 0 – No lint errors detected. Warnings and informational messages may be present, but the document is considered valid.
- 1 – One or more lint errors were found in the document.
- 2 – The input file could not be read (I/O error or missing file).
This behavior allows shell scripts and CI systems to distinguish between validation failures and system errors reliably.
Practical Usage Examples
Basic JSON Validation
Run the linter against a DESIGN.md file to receive machine-readable output:
design-md lint ./examples/totality-festival/DESIGN.md
Typical JSON output structure:
{
"findings": [
{
"severity": "error",
"message": "Token \"brand-primary\" is undefined",
"path": "colors.brand-primary"
},
{
"severity": "warning",
"message": "Unused token \"spacing.large\"",
"path": "spacing.large"
}
],
"summary": {
"errors": 1,
"warnings": 1,
"infos": 0
}
}
Exit Code Handling in Scripts
Use the exit code in automated workflows to trigger different actions:
#!/usr/bin/env bash
design-md lint ./DESIGN.md
case $? in
0) echo "✅ Lint passed – no errors." ;;
1) echo "❌ Lint failed – errors were reported." ;;
2) echo "⚠️ Unable to read the DESIGN.md file." ;;
esac
Human-Readable Markdown Reports
For review during development, request a markdown formatted report:
design-md lint ./DESIGN.md --format markdown
This produces structured output like:
# Lint Report
**1 errors**, **1 warnings**, **0 infos**
## Findings
- **error** `colors.brand-primary`: Token "brand-primary" is undefined
- **warning** `spacing.large`: Unused token "spacing.large"
Summary
- The lint command validates DESIGN.md documents through a pipeline involving input reading, model validation, and report generation.
- Exit code 0 indicates success (no errors), exit code 1 indicates validation errors found, and exit code 2 indicates file read failures.
- Validation reports include a
findingsarray with detailed issue descriptions and asummaryobject aggregating error, warning, and info counts. - Output formats include JSON (default) and markdown, controlled via the
--formatflag. - Core implementation resides in
packages/cli/src/commands/lint.ts,packages/cli/src/linter/lint.ts, andpackages/cli/src/utils.ts.
Frequently Asked Questions
What exit code does the lint command return when only warnings are present?
The command returns exit code 0 when only warnings or informational messages are present. According to the source code in packages/cli/src/commands/lint.ts, the process only exits with code 1 when report.summary.errors > 0. Warnings and infos do not trigger a failure status.
How does the lint command handle file read errors?
When the input file cannot be read, the readInput function in packages/cli/src/utils.ts throws a FileReadError. This exception causes the command to exit with exit code 2 before any validation logic executes, distinguishing I/O problems from document validation issues.
Can the lint command output be formatted as markdown?
Yes. The --format flag accepts markdown as an option. When specified, the formatOutput utility in packages/cli/src/utils.ts serializes the LintReport into a human-readable markdown document containing a summary header and a bulleted list of findings with their severity levels.
Where is the exit code logic implemented in the source code?
The exit code assignment is implemented in packages/cli/src/commands/lint.ts. After formatting and printing the output, the command explicitly sets process.exitCode based on the error count from the report summary, while file read errors handled earlier in the pipeline use code 2.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →