crefft Source 2026.10.4

Markdown Style Guide

crefft > Documentation > Markdown

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

Extends Google Markdown Style Guide.

Quick Reference

TaskToolCommand
Lintmarkdownlint1npx --package=markdownlint-cli@0.46.0 markdownlint '**/*.md'
FormatPrettier2npx prettier@4.0.0-alpha.8 --write '**/*.md'
DiagramsMermaid3via markdown code blocks
Link checkmarkdown-link-check4Link-check command

Linting: markdownlint

Projects MUST use markdownlint1 to enforce consistent Markdown style.

npm install --save-dev markdownlint-cli@0.46.0
npx --package=markdownlint-cli@0.46.0 markdownlint '**/*.md'

Why markdownlint

markdownlint1 provides automated enforcement of Markdown conventions, catching common issues like inconsistent heading styles, improper list formatting, and missing blank lines. It ensures consistent style across teams without manual review effort.

Configuration (.markdownlint.json)

Projects MUST use the following base configuration:

{
  "default": true,
  "MD013": false,
  "MD033": false,
  "MD041": false
}

Disabled rules:

  • MD013: Line length (Prettier2 handles this)
  • MD033: Inline HTML (sometimes needed)
  • MD041: First line must be heading (not always applicable)

Formatting: Prettier

Projects MUST use Prettier2 for Markdown formatting with the following configuration:

{
  "proseWrap": "always",
  "printWidth": 80,
  "tabWidth": 2
}

Why Prettier

Prettier2 eliminates debates about formatting details by automatically enforcing a consistent style. It handles line wrapping, spacing, and alignment automatically, allowing authors to focus on content rather than formatting.

Why tabWidth 2

tabWidth controls the indentation Prettier2 emits for nested list items, and markdownlint1 rule MD007/ul-indent defaults to an expected indent of two spaces. Setting tabWidth to 4 makes the two mandatory tools contradict each other: Prettier writes four-space nested items and markdownlint then reports MD007/ul-indent [Expected: 2; Actual: 4] on the file Prettier just formatted, so no file can satisfy both. tabWidth: 2 keeps MD007 at its default and leaves the base .markdownlint.json above unchanged.

Projects that MUST use four-space indentation for portability with legacy Markdown parsers MUST relax the affected rule in .markdownlint.json rather than leaving the conflict in place:

{
  "MD007": { "indent": 4 }
}

Only MD007 needs relaxing. Prettier 3.9.6 applies tabWidth to continuation and nesting indentation only, and still emits a single space after every list marker, so the MD030/list-marker-space override shown in the upstream compatibility notes5 is unnecessary — setting it to 3 makes markdownlint1 reject Prettier’s own output.

The trade-off is that MD007: { "indent": 4 } diverges from the markdownlint1 default, so every consumer of the documentation must copy it; two-space indentation needs no configuration at all.

Key Conventions

Line Length

Prose MUST wrap at 80 characters. URLs, code blocks, and tables MAY exceed this limit when necessary.

Headings

# Document Title (only one H1)

## Section

### Subsection

Headings MUST:

  • Use ATX-style (#) not Setext-style (underlines)
  • Have one blank line before and after
  • Omit trailing punctuation

Lists

Nested list items MUST be indented by two spaces, matching the tabWidth: 2 Prettier2 setting above and the markdownlint1 MD007 default.

- Item one
- Item two
  - Nested item (2-space indent)
  - Another nested item
- Item three

1. First step
2. Second step
3. Third step

Code Blocks

Code blocks MUST specify the language:

```python
def hello():
    print("Hello, World!")
```

```bash
echo "Hello"
```

Inline code SHOULD be used for: variable_name, function(), ClassName

[Link text](https://example.com)

[Reference-style link][ref]

[ref]: https://example.com

Tables

| Header 1 | Header 2 | Header 3 |
|----------|----------|----------|
| Cell 1   | Cell 2   | Cell 3   |
| Cell 4   | Cell 5   | Cell 6   |

Diagrams: Mermaid

Projects SHOULD use Mermaid3 for diagrams in documentation. It renders in GitHub, GitLab, and most documentation systems.

Why Mermaid

Mermaid3 diagrams are version-controllable text files, making them easy to review, diff, and maintain. They render automatically in most modern platforms without requiring external image hosting or build steps. Changes to diagrams appear in pull request diffs alongside code changes.

When to Use Mermaid

  • Flowcharts and process diagrams
  • Sequence diagrams
  • Entity-relationship diagrams
  • State diagrams
  • Architecture diagrams
  • Git graphs

When NOT to Use Mermaid

Projects SHOULD NOT use Mermaid3 for:

  • Complex diagrams with many nodes (>20)
  • Diagrams requiring precise positioning
  • Diagrams with images/icons
  • Highly customized styling

For complex diagrams, projects MAY use dedicated tools (Excalidraw6, draw.io7) and embed as images.

Flowchart

```mermaid
flowchart TD
    A[Start] --> B{Is it working?}
    B -->|Yes| C[Great!]
    B -->|No| D[Debug]
    D --> B
```

Sequence Diagram

```mermaid
sequenceDiagram
    participant Client
    participant API
    participant Database

    Client->>API: POST /users
    API->>Database: INSERT user
    Database-->>API: user_id
    API-->>Client: 201 Created
```

Entity Relationship

```mermaid
erDiagram
    USER ||--o{ ORDER : places
    ORDER ||--|{ ORDER_ITEM : contains
    PRODUCT ||--o{ ORDER_ITEM : "ordered in"
```

Validating Mermaid

# Install mermaid-cli
npm install -g @mermaid-js/mermaid-cli@12.0.0

# Validate syntax
mmdc -i diagram.mmd -o diagram.png

# Or use online editor
# https://mermaid.live

See the Mermaid Live Editor8 for interactive diagram creation and validation.

ASCII Diagrams

For simple diagrams that MUST work everywhere (including plain text viewers), projects MAY use ASCII art:

┌─────────────┐     ┌─────────────┐
│   Client    │────>│    API      │
└─────────────┘     └──────┬──────┘
                           │
                           v
                    ┌─────────────┐
                    │  Database   │
                    └─────────────┘

ASCII Box Drawing Characters

Box drawing:
┌ ┐ └ ┘ ─ │ ├ ┤ ┬ ┴ ┼

Arrows:
-> <- ^ v > < A V

Double lines:
╔ ╗ ╚ ╝ ═ ║ ╠ ╣ ╦ ╩ ╬

Checking ASCII Alignment

Ensure your editor uses a monospace font. In CI, you can validate alignment using a simple script that checks character positions, but this is rarely necessary if you use proper editor support.

Projects SHOULD validate links using markdown-link-check4:

npm install --save-dev markdown-link-check@3.15.0
npx markdown-link-check@3.15.0 --config .markdown-link-check.json README.md

Broken links degrade documentation quality and user trust. Automated link checking catches broken references before they reach users, especially important for documentation that references external resources that may change or move.

{
  "ignorePatterns": [
    { "pattern": "^https://localhost" }
  ],
  "timeout": "20s",
  "retryOn429": true
}

Every invocation MUST pass this file explicitly: --config .markdown-link-check.json on the command line and config-file: .markdown-link-check.json for the GitHub Action below.

Why the Configuration Must Be Passed Explicitly

markdown-link-check4 loads a configuration file only when one is named on the command line; it does not discover .markdown-link-check.json by convention. The GitHub Action does default a configuration path, but the default is mlc_config.json, not the filename used here. Omitting the flag therefore silently discards the ignorePatterns, timeout, and retryOn429 settings, and a local https://localhost link fails the run with a connection error instead of being ignored.

Pre-commit Configuration

Projects SHOULD configure pre-commit hooks to run markdownlint1 and Prettier2:

repos:
  - repo: https://github.com/igorshubovych/markdownlint-cli
    rev: v0.46.0
    hooks:
      - id: markdownlint
        args: [--disable, MD013, MD033, MD041, --]

  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v4.0.0-alpha.8
    hooks:
      - id: prettier
        types: [markdown]

See pre-commit9 documentation for more information on configuring hooks.

CI Pipeline

Projects SHOULD run Markdown linting and link checking in CI. The following is a complete workflow, not a fragment: save it as .github/workflows/docs.yml and it runs as written.

name: Docs

on:
  push:
    branches: [main]
  pull_request:

permissions:
  contents: read

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: DavidAnson/markdownlint-cli2-action@eb5ca3ab411449c66620fe7f1b3c9e10547144b0 # v18.0.0
        with:
          globs: "**/*.md"
      - uses: >- # v1
          gaurav-nelson/github-action-markdown-link-check@5c5dfc0ac2e225883c0e5f03a85311ec2830d368
        with:
          config-file: .markdown-link-check.json

Why Each Key Is Required

  • on is what makes the file a workflow. Without it GitHub Actions has no trigger to attach the run to, so the job never executes.
  • globs overrides the markdownlint-cli2-action default of *.{md,markdown}, which matches only the repository root. Without it every nested directory — docs/, guides/, and the rest — is silently unlinted.
  • config-file is required because the action’s default is mlc_config.json; see Link Checking above.
  • permissions: contents: read drops the default write scopes from the GITHUB_TOKEN. Linting needs only to read the checkout, so a compromised action or dependency cannot push commits or open releases.

See GitHub Actions10 documentation for more CI/CD configuration options.

See Also

References

Footnotes

  1. markdownlint - A Node.js style checker and lint tool for Markdown/CommonMark files ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8

  2. Prettier - An opinionated code formatter with support for Markdown ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7

  3. Mermaid - JavaScript-based diagramming and charting tool that renders Markdown-inspired text definitions ↩ ↩2 ↩3 ↩4

  4. markdown-link-check - Checks all hyperlinks in Markdown files for validity ↩ ↩2 ↩3

  5. Using markdownlint with Prettier - Upstream compatibility notes for the two tools ↩

  6. Excalidraw - Virtual whiteboard for sketching hand-drawn like diagrams ↩

  7. draw.io - Free online diagram software for making flowcharts, process diagrams, and more ↩

  8. Mermaid Live Editor - Interactive editor for creating and validating Mermaid diagrams ↩

  9. pre-commit - A framework for managing and maintaining multi-language pre-commit hooks ↩

  10. GitHub Actions - Automation platform for CI/CD workflows ↩

  11. CommonMark - A strongly defined, highly compatible specification of Markdown ↩

  12. GitHub Flavored Markdown - GitHub’s extended Markdown syntax specification ↩