Linting & formatting¶
This page documents the lint configuration choices that are non-obvious or whose rationale would otherwise be lost.
treefmt formatters¶
Wired in treefmt.nix. Run via nix fmt or just fmt. Pre-commit hook
treefmt runs the same set.
| Formatter | Scope |
|---|---|
| nixfmt | *.nix |
| prettier | JSON and YAML only |
| mdformat | *.md (with gfm + frontmatter + mkdocs + footnote plugins) |
| shfmt | shell scripts, 2-space indent |
| taplo | TOML |
Prettier rewrites single-quoted YAML scalars to double-quoted. Use double quotes from the start in workflow files.
Pre-commit hooks¶
Configured via cachix/git-hooks.nix (input pinned in flake.nix).
The .pre-commit-config.yaml symlink is generated by nix develop
into the Nix store and is .gitignored. Edits go in flake.nix's
pre-commit.settings.hooks block, not the symlink target.
Hooks: actionlint, check-jsonschema, commitizen (commit-msg),
deadnix, editorconfig-checker, markdownlint, nixfmt-rfc-style,
statix, typos, yamllint, shellcheck (skipping justfile), treefmt,
zizmor (--min-severity=low), readme-flake-show-fresh,
uses-sha-pinned.
markdownlint rule disables¶
.markdownlint.json disables eight rules. Rationale per rule:
| Rule | Name | Reason |
|---|---|---|
| MD007 | Unordered list indentation | mdformat's nested-list output uses 4-space indent, conflicting with the default 2-space expectation |
| MD013 | Line length | Docs site is MkDocs-Material with prose paragraphs; hard-wrapping at 80/100 chars fights table cells and admonitions |
| MD024 | Multiple headings same content | Dashboard and release-notes pages have repeated section headers per release / per artifact |
| MD032 | Lists surrounded by blank lines | Common false positives around mkdocs-material admonition trees |
| MD033 | Inline HTML | MkDocs-Material relies on <details>, <span> for admonitions and badges |
| MD038 | Spaces inside code-span markers | False positives on Mermaid edge-syntax (-->, ---) |
| MD041 | First line top-level heading | Some pages (release notes, dashboard) open with a macros / yaml block before the H1 |
| MD060 | Hard tabs | Source files include intentional tab characters (justfile rules); markdownlint should not police that |
Adding or removing a disable: update .markdownlint.json and this
table in the same PR so the rationale stays discoverable.
Lychee link checker¶
lychee.toml accepts 200, 204, 206, 302. 429 (rate-limited) is
not accepted — relying on lychee's built-in retry is preferable
to silently letting bot-blocked links pass. If a specific upstream
consistently rate-limits anonymous GETs and is known-good, add it to
the exclude regex list with a comment rather than expanding accept.
include_verbatim = false skips fenced-code-block content so command
examples are not crawled.
Typos¶
_typos.toml excludes tests/fixtures/** because fixtures contain
intentionally malformed content (bad versions, malformed renovate
configs); future fixtures may include realistic prose that would
otherwise trigger typo flags.
Zizmor¶
Workflow-security linter; --min-severity=low to catch everything.
Suppressions live in zizmor.yml with documented rationale per
suppressed rule + workflow. Do not raise --min-severity above
low without a security-review entry in .claude/CLAUDE.md.
Treefmt YAML quote gotcha¶
Prettier rewrites single-quoted YAML scalars to double-quoted. Run
nix fmt before push, or use double quotes from the start.
README flake-show auto-block¶
scripts/refresh-flake-show.sh regenerates the auto-block. Pre-commit
hook readme-flake-show-fresh has NIX_BUILD_TOP sandbox guard.