repo-doctor · git:20261005.e810047 · 2026-10-05 · sha256 d038c6a056e06b1c

repo-doctor git:20261005.e810047A

Immutable. This exact content never changes and is served at /api/v1/blob/d038c6a056e06b1c.

---
name: repo-doctor
description: "Audit any repo against the agentic-quality doctrine; create, audit, upgrade or org-survey its AGENTS.md. Triggers on: repo doctor, repo audit, agentic quality, agent-friendly, write AGENTS.md, audit AGENTS.md, upgrade AGENTS.md, AGENTS.md not loading, CLAUDE.md shadows AGENTS.md, AGENTS.md org survey, stale AGENTS.md, monorepo structure, nested CLAUDE.md."
license: MIT
allowed-tools: "Read Bash Glob Grep Agent"
metadata:
  author: claude-mods
  related-skills: "doc-scanner, adr-ops, refactor-ops, techdebt, scaffold, project-planner, github-ops"
---

# Repo Doctor

Scores a repository against the **agentic-quality doctrine** (the cross-repo standard
in [rules/agentic-quality.md](../../rules/agentic-quality.md) for code, comments, docs
and structure a cold agent session can navigate), and owns the **AGENTS.md protocol**:
creating, auditing, upgrading and org-surveying a repo's entry doc.

Read-only by default. The scorer, the scan, the audit and the survey never write. The
only writing step is `agents-md.py scaffold --write`, which **creates** an AGENTS.md and
refuses to overwrite one (there is deliberately no `--force`).

## AGENTS.md: create, audit, upgrade, survey

The protocol (what goes in, what stays out, the 150/200-line budget and how to split,
CLAUDE.md shadowing, staleness in commits) is
[references/agents-md-protocol.md](references/agents-md-protocol.md). Read it before
writing or judging an entry doc. The load-bearing fact: **Claude Code reads AGENTS.md
only when no `CLAUDE.md`, `.claude/CLAUDE.md` or `CLAUDE.local.md` sits in the working
directory or above it**, unless that CLAUDE.md imports `@AGENTS.md`.

```bash
# 1. Deep scan: deterministic facts JSON; every fact cites file:line or a command,
#    plus landmine CANDIDATES from git history (always questions, never facts)
python scripts/repo-scan.py --repo path/to/repo --json > facts.json

# 2. Create: draft from the facts (commands only from declared scripts, tagged [untested])
python scripts/agents-md.py scaffold --repo path/to/repo --facts facts.json > AGENTS.draft.md
python scripts/agents-md.py scaffold --repo path/to/repo --write      # creates; never overwrites

# 3. Audit, then upgrade with a reviewable patch
python scripts/agents-md.py audit --repo path/to/repo                 # exit 10 on warn/crit
python scripts/agents-md.py audit --repo path/to/repo --diff > agents-md.patch
git -C path/to/repo apply "$PWD/agents-md.patch"

# 4. Survey a GitHub org: read-only gh api, no clones, writes nothing
python scripts/agents-md.py survey --org my-org --json | jq '.meta'
```

Workflow rules:

1. **Scan before drafting.** The scaffold's archetype templates
   ([assets/agents-md/](assets/agents-md/): PHP CMS + DDEV + bundler, Node/TS app,
   Python service, static site) hold slots, not claims. Everything the scan can't
   verify becomes a `TODO(owner):` question.
2. **The owner finishes the draft.** Answer or delete every `TODO(owner)`, run each
   command once and drop its `[untested]` tag, delete the DRAFT comment. The audit flags
   all three until done. Optional synthesis (one read-only Explore subagent per custom
   code area, at most four, fed the facts JSON) is in the protocol's section 8.
3. **The patch never removes landmines.** `--diff` adds missing-section stubs, an
   `@AGENTS.md` import for a shadowing CLAUDE.md, annotations on dead commands, and moves
   for oversized sections (setup prose to README, subsystem detail to a nested
   AGENTS.md, the rest to `docs/agents/`). It leaves the overview, Commands, Landmines and
   Deploy where they are.
4. **Pair with Claude Code's own checks.** `/doctor prompt-audit` does the semantic pass
   (outdated or contradictory instructions); this tooling is the deterministic, CI-able
   one (protocol section 7).

Never run repo tooling to "verify" a command: Composer plugins, justfile backticks and
`make $(shell ...)` execute repo code even when listing. The scan reads tracked files and
git metadata only, never opens secret files, and keeps variable names (not values) from
`.env.example`.

## Repo scorer

```bash
python scripts/repo-doctor.py                          # audit cwd, human panel
python scripts/repo-doctor.py --repo path/to/repo      # audit another repo
python scripts/repo-doctor.py --json | jq .data.grade  # machine-readable
python scripts/repo-doctor.py --strict                 # CI gate: exit 10 below B
```

Six dimensions, 0-5 each, weighted into a letter grade:

| Dimension | Measures | Weight |
|---|---|---|
| `entry_docs` | AGENTS.md/CLAUDE.md present · Landmines section · 200-line budget · freshness in **commits-since-touched** · a CLAUDE.md that shadows AGENTS.md | 2.0 |
| `docs_health` | README · docs/ index when >6 files · ghost links in the index | 1.5 |
| `comments` | contract blocks on the largest source files · section markers in files >400 lines | 2.0 |
| `structure` | monster files (>800 warn, >1500 crit; generated exempt) · repo-root junk | 2.0 |
| `enforcement` | tests · CI · single `check` entry point · invariant gate scripts | 1.5 |
| `doc_pairing` | fraction of recent feat/fix commits touching a `*.md` in the same commit | 1.0 |

Full rubric (each check, threshold and fix): [references/scoring-rubric.md](references/scoring-rubric.md).

### Audit workflow

1. **Run the scorer.** On cp1252/plain terminals it degrades to ASCII; nothing is written.
2. **Read findings top-down** (crit, then warn, then info). Facts (monster-file list,
   pairing ratio, entry-doc age) ride in `--json` under `.data.facts`.
3. **Verify before acting.** The scorer is heuristic: a flagged 900-line file may be a
   justified single-writer module (then it needs the guard comment, section map and gate,
   not a split); a "stale" AGENTS.md may describe code that genuinely didn't change.
4. **Remediate via the owning skill** (below). Batch fixes into small commits: entry doc
   first (highest leverage), then indexes, guard comments, splits.
5. **Re-run to confirm** the grade moved. For fleets, loop `--json` over repo roots, or
   use `agents-md.py survey --org` for the entry-doc column without cloning.

## Remediation map: who owns each fix

| Finding | Owner |
|---|---|
| Missing/weak/oversized AGENTS.md, shadowing CLAUDE.md | `agents-md.py scaffold` / `audit --diff` (above); hand skeleton: [assets/AGENTS-template.md](assets/AGENTS-template.md) |
| Multi-platform doc mess (CLAUDE.md + COPILOT.md + CURSOR.md ...) | `doc-scanner` (consolidate), then audit the result here |
| Missing docs index | Write from [assets/docs-index-template.md](assets/docs-index-template.md) |
| Monster file needs splitting | `refactor-ops` (extract-module patterns, circular-dep cautions) |
| Monster file is *justified* | Guard comment + section map + a `scripts/check-*` invariant gate ([references/comment-doctrine.md](references/comment-doctrine.md)) |
| Missing/weak comments | [references/comment-doctrine.md](references/comment-doctrine.md): contract blocks, WHY-only, guard comments, citations |
| Decisions undocumented | `adr-ops` |
| Stale PLAN/roadmap | `project-planner` |
| Code-level debt (duplication, dead code, security) | `techdebt`: deliberately NOT scored here |
| New repo from scratch | `scaffold` + the templates in assets/ |

Boundary: repo-doctor audits **repo-level conventions**; `techdebt` scans **code-level
debt**; `review`/code-review judge **diffs**. Don't blur the three.

## Nested entry docs and monorepos

Nest an AGENTS.md only where a subsystem has its own contract (invariant law, audience
or gate); the root links every nested doc, and a CLAUDE.md beside a nested AGENTS.md
shadows it (protocol section 6). For large multi-subsystem repos the root entry doc is
judged as a *router* (invariants + ownership table), each contracted package needs its
own entry doc and `check`, and cross-package invariants need mechanical gates:
[references/monorepo-structure.md](references/monorepo-structure.md). Run the scorer
per package as well as at root.

## Resources

| Resource | What it owns |
|---|---|
| [scripts/repo-doctor.py](scripts/repo-doctor.py) | The scorer: six dimensions, findings, grade; `--json` envelope `claude-mods.repo-doctor/v1`; `--strict` CI gate |
| [scripts/repo-scan.py](scripts/repo-scan.py) | Deep scan: manifests, DDEV, deploy hooks and the scripts they call, CI, tests, generated output, code areas, size outliers, docs, env names, git-history landmine candidates; `--json` (`repo-scan/v1`), `--only` |
| [scripts/agents-md.py](scripts/agents-md.py) | `scaffold` (`--write` creates only), `audit` (`--diff` patch), `survey --org` / `--remote` (GET-only); exit 10 on findings |
| [scripts/check-memory-docs.py](scripts/check-memory-docs.py) | Tripwire for the Claude Code facts the protocol encodes: `--offline` in PR CI, `--live` in the scheduled freshness workflow |
| [references/agents-md-protocol.md](references/agents-md-protocol.md) | The AGENTS.md protocol: contents, exclusions, size and split, CLAUDE.md shadowing, staleness, how the tools fit beside `/doctor` |
| [references/scoring-rubric.md](references/scoring-rubric.md) | Every scorer check: what it measures, threshold, why, and the fix |
| [references/comment-doctrine.md](references/comment-doctrine.md) | Contract blocks, WHY-only inline, guard comments, section markers, format-at-site, citations |
| [references/monorepo-structure.md](references/monorepo-structure.md) | Structuring very large monorepos for agentic development |
| [assets/agents-md/](assets/agents-md/) | Archetype templates the scaffold fills (usable by hand: the slots are documented in each file's header) |
| [assets/AGENTS-template.md](assets/AGENTS-template.md) | Hand-fill entry-doc skeleton with the mandatory Landmines section |
| [assets/docs-index-template.md](assets/docs-index-template.md) | `docs/00_INDEX.md` skeleton with the two anti-rot rules baked in |