"""Every repo path an agent doc points at must exist.
Agent docs are read by agents that cannot tell a stale pointer from a live one.
A rename that orphans a reference is silent until an agent follows it, wastes a
turn, and then improvises -- which is exactly the failure mode guidance is
supposed to prevent.
Real instances this would have caught, all live on main when this landed:
- CLAUDE.md pointed at `desktop/CLAUDE.md` and `desktop/e2e/SKILL.md`; both
moved under `desktop/macos/` long before.
- desktop/macos/AGENTS.md pointed at `.claude/skills/firebase/SKILL.md` and
`.claude/skills/sentry-release/SKILL.md`, which are agent-local and have
never existed in this repo.
- desktop/macos/AGENTS.md told agents to launch via `./reset-and-run.sh`,
which does not exist.
What counts as a reference: a markdown link to a relative path, and a backticked
token that looks like a repo path (contains `/` and a known source extension, or
starts with a top-level repo directory). Bare filenames like `auth.py` are
shorthand, not pointers, and are ignored -- resolving those would need judgment,
and a check that needs judgment is a check that gets an allowlist.
"""
from __future__ import annotations
import re
import subprocess
import sys
import tempfile
from pathlib import Path
EXTRA_DOCS = ("CLAUDE.md", "PRODUCT.md", ".github/agent-docs", ".cursor/cloud-agent-environment.md")
SOURCE_SUFFIXES = {
".md", ".py", ".sh", ".yaml", ".yml", ".json", ".dart", ".swift",
".ts", ".tsx", ".rs", ".mdx", ".toml", ".kt", ".java", ".h", ".c",
}
REPO_ROOTS = (
".github/", ".cursor/", "app/", "backend/", "desktop/", "docs/",
"infrastructure/", "omi/", "product/", "scripts/", "web/",
)
MD_LINK = re.compile(r"\[[^\]]*\]\(\s*(?!https?:|mailto:|#)([^)\s#]+)")
BACKTICK = re.compile(r"`([^`\n]+)`")
PLACEHOLDER = re.compile(r"[<>{}*]|\.\.\.|\bYYYY\b|\bXXXX\b|20260628-short-description")
def is_repo_path(token: str) -> bool:
"""True when a backticked token is a pointer rather than shorthand."""
if PLACEHOLDER.search(token) or " " in token:
return False
if token.startswith(REPO_ROOTS):
return True
return "/" in token and Path(token).suffix in SOURCE_SUFFIXES
def ignored(repo: Path, candidates: list[Path]) -> bool:
"""True when git deliberately ignores the path.
Build outputs, virtualenvs, .env files, and generated sources are absent in a
clean checkout by design. Pointing at them is correct documentation, not a
stale reference, so gitignore is the repo's own answer to 'is this expected
to be missing?' -- no hand-maintained allowlist required.
"""
rels = []
for c in candidates:
try:
rels.append(str(c.relative_to(repo)))
except ValueError:
continue
if not rels:
return False
result = subprocess.run(
["git", "check-ignore", "--quiet", "--no-index", "--stdin"],
cwd=repo,
input="\n".join(rels),
capture_output=True,
text=True,
)
return result.returncode == 0
def resolve(repo: Path, doc: Path, ref: str) -> bool:
"""A reference resolves if it exists relative to the doc or the repo root."""
ref = ref.rstrip("/")
if not ref:
return True
candidates = [doc.parent / ref, repo / ref]
if any(c.exists() for c in candidates):
return True
return ignored(repo, candidates)
def collect_docs(repo: Path) -> list[Path]:
docs = sorted(
p for p in repo.rglob("AGENTS.md")
if "node_modules" not in p.parts and ".build" not in p.parts
)
for extra in EXTRA_DOCS:
target = repo / extra
if target.is_dir():
docs.extend(
sorted(p for p in target.rglob("*.md") if "superpowers" not in p.parts)
)
elif target.exists():
docs.append(target)
return docs
def check_doc(repo: Path, doc: Path) -> list[str]:
text = doc.read_text(encoding="utf-8")
rel = doc.relative_to(repo)
errors = []
seen: set[str] = set()
for ref in MD_LINK.findall(text):
if ref in seen or PLACEHOLDER.search(ref):
continue
seen.add(ref)
if not resolve(repo, doc, ref):
errors.append(f"{rel}: markdown link -> '{ref}' does not exist")
for token in BACKTICK.findall(text):
token = token.strip()
if token in seen or not is_repo_path(token):
continue
seen.add(token)
if not resolve(repo, doc, token):
errors.append(f"{rel}: reference `{token}` does not exist")
return errors
def self_test() -> None:
with tempfile.TemporaryDirectory() as tmp:
repo = Path(tmp)
(repo / "backend").mkdir()
(repo / "backend" / "real.py").write_text("")
doc = repo / "AGENTS.md"
doc.write_text("see `backend/real.py` and [ok](backend/real.py)\n")
assert check_doc(repo, doc) == [], "existing references must pass"
doc.write_text("see `backend/gone.py`\n")
assert check_doc(repo, doc), "missing backticked repo path must fail"
doc.write_text("see [x](backend/gone.py)\n")
assert check_doc(repo, doc), "missing markdown link must fail"
doc.write_text("run `auth.py` and `make setup` and `pip install -e .`\n")
assert check_doc(repo, doc) == [], "bare shorthand must be ignored"
doc.write_text("see `docs/<component>/guide.md` and `changelog/YYYY-x.json`\n")
assert check_doc(repo, doc) == [], "placeholders must be ignored"
(repo / "backend" / "AGENTS.md").write_text("run `scripts/x.sh`\n")
(repo / "backend" / "scripts").mkdir()
(repo / "backend" / "scripts" / "x.sh").write_text("")
assert check_doc(repo, repo / "backend" / "AGENTS.md") == [], (
"component-relative reference must resolve"
)
def main() -> int:
self_test()
repo = Path(__file__).resolve().parents[2]
errors = [e for doc in collect_docs(repo) for e in check_doc(repo, doc)]
if errors:
print("Agent docs reference paths that do not exist:\n", file=sys.stderr)
for e in errors:
print(f" {e}", file=sys.stderr)
print(
"\nFix the path, or delete the pointer if the target is gone.\n"
"Agents cannot tell a stale pointer from a live one.",
file=sys.stderr,
)
return 1
print("agent doc references OK")
return 0
if __name__ == "__main__":
raise SystemExit(main())