--- name: ctx-link-check description: "Audit docs for dead links. Use before releases, after restructuring docs, or when running a documentation audit." allowed-tools: Bash(curl:*), Read, Grep, Glob --- Scan markdown files for broken links. Two passes: internal (file targets) and external (HTTP URLs). ## Scope Discovery Determine which directories to scan: 1. If the user specifies a path, use that 2. Otherwise, glob for common doc directories: `docs/`, `doc/`, `documentation/`, `site/` 3. If none exist, fall back to scanning all `.md` files in the project root (excluding `node_modules/`, `.git/`, `vendor/`) Report which directories are being scanned at the start of output. ## When to Use - Before releases or doc deployments - After renaming, moving, or deleting doc pages - After restructuring documentation directories or nav - When `/_ctx-audit` runs (audit check #12) - When a user reports a 404 on the site ## When NOT to Use - When editing a single doc (just eyeball links in that file) - When offline and only external checks would matter ## Execution ### Pass 1: Internal Links Scan every `.md` file in the discovered scope for markdown links pointing to other files: `[text](target.md)`, `[text](../path/file.md)`, `[text](path/file.md#anchor)`. For each link: 1. Resolve the target **relative to the source file's directory** 2. Strip any `#anchor` fragment before checking file existence 3. Skip external URLs (`http://`, `https://`, `mailto:`) 4. Skip bare anchors (`#section-name`): these are intra-page 5. Verify the target file exists on disk Collect all broken internal links as: ``` BROKEN: source-file.md:LINE → target.md (file not found) ``` ### Pass 2: External Links Scan every `.md` file in the discovered scope for `http://` and `https://` URLs in markdown link syntax. For each URL: 1. Send an HTTP HEAD request with a 10-second timeout 2. If HEAD fails or returns 405, retry with GET 3. Record the HTTP status code Report failures as: ``` WARN: source-file.md:LINE → https://example.com (HTTP 404) WARN: source-file.md:LINE → https://example.com (timeout) ``` **Do not treat external failures as errors.** Network partitions, rate limiting, and transient outages are common. Report them but do not fail the check. Exceptions: skip these URLs: - `localhost` / `127.0.0.1` URLs (local dev servers) - `example.com` / `example.org` (placeholder domains) ### Pass 3: Image References Scan for image links: `![alt](path/to/image.png)` and `![alt](images/file.jpg)`. Verify the image file exists on disk. Same resolution rules as internal links. ## Output Format ``` ## Link Check Report ### Internal Links - N broken links found (or "All clear") - [list of broken links with file:line and target] ### External Links - N warnings (or "All reachable") - [list of failures with file:line, URL, and reason] ### Images - N missing images (or "All present") - [list of missing images with file:line and target] ### Summary Internal: N broken / M total External: N unreachable / M total Images: N missing / M total ``` ## Fixing For broken internal links, offer specific fixes: - If the target was renamed, suggest the new path - If the target was deleted, suggest removing the link or pointing to an alternative - If the target is a typo (close match exists), suggest the correction For external links, just report. The user decides whether to update, remove, or ignore. ## Integration with /_ctx-audit When invoked as check #12 from `/_ctx-audit`: - Run the full check (all 3 passes) - Report findings in the same format as other consolidation checks - Internal broken links count as findings to fix - External failures count as warnings (informational) ## Quality Checklist After running the check: - [ ] All `.md` files in the discovered scope were scanned - [ ] Relative path resolution accounts for subdirectories - [ ] Anchors stripped before file existence check - [ ] External check used timeouts (not hanging on slow hosts) - [ ] localhost/example URLs were skipped - [ ] Report distinguishes errors (internal) from warnings (external)