--- name: repo-hygiene-audit description: > Repeatable hygiene audit across the homelab / pbs / docker project domains. Runs scripted, read-only checks for git auditability and .git ownership drift, .env file permissions, inline secrets in compose files, non-git directories, uv-init leftover stubs, docker-compose.yml -> compose.yml naming, branch and master-vs-main default-branch state, dirty trees, stray worktrees, and herbygitea SSH-alias residue — then emits a findings report mapped to the remediation-plan phases. Use when asked to audit repos, run a repo-hygiene sweep, check project folders for drift, do the weekly/recurring guided review, or verify repos against conventions before a commit/merge. --- # Repo Hygiene Audit Makes the one-time 2026-05-19/20 documentation/repo audit **repeatable** so the project folders don't silently drift back into inconsistency. The mechanical checks are scripted (`scripts/audit.py`); the judgement calls (semantic doc freshness, policy decisions) stay with the human/agent driving the review. This skill is **read-only against the trees it scans.** It never edits, commits, or pushes anything in the audited repos — it reports. Remediation is a separate, deliberate step the operator drives. ## When to run - The recurring guided review (current cadence: **weekly, manually triggered**). - After landing a batch of new repos or scaffolds, to confirm they start clean. - Before a commit/merge sweep, to catch state that should be resolved first. - Whenever asked to "audit repos", "check for drift", "repo hygiene sweep". ## The method The original audit scored docs on a five-dimension rubric — **accuracy (heaviest) → freshness → internal contradiction → completeness → role fit** — and verified documented commands/paths against the real tree (a confidently wrong doc is worse than a missing one). That semantic scoring is the human part. This skill automates the **mechanical enumeration** underneath it: sweep every repo in every domain and flag the objective signals that drift produces. Default domains scanned: | Domain | Roots scanned | |--------|---------------| | `homelab` | `/opt/projects/homelab/*` | | `pbs` | `/opt/projects/pbs/*` | | `docker` | `/opt/projects/docker/*`, `~/projects/docker/*` (compose stacks) | `docker` repos are treated as compose stacks: README expected, **no per-stack CLAUDE.md** (per the locked doc-role convention). **The Obsidian vault (`wiki-vault`, `wiki-context`) is intentionally out of scope.** It's an MCP-owned, managed surface — the vault MCP maintains its own context — so a second scanner poking at it risks interference. The original audit covered it as a "root" domain; this recurring skill deliberately does not. The `--scan` / `--repo` escape hatch can still point at it manually if ever truly needed; don't re-add it to the defaults. ## Workflow ### Step 1 — Run the scripted sweep ```bash cd repo-hygiene-audit # Human-readable, all domains (default config): python scripts/audit.py # Phase-mapped markdown you can paste into the remediation plan: python scripts/audit.py --format md -o findings-$(date +%Y%m%d).md # Machine-readable for diffing week-over-week: python scripts/audit.py --format json -o findings-$(date +%Y%m%d).json ``` No third-party dependencies — plain `python3` (or `uv run python`) is enough. ### Step 2 — Triage by phase Findings are grouped into the categories that map onto the remediation plan's phases (see `references/findings-format.md`): - **SECURITY** (Phase 2) — world-readable / wrong-mode `.env`, inline compose secrets. - **AUDITABILITY** (Phase 3) — missing `.git`, dubious ownership, `.git`/dir owner drift, non-git dirs with content. - **CLEANUP** (Phase 4) — uv-init stubs, compose naming, stale review docs, herbygitea residue, stray backup dirs. - **GIT_STATE** — master-vs-main default, dirty trees, leftover `docs-audit` branches, unpushed commits, stray worktrees. - **DOCS** — missing README/CLAUDE.md, oversized CLAUDE.md (possible README clone). Start at `high`, work down. The `INVENTORY` block also lists every repo (even clean ones) so you can confirm the sweep saw what you expected. ### Step 3 — Semantic doc pass (human judgement) For each repo with stale-looking docs, apply the five-dimension rubric by hand: read README + CLAUDE.md against the actual tree. The script flags *candidates* (missing docs, bloated CLAUDE.md, stale review artifacts); it can't judge whether the prose is *accurate*. That's the reviewer's call. ### Step 4 — Decide remediation, don't auto-fix The hint on each finding is the suggested remediation, **not** an action the skill takes. Sequence fixes through the normal flow (and the manual-push rule for GitHub-destined repos). For the safe.directory caveat specifically: prefer a **scoped** `safe.directory ` entry over the `*` wildcard, which disables the dubious-ownership safety check everywhere. ### Step 5 — Persist the run Save the markdown report alongside the project plan (or as a vault session note) so the next run can diff against it. Drift shows up as new findings; remediation shows up as findings that disappear. ## Scripted checks `scripts/audit.py` is the engine. Each check is read-only and resilient (one repo erroring never aborts the sweep). Full catalogue with rationale in `references/check-catalog.md`. Selected flags: | Flag | Purpose | |------|---------| | `--format {text,json,md}` | output format (default `text`) | | `-o, --output PATH` | write report to a file instead of stdout | | `--config FILE.json` | override the domain map (`{domain: {scan:[], repos:[]}}`) | | `--scan NAME=PATH` | ad-hoc: scan immediate children of PATH as repos | | `--repo NAME=PATH` | ad-hoc: treat PATH itself as one repo | | `--only CATEGORY` | restrict output to one or more categories | | `--fail-on SEVERITY` | exit non-zero if any finding at/above that severity (CI/automation hook) | ## Available resources | Resource | When to load | Purpose | |----------|--------------|---------| | `scripts/audit.py` | Every run | The read-only check engine | | `references/check-catalog.md` | Interpreting a finding | What each check looks for + why it matters | | `references/findings-format.md` | Wiring output into the plan | Output schema + category→phase mapping |