# Link Rot Detection

> Use when authoring or reviewing a periodic-scan job that walks every external link in a markdown content set and flags 404s, redirects to unrelated content, and connection failures. Activate this skill whenever the task says 'check our links' or mentions a link-rot scan, broken-link audit, or link-health report. Do NOT use for live runtime link checking inside the rendered page (use a frontend a11y / UX skill) or for chasing a specific broken-link incident from a user report (use debugging).

- Skill: `jacob-balslev/link-rot-detection` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add jacob-balslev/link-rot-detection`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jacob-balslev/link-rot-detection/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- License: MIT
- Author: jacob-balslev (https://skillmd.com/u/jacob-balslev)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/jacob-balslev/link-rot-detection

---


# Link-Rot Detection

## Concept of the skill

**What it is:** The scheduled audit mechanism that scans markdown content for external links that no longer resolve correctly.
**Mental model:** Treat link checking as a batch health report, not a live page-rendering feature.
**Why it exists:** Broken or redirected links erode trust quietly, so the project needs a repeatable scan with clear evidence.
**What it is NOT:** It is not a one-off production incident investigation or UI design for broken-link badges.
**Adjacent concepts:** Markdown link extraction, status-code classification, soft-404 detection, polite crawling.
**One-line analogy:** It is a periodic inspection report for all outbound references.
**Common misconception:** HTTP 200 means healthy; soft-404s, unrelated redirects, and rate-limit behavior also need interpretation.

## Coverage

- Markdown link extraction — pulling every `[text](url)` and `[text][ref]` reference link out of every `.md` and `.mdx` file in the content tree
- External vs internal classification — what counts as external (different host) and what gets skipped (relative path, anchor link, mailto, tel)
- Status-code interpretation — 200 is healthy, 301/308 is a redirect (record the new URL but don't fail), 302/307 is transient (re-check next run), 404/410 is dead (flag), 5xx is transient (retry with backoff before flagging)
- Soft-404 detection — pages that return HTTP 200 but render an "unknown page" interstitial (compare body length / content against known soft-404 patterns)
- Rate-limiting and politeness — concurrent request budget per origin host, honoring `robots.txt` crawl-delay, exponential backoff on 429
- Reporting shape — the scanner's output is a structured report (JSON + markdown summary), not a live alert; the report is the audit artifact

## Philosophy of the skill

External links rot. Every site that's older than two years has at least a few. The choice is between knowing about them on a schedule or finding out from a user. A periodic scan with a published report turns link health into a maintenance task instead of an emergency. The discipline is to be conservative — distinguish persistent failures (404 across 3 runs) from transient ones (one 503 on a Tuesday) — and to never let the scanner itself become a denial-of-service vector against the targets it's checking.

## Verification

Before merging any change to the link-rot scanner or its config:

- [ ] The scanner extracts every link in `[text](url)` and `[text][ref]` form from `.md` and `.mdx` files; reference links resolve their targets before classification
- [ ] Internal links (relative paths, same-host absolute, anchors, mailto, tel) are explicitly excluded — confirmed by a fixture test with mixed link types
- [ ] Persistent failures are distinguished from transient ones — a link is only flagged after N consecutive failures across separate runs (default N=3)
- [ ] The scanner respects per-host concurrency limits and honors `robots.txt` crawl-delay; a single host getting many requests in tight sequence is a bug
- [ ] Soft-404 detection has a defined pattern set and an explicit "unknown" bucket for cases that don't match any known soft-404
- [ ] The scanner produces both a JSON report (machine-readable) and a markdown summary (human-readable) with link, status code, last-seen-OK timestamp, and recommendation

## Do NOT Use When

| Use instead | When |
|---|---|
| (a frontend a11y / UX skill) | The task is rendering a "this link may be broken" badge in the live UI |
| `debugging` | A specific link broke for a specific user and you need to reproduce |
| `documentation` | The task is writing the link-health policy doc, not the scanner |
| `refactor` | The task is restructuring the scanner without changing the detection contract |

