From 94efbe67642de75c5a44af1fde91a7e4a2cd3adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Ho=C3=9F?= Date: Thu, 9 Jul 2026 23:47:11 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20ci-harper=20=E2=80=94=20grammar=20for?= =?UTF-8?q?=20prose,=20complementing=20typos=20for=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit harper-cli joins the shared lint gate: typos owns spelling (code identifiers, low-FP corrections), harper owns grammar (repetition, agreement, style) — so the wrapper ships with SpellCheck off (typos' job) and UseTitleCase off (heading case is a style choice). Repos append rules via HARPER_IGNORE; scope defaults to docs/ and kb/ (the prose homes), with explicit paths overriding. Exits non-zero via xargs when any file has findings. Heads-up for adopters: harper joins wrapped lines, so hand-wrapped markdown can trip false positives (a split word across a line break reads as one word) — repos with tightly wrapped design docs may want this advisory rather than gating. Co-Authored-By: Claude Fable 5 Signed-off-by: Sebastian Hoß --- flake.nix | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 41f9615..e075237 100644 --- a/flake.nix +++ b/flake.nix @@ -114,6 +114,7 @@ actionlint shellcheck # actionlint shells out to it for run: blocks markdownlint-cli2 + harper # grammar/style for prose; typos stays for code identifiers ]; # One canonical `ci-` command per shared lint tool, wrapping the EXACT @@ -132,6 +133,25 @@ # actionlint finds shellcheck on PATH, which the devShell provides. (pkgs.writeShellScriptBin "ci-actionlint" ''exec ${pkgs.actionlint}/bin/actionlint "$@"'') (pkgs.writeShellScriptBin "ci-markdown" ''exec ${pkgs.markdownlint-cli2}/bin/markdownlint-cli2 "**/*.md" "$@"'') + # harper lints PROSE (grammar, repeated words, style) where typos + # lints CODE (identifier spelling) — complements, not substitutes, + # so SpellCheck is off here; heading case is a style choice, so + # UseTitleCase is off too. Repos append rules via HARPER_IGNORE. + # Scope defaults to docs/ and kb/ (the prose homes); pass paths to + # override. Exits non-zero via xargs when any file has findings. + (pkgs.writeShellScriptBin "ci-harper" '' + set -eu + ignore="SpellCheck,UseTitleCase''\${HARPER_IGNORE:+,$HARPER_IGNORE}" + if [ "$#" -gt 0 ]; then + roots=("$@") + else + roots=() + for d in docs kb; do [ -d "$d" ] && roots+=("$d"); done + [ "''\${#roots[@]}" -gt 0 ] || roots=(.) + fi + ${pkgs.findutils}/bin/find "''\${roots[@]}" -name '*.md' -not -path './.git/*' -print0 \ + | ${pkgs.findutils}/bin/xargs -0 ${pkgs.harper}/bin/harper-cli lint --ignore "$ignore" + '') ]; # Assemble a repo's devShell: the shared lint gate plus the repo's own @@ -154,8 +174,8 @@ packages = lintTools pkgs ++ lintCommands pkgs ++ packages; shellHook = '' if [ -t 1 ]; then - echo "metio devshell — shared lint gate: reuse, typos, yamllint, actionlint, markdownlint-cli2" - echo " run any the CI way: ci-reuse, ci-typos, ci-yaml, ci-actionlint, ci-markdown" + echo "metio devshell — shared lint gate: reuse, typos, yamllint, actionlint, markdownlint-cli2, harper" + echo " run any the CI way: ci-reuse, ci-typos, ci-yaml, ci-actionlint, ci-markdown, ci-harper" ${menu} fi ''