Single source of truth for pre-commit hook configuration across every dryvist repo. Two consumption paths share these artifacts.
- Nix flake module — Repos with
flake.nix+.envrc(terraform-, ansible-, nix-*, orbstack-kubernetes) consumeinputs.nix-devenv.flakeModules.{base,terraform,ansible,python,nix,markdown}. Versions pinned viaflake.lock. - Static YAML copy — Repos without Nix (cribl packs, raw CI
checkouts, external contributor clones) copy
templates/<profile>.yamlat scaffold time. Renovate keepsrev:pins fresh.
Both paths reference the same canonical config files in configs/ for
tools that demand a config file on disk (ansible-lint, yamllint, tflint).
Markdown lint config lives at the dryvist/.github root
(../.markdownlint-cli2.yaml) for backwards compatibility with existing
markdownlint workflow consumers.
precommit/
├── configs/
│ ├── ansible-lint.yml # canonical .ansible-lint
│ ├── tflint.hcl # canonical .tflint.hcl
│ └── yamllint.yml # canonical .yamllint.yml
├── templates/
│ ├── base.yaml # common 80% (no language-specific hooks)
│ ├── terraform.yaml # base + terraform_fmt/validate/tflint/docs
│ ├── ansible.yaml # base + ansible-lint + yamllint
│ └── python.yaml # base + ruff + ruff-format + mypy
└── README.md
The markdownlint canonical (.markdownlint-cli2.yaml) stays at the
repo root — it predates this directory and is referenced by existing
consumer workflows. New canonical configs land here in configs/.
This directory is consumed by reference, not installed. Pick the path that matches the consumer repo once.
No copy step needed. Add the nix-devenv flake input and one
imports = [ ... ] line in the consumer's flake.nix (see Usage).
Fetch the matching template at scaffold time, plus the configs the hooks need:
# Pick base / terraform / ansible / python
gh api repos/dryvist/.github/contents/precommit/templates/terraform.yaml \
-H "Accept: application/vnd.github.raw" > .pre-commit-config.yaml
# Materialize tflint canonical (terraform profile only)
gh api repos/dryvist/.github/contents/precommit/configs/tflint.hcl \
-H "Accept: application/vnd.github.raw" > .tflint.hcl
# Markdown lint config lives at the .github root
gh api repos/dryvist/.github/contents/.markdownlint-cli2.yaml \
-H "Accept: application/vnd.github.raw" > .markdownlint-cli2.yaml
# Zizmor policy for workflow security
gh api repos/dryvist/.github/contents/zizmor.yml \
-H "Accept: application/vnd.github.raw" > zizmor.yml
pre-commit installFor ansible.yaml, also fetch precommit/configs/ansible-lint.yml
to .ansible-lint and precommit/configs/yamllint.yml to
.yamllint.yml. For python.yaml, no extra configs needed beyond
optional repo-local pyproject.toml for mypy / ruff.
In the consumer's flake.nix:
{
inputs.nix-devenv.url = "github:dryvist/nix-devenv";
inputs.flake-parts.url = "github:hercules-ci/flake-parts";
outputs = inputs@{ flake-parts, nix-devenv, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
systems = [ "aarch64-darwin" "x86_64-linux" ];
imports = [ inputs.nix-devenv.flakeModules.terraform ];
};
}Profile picks one of {base, terraform, ansible, python, nix, markdown}.
The module imports dev-hygiene (base hooks) and layers the matching
language hooks on top. No .pre-commit-config.yaml needed in the repo.
base, nix, and markdown are aliases for dev-hygiene — the base
already covers Nix lints (deadnix, statix) and markdownlint via
file-glob filtering. Repos pick one of those aliases for readability;
the runtime behavior is identical.
After running the Installation step above, hooks run automatically on
git commit. To run them ad-hoc:
pre-commit run --all-filesRenovate's custom manager in dryvist/.github keeps rev: pins in the
copied .pre-commit-config.yaml fresh going forward. Sync of the
config files themselves (.tflint.hcl, etc.) is still manual today —
extending the Renovate custom manager to cover them is tracked
separately.
This directory exposes the following surfaces:
| Path | Purpose |
|---|---|
configs/ansible-lint.yml |
Canonical ansible-lint (production profile, fqcn + no-changed-when) |
configs/tflint.hcl |
Canonical tflint (terraform plugin, recommended preset, docs rules) |
configs/yamllint.yml |
Canonical yamllint (line-length 160 warn, octal forbidden, ansible-lint-compatible) |
templates/base.yaml |
Common-80% static .pre-commit-config.yaml for non-Nix consumers |
templates/terraform.yaml |
base plus terraform_fmt / validate / tflint / docs |
templates/ansible.yaml |
base plus ansible-lint + yamllint |
templates/python.yaml |
base plus ruff / ruff-format / mypy |
Adding a new profile means both paths stay in sync:
- Nix side — add
flake-modules/profiles/<name>.nixindryvist/nix-devenvand exposeflakeModules.<name>in itsflake.nix. Validate with a smoke-test consumer undertests/profile-modules/<name>/. - YAML side — add
templates/<name>.yamlhere that mirrors the Nix profile's hook set. - Document both paths in this README's
Layoutsection.
Profile hooks must stay in sync between the two paths. The Nix smoke
tests in dryvist/nix-devenv catch hook-name drift in git-hooks.nix;
no equivalent test exists for the YAML templates yet (a pre-commit dry-run against a representative repo is the manual check).
configs/holds files that tools demand on disk. Tools that accept all config via CLI args ship their canonical at the repo root (see.markdownlint-cli2.yaml).- Each merged config picks the most-common variant from the inventory rather than the strictest superset, to minimize migration churn. Consumers add stricter rules locally until a critical mass agrees to lift them into the canonical.
- AWS / GCP / Azure tflint plugins stay opt-in per repo. Their
rulesets are large and noisy on repos that don't target that cloud.
The canonical
tflint.hclenables only the core terraform plugin. banditanddetect-secretsappear in one inventory repo each and are NOT in the python template. Repos that want them add arepo:block locally.checkovfor terraform appears in three repos and is NOT in the terraform template. Run time dominates the hook cycle; consumers opt in locally viapre-commit.settings.hooks.checkov.enable = true;(Nix path) or arepo:block (YAML path).
Apache-2.0 — inherited from the dryvist/.github root.