v0.20.0
First release cut since v0.19.0. It consolidates the batch of checks, commands,
and verdict changes that landed on main after v0.19.0 (none of which were tagged
individually) into a single release.
New checks
coverage(recommended, advisory): every detected language ecosystem
(rust, js, python) must wire up some coverage tool — presence-only, not a
threshold. Accepts a config file, a CI step or task-runner target, or a manifest
dependency; skips when no rust/js/python ecosystem is present.allow-auto-merge(recommended, fixable): asserts GitHub'sallow_auto_merge
setting matches a declared preference (default off); opt in with
[allow-auto-merge] enabled = true. The fix PATCHes the setting to match.artifacts-built(recommended, warns): for every build artifact detection
finds (napi addon, PyO3/maturin wheel, Magnus/rb-sys gem, Tauri app, web/site
bundle, compiled binary), greps the workflows for the build step it needs and
reports the ones with no coverage; conservative static parse, so it warns rather
than gates.pinned-versions(recommended, check-only): flags floating version
specifiers per ecosystem (npm/bun exact semver, python==X.Y.Z, ruby= X.Y.Z,
actions a 40-char commit SHA; cargo advisory by default sinceCargo.lockpins
the build). Configure scope via[pinned-versions]; no auto-fix.dependabot-automerge(recommended, fixable): when a repo opts in with
[allow-auto-merge] dependabot = true, wants a workflow that auto-merges
dependabot's non-major PRs once their required checks go green (also requires
enabled = true). The fix writes.github/workflows/dependabot-automerge.yml.
New commands
housekeeper detect: prints the repo's detected ecosystems, typed-language
layers, and build artifacts, plus the recommended fleet setup per ecosystem
(--jsonfor machine output). Backed by a new artifact-detection layer in
languages.pythat reads source manifests and skips vendored/build trees.housekeeper new <name> --flavor rust|bun|python: scaffolds a
fleet-compliant repo skeleton (CI/housekeeping workflows, committed git hooks,
.housekeeping.toml, LICENSE,scripts/dev.sh, dependabot config, CODEOWNERS,
notes/design.md), then prints the human next steps it can't do itself. The
opt-in--dependabot-automergeflag (off by default) additionally writes the
dependabot-automergeworkflow and sets[allow-auto-merge] enabled = true, dependabot = true, so the new repo passes that check out of the gate.
Changed verdicts / behavior
lockfilesgit-history staleness fallback: for ecosystems with no native
sync check (ruby's Gemfile.lock, go's go.sum), the check now compares commit
timestamps and flags a lockfile whose manifest was committed in a strictly later
commit as likely stale; it also distinguishes a gitignored lockfile and falls
back to the heuristic when a native tool is absent. Verdict change: can now fail
ruby/go repos carrying a stale-by-history lockfile.- Nested-aware ecosystem detection:
detect_ecosystemsnow returns one
Ecosystemper location (each carrying itsdir) instead of probing only the
repo root, so nested manifests undercrates/*are detected.lockfiles,
dependabot,ci-exists,coverage, andgitignorenow grade nested packages
per-directory, so repos with nested packages (entl, disponent) may now fail for
genuinely-ungraded nested lockfiles, dependabot coverage, or CI. Closes #90. repo-metareconciles a README declaration: description and topics are
declared at the top of the README via<!-- housekeeper:description ... -->and
<!-- housekeeper:topics a, b, c -->markers, and the check asserts GitHub's
actual values match them (README = source of truth; topics validated to GitHub's
rules). Verdict change: a repo with no markers now fails with an adoption nudge.
housekeeper fix repo-metapushes the declared values to GitHub, or — when a
repo has no markers yet — seeds them into the README from GitHub's current values.bunlockfile check no longer runspostinstall: the frozen
bun install --dry-runnow passes--ignore-scripts(matching npm), so a repo
whose postinstall needs network/tools is no longer falsely flaggedbun.lock
out of sync after the frozen check itself passed.- ruby
testsignal recognizes theruby -Itest test/...idiom:ci-exists
now credits ruby tests run that way, so it no longer under-credits ruby.