Problem
nix fmt runs treefmt (configured in treefmt.nix) over Cabal, Nix, YAML and Dhall files. Haskell is deliberately excluded, and the exclusion is the first thing the file says:
# Haskell (fourmolu) is deliberately NOT wired into `nix fmt`. fourmolu's
# --haddock-style is global (single-line | multi-line | multi-line-compact)
# with no per-comment or by-length mode, so any choice rewrites the
# hand-authored Haddock — single-line line-prefixes long block comments
# (annoying to copy), while multi-line bloats short ones. The source keeps a
# deliberate mix (short `-- |`, long `{- | … -}`), so Haskell stays a manual
# `fourmolu -i lib/ exe/ test/` step the author runs when they choose.
That rationale no longer holds, for two measurable reasons.
A global style is already chosen and already applied. fourmolu.yaml pins haddock-style: multi-line, and the tree is at fourmolu's fixed point under it — fourmolu --mode check lib/ exe/ test/ exits 0 with nothing to report. So wiring fourmolu into nix fmt is zero-churn today; the cost the comment warns about has already been paid by the manual step.
And the stated objection is false against the fourmolu in use (0.19.0.1). haddock-style governs how multi-line Haddock is rendered; it does not expand a short one-line -- | into a block. The tree carries 169 -- | occurrences alongside 492 {- | ones in lib/ exe/ test/ and still passes --mode check under haddock-style: multi-line, so the "deliberate mix" is preserved by fourmolu rather than threatened by it.
Approach
Enable the formatter in treefmt.nix and delete the stale comment:
programs.fourmolu.enable = true;
treefmt-nix's module invokes it as fourmolu -i -c over *.hs and adds --ghc-opt -X<Ext> for each entry in programs.fourmolu.ghcOpts (default BangPatterns, PatternSynonyms, TypeApplications). fourmolu finds fourmolu.yaml and picks up default-extensions from the Cabal file on its own, so no further configuration should be needed — but that is the thing to verify, since a parse difference between the treefmt invocation and the manual one would show up as churn rather than as an error.
One coupling is worth making explicit rather than inheriting. The module takes its binary from nixpkgs (haskellPackages.fourmolu), while the dev shell's fourmolu comes from the flake's haskell.nix tooling. Both currently resolve to 0.19.0.1, so they agree — but they can drift independently on a nix flake update, and two fourmolu versions formatting the same tree would fight: nix fmt would rewrite what the manual step just wrote, and the format CI job (nix fmt && git diff --exit-code) would fail on a tree that is clean under the dev-shell binary. Point programs.fourmolu.package at the same derivation the dev shell uses so there is one fourmolu in the repo.
Once nix fmt covers Haskell, the manual fourmolu -i lib/ exe/ test/ step in CLAUDE.md and docs/ becomes redundant and should be folded into nix fmt there too.
Prerequisites / Relations
Independent. Touches treefmt.nix, possibly flake.nix for the package pin, and the formatting instructions in CLAUDE.md. No compiler code involved.
Acceptance criteria
nix fmt formats Haskell, and running it on a clean checkout leaves the tree unchanged (which is what the format CI job already asserts with git diff --exit-code).
nix fmt and a direct fourmolu -i use the same fourmolu build, so neither can undo the other after a flake update.
- The formatting instructions no longer describe Haskell as a separate manual step.
Problem
nix fmtruns treefmt (configured intreefmt.nix) over Cabal, Nix, YAML and Dhall files. Haskell is deliberately excluded, and the exclusion is the first thing the file says:That rationale no longer holds, for two measurable reasons.
A global style is already chosen and already applied.
fourmolu.yamlpinshaddock-style: multi-line, and the tree is at fourmolu's fixed point under it —fourmolu --mode check lib/ exe/ test/exits 0 with nothing to report. So wiring fourmolu intonix fmtis zero-churn today; the cost the comment warns about has already been paid by the manual step.And the stated objection is false against the fourmolu in use (0.19.0.1).
haddock-stylegoverns how multi-line Haddock is rendered; it does not expand a short one-line-- |into a block. The tree carries 169-- |occurrences alongside 492{- |ones inlib/ exe/ test/and still passes--mode checkunderhaddock-style: multi-line, so the "deliberate mix" is preserved by fourmolu rather than threatened by it.Approach
Enable the formatter in
treefmt.nixand delete the stale comment:treefmt-nix's module invokes it as
fourmolu -i -cover*.hsand adds--ghc-opt -X<Ext>for each entry inprograms.fourmolu.ghcOpts(defaultBangPatterns,PatternSynonyms,TypeApplications). fourmolu findsfourmolu.yamland picks updefault-extensionsfrom the Cabal file on its own, so no further configuration should be needed — but that is the thing to verify, since a parse difference between the treefmt invocation and the manual one would show up as churn rather than as an error.One coupling is worth making explicit rather than inheriting. The module takes its binary from nixpkgs (
haskellPackages.fourmolu), while the dev shell'sfourmolucomes from the flake's haskell.nix tooling. Both currently resolve to 0.19.0.1, so they agree — but they can drift independently on anix flake update, and two fourmolu versions formatting the same tree would fight:nix fmtwould rewrite what the manual step just wrote, and theformatCI job (nix fmt && git diff --exit-code) would fail on a tree that is clean under the dev-shell binary. Pointprograms.fourmolu.packageat the same derivation the dev shell uses so there is one fourmolu in the repo.Once
nix fmtcovers Haskell, the manualfourmolu -i lib/ exe/ test/step inCLAUDE.mdanddocs/becomes redundant and should be folded intonix fmtthere too.Prerequisites / Relations
Independent. Touches
treefmt.nix, possiblyflake.nixfor the package pin, and the formatting instructions inCLAUDE.md. No compiler code involved.Acceptance criteria
nix fmtformats Haskell, and running it on a clean checkout leaves the tree unchanged (which is what theformatCI job already asserts withgit diff --exit-code).nix fmtand a directfourmolu -iuse the same fourmolu build, so neither can undo the other after a flake update.